EffectiveJava——方法

第38条:检查参数的有效性

索引值不能为负数,对象不能为null,如果作为方法的参数,应该在发生错误之后尽快检查出错误,所以对于方法的参数,如果没有尽早的做校验,随着方法的运行,可能发生令人费解的异常。

public BigInteger mod(BigIngeger m){
//尽早校验
   if(m.signum <=0){
     throw new ArithmeticException("Moduleus <=0 :"+m)                
    }
}

对于有些参数方法本身没有用到,而是被存储起来以供后面使用,这种参数的有效性检查尤为重要。

例外:有些情况下,有效性检查工作非常昂贵,不切实际,而有效性检查已经隐含在计算过程中完成,例如:Collections.sort()中要求列表总所有参数都可以相互比较,否则抛出ClassCastException

第39条:必要时进行保护性拷贝

假设客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性的设计程序。

  • 对于不可变类提供方法返回内部可变的对象时,必须进行保护性拷贝,否则不可变类就可能被改变了。
  • * 对于构造器的每个可变参数进行保护性拷贝,是必须的*
  • 保护性拷贝是在检查参数的有效性之前进行的,并且有效性检查是针对拷贝之后的对象,而不是针对原始对象。(避免危险阶段期间从另一个线程改变参数,Time-of-check/Time-Of-Use)
  • 对于参数类型可以被不可信任方子类化的参数,请不要使用clone进行保护性拷贝。因为无法确认子类化的类的clone方法。
  • 长度非0的数组总是可变的
  • 只要有可能,都应该使用不可变类的对象作为对象的背部组件。
  • 有经验的程序员通常使用Date的getTime返回long基本类型作为内部时间表示法,因为Date是可变的。
  • 保护性拷贝可能会带来相关的性能损失,这种说法并不总是正确的。

第40条:谨慎的设计方法的签名

谨慎的选择方法的名称

首先方法名复合命名习惯,首要目的是易于理解,并且与包中其他名称风格一致(这是很重要的,即使你的方法名称算是有意义的,但是如果风格迥异的话,阅读起来也是很容易造成疑惑的,个人见解-_-!)

不要过于追求提供便利的方法

每个方法都应该尽其所能,方法太多造成类难以学习。接口中的方法太多造成实现者的工作变得复杂。

避免过长的参数列表

目标是4个,或者更少,相同类型的长参数序列格外难以记忆,且容易记错顺序。
缩短过长参数的可行措施:
- 被方法分解成多个方法
- 创建辅助类用来保存参数,这种辅助类一般为静态内部类
- 对于对象构造的方法采用Builder模式

对于参数类型要优先使用接口而不是类。

对于Boolean参数,要优先使用两个元素的枚举类型

这样代码更易阅读与编写,更易于拓展,(防止粗线true和false之后的第三者可能)

第41条:慎用重载

不合理的重载会带来与期望不一样的结果。

  • 调用哪个重载方法是在编译时期做出决定的
  • 对于重载方法的选择是静态的,而对于被覆盖的方法的选择是动态的
  • 覆盖机制是规范,重载机制是例外

安全而保守的策略是,永远不要导出两个具有相同参数数目的重载方法,如果使用的是可变参数,保守的策略是根本不要重载它

例如对于ObjectOutputStream对于每个基本类型,它的write方法都有一种变形:

是
writeLong(long long);
writeInt(int int);
而不是
write(long long);
write(int int);

当调用覆盖方法时,对象的编译时类型不会影响到哪个方法被执行,最为具体的那个覆盖版本总是会得到执行,这与重载的情况性比,重载的方法的选择是在编译时进行的,完全基于参数的编译时类型。

只要当两个重载方法在同样参数上被调用,他们执行相同的功能,重载就不会带来危害,下面是一个坏例子:

String.valueOf(char[])
String.valueOf(Object)

第42条:慎用可变参数

对于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个参数,当参数超过时,才使用可变参数。

在使用可变参数时,它确实是很方便的方式,但是他们不应该被过度滥用,如果使用不当,就会产生混乱的结果。

第43条:返回0长度的数组或者集合,而不是null

public List<String> getPeopleName(){
   if(peopleNames.size==0){
      return null;
   }
   ......
}

这种写法在开发中经常可见,但是把size=0的情况返回Null,这样要求客户端中必须有额外的代码来处理null的返回值。这是不合理的。

不要在这种情况上担心数组或集合的分配,这是不明智的。

总是:返回类型为数组或集合的类型,没有理由返回null.

第44条:为所有导出API元素编写文档注释

  • 文档注释应当简洁的描述出它和客户端之间的约定。
  • 同一个类或者接口中的两个成员或者构造器, 不应该具有相同的概要描述

你可能感兴趣的:(EffectiveJava——方法)