Android基础进阶之EffectJava翻译系列(第六章:方法)

这一章介绍方法设计的几个方面:如何对待参数和返回值,如何设计方法签名,如何注释方法

Item38: 检查参数的合法性

大部分使用的方法参数都有一定的限制,如不为null,size>0等
通用的原则就是预防大于整改,提前发现错误可以更快的规避问题,而不是在程序运行中发生

对于公共方法,使用Javadoc@块标记,来记录在违反参数值限制时抛出的异常(Item62)。

/**
* Returns a BigInteger whose value is (this mod m). This method
* differs from the remainder method in that it always returns a
* non-negative BigInteger.
*
* @param m the modulus, which must be positive
* @return this mod m
* @throws ArithmeticException if m is less than or equal to 0
*/
public BigInteger mod(BigInteger m) {
    if (m.signum() <= 0)
        throw new ArithmeticException("Modulus <= 0: " + m);
    ... // Do the computation
}

对于私有的方法则使用断言

// Private helper function for a recursive sort
private static void sort(long a[], int offset, int length) {
    assert a != null;
    assert offset >= 0 && offset <= a.length;
    assert length >= 0 && length <= a.length - offset;
    ... // Do the computation
}

assert在实际项目中使用的很少,更多的还是使用的if判断

每次写一个方法或者构造函数的时候,在方法的开头考虑参数的合法性是必不可少的

Item39: 必要的时候使用拷贝对象

Java是一门安全的语言,即使在Java语言中,也要假设用户正想方设法的破坏你的程序.除了少部分人想破坏系统的安全性,大部分问题都是编程人员可以控制的
虽然没有对象的帮助,另一个类不太可能改变对象的内部状态,但偶尔也有疏忽的地方

//一个不可变的周期类
// Broken "immutable" time period class
public final class Period {
    private final Date start;
    private final Date end;
    /**
    * @param start the beginning of the period
    * @param end the end of the period; must not precede start
    * @throws IllegalArgumentException if start is after end
    * @throws NullPointerException if start or end is null
    */
    public Period(Date start, Date end) {
        if (start.compareTo(end) > 0)
            throw new IllegalArgumentException(
                start + " after " + end);
        this.start = start;
        this.end = end;
    }
    public Date start() {
        return start;
    }

    public Date end() {
        return end;
    }
    ... // Remainder omitted
}

其中Date对象是可变的

// bad
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
end.setYear(78); // 修改了p的内部状态

为了保护对象的状态,我们需要在构造函数中对可变参数执行拷贝防御

// Repaired constructor - makes defensive copies of parameters
public Period(Date start, Date end) {
    this.start = new Date(start.getTime());
    this.end = new Date(end.getTime());
    if (this.start.compareTo(this.end) > 0)
        throw new IllegalArgumentException(start +" after "+ end);
}

// Repaired accessors - make defensive copies of internal fields
public Date start() {
    return new Date(start.getTime());
}
public Date end() {
    return new Date(end.getTime());
}

这里没有使用clone方法,因为Date有其它不可信任的子类

经验上讲,在内部尽量不要使用可变的类,如Date,可用long型替代Date.getTime()

总结:如果一个类调用了或返回可变的对象,则需要用拷贝对象防御,如果很信任调用者不会修改类的内部状态,则需要有一份警告文档提示调用者不能修改类的状态

Item 40: Design method signatures carefully

上一章:枚举和注解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章