索引值不能为负数,对象不能为null,如果作为方法的参数,应该在发生错误之后尽快检查出错误,所以对于方法的参数,如果没有尽早的做校验,随着方法的运行,可能发生令人费解的异常。
public BigInteger mod(BigIngeger m){
//尽早校验
if(m.signum <=0){
throw new ArithmeticException("Moduleus <=0 :"+m)
}
}
对于有些参数方法本身没有用到,而是被存储起来以供后面使用,这种参数的有效性检查尤为重要。
例外:有些情况下,有效性检查工作非常昂贵,不切实际,而有效性检查已经隐含在计算过程中完成,例如:Collections.sort()中要求列表总所有参数都可以相互比较,否则抛出ClassCastException
假设客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性的设计程序。
首先方法名复合命名习惯,首要目的是易于理解,并且与包中其他名称风格一致(这是很重要的,即使你的方法名称算是有意义的,但是如果风格迥异的话,阅读起来也是很容易造成疑惑的,个人见解-_-!)
每个方法都应该尽其所能,方法太多造成类难以学习。接口中的方法太多造成实现者的工作变得复杂。
目标是4个,或者更少,相同类型的长参数序列格外难以记忆,且容易记错顺序。
缩短过长参数的可行措施:
- 被方法分解成多个方法
- 创建辅助类用来保存参数,这种辅助类一般为静态内部类
- 对于对象构造的方法采用Builder模式
这样代码更易阅读与编写,更易于拓展,(防止粗线true和false之后的第三者可能)
不合理的重载会带来与期望不一样的结果。
安全而保守的策略是,永远不要导出两个具有相同参数数目的重载方法,如果使用的是可变参数,保守的策略是根本不要重载它
例如对于ObjectOutputStream对于每个基本类型,它的write方法都有一种变形:
是
writeLong(long long);
writeInt(int int);
而不是
write(long long);
write(int int);
当调用覆盖方法时,对象的编译时类型不会影响到哪个方法被执行,最为具体的那个覆盖版本总是会得到执行,这与重载的情况性比,重载的方法的选择是在编译时进行的,完全基于参数的编译时类型。
只要当两个重载方法在同样参数上被调用,他们执行相同的功能,重载就不会带来危害,下面是一个坏例子:
String.valueOf(char[])
String.valueOf(Object)
对于Arrays.asList方法:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
分别传入int[]或String[]会参数截然不同的结果。
int[]会被当成单独的对象
String[]才会被当成数组
可变参数的每次调用都会导致进行一次数组的分配和初始化,如果不希望承受这一成本,但又需要可变参数的灵活性,有一种模式可供选择:
public void foo(){}
public void foo(){int i}
public void foo(){int i,int j}
public void foo(){int i,int j,int k}
public void foo(){int i,int j,int k,int ... rest}
假设有95%的调用会调用3个或更少的参数,就该声明方法的5个重载,每个方法带有三个0-3个参数,当参数超过时,才使用可变参数。
在使用可变参数时,它确实是很方便的方式,但是他们不应该被过度滥用,如果使用不当,就会产生混乱的结果。
public List<String> getPeopleName(){
if(peopleNames.size==0){
return null;
}
......
}
这种写法在开发中经常可见,但是把size=0的情况返回Null,这样要求客户端中必须有额外的代码来处理null的返回值。这是不合理的。
不要在这种情况上担心数组或集合的分配,这是不明智的。
总是:返回类型为数组或集合的类型,没有理由返回null.