《Effective Java》读书笔记六(方法)

No38 检查参数的有效性

对于公有的方法,要用Javadoc的@throws标签(tag)在文档中说明违反参数值时会抛出的异常。这样的异常通常为IllegalArgumentException、IndexOutOfBoundsException或NullPointerException。

/**
* ...
* @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 }

对于非公有的方法通常应该使用断言(assertion)来检查它们的参数:

// 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
}

断言如果失败,将会抛出AssertionError。

No39 必须时进行保护性拷贝

有经验的程序员通常使用Date.getTime()返回的long基本类型作为内部的时间表示法,而不是使用Date对象引用。主要是因为Date是可变的,它可能被外界调用无意中更改掉而失去它的真实意义。

No40 谨慎设计方法签名

  • 避免过长的参数列表,相同类型的长参数序列格外有害。
  • 对于参数类型,要优先使用接口而不是类。

    比如:

// 不合适的方法定义
private void sort(HashMap<String> hashMap); 

// 合适的方法定义
// 这使你可以传入一个Hashtable、HashMap、TreeMap等等。更改起来很容易。
private void sort(Map<String> map); 

No41 慎用重载

下面这个程序的意图是很好的,它试图根据一个集合(collection)是Set、List,还是其他的集合类型来对它进行分类:

// Broken! - What does this program print?
import java.util.*;
import java.math.*;

public class CollectionClassifier {
    public static String classify(Set<?> s) {
        return "Set";
    }

    public static String classify(List<?> lst) {
        return "List";
    }

    public static String classify(Collection<?> c) {
        return "Unknown Collection";
    }

    public static void main(String[] args) {
        Collection<?>[] collections = {
            new HashSet<String>(),
            new ArrayList<BigInteger>(),
            new HashMap<String, String>().values()
        };

        for (Collection<?> c : collections)
            System.out.println(classify(c));
    }
}

你可能期望这个程序会打印出“Set”,紧接着是“List”,以及“Unknown Collection”,但实际上不是这样,它是打印“Unknown Collection”三次。

这个程序的行为有悖于常理,因为对于重载方法(overloaded method)的选择是静态的;而对于被覆盖的方法(overridded method)的选择则是静态的。

另外还是注意,在集合的操作中,remove(i)与remove((Integer)i)的含义是不一样的。聪明的你一定知道区别在哪儿了。

No43 返回零长度的数组或者集合,而不是null

像下面的方法:

private final List<Cheese> cheeseInStock = ...;

/**
*@return an array containing all of the cheeses in the shop.
* or null if no cheese are available for purchase.
*/
public Cheese[]  getCheeses() {
         if(cheeseInStock.size() == 0)
                return null;
         ...
}

把没有奶酪(cheese)可买的情况当作是一种特例,这是不全常理的。这样做会要求客户端中必须有额外的代码来处理null返回值。例如:

Cheese[] cheeses = shop.getCheeses();
if(cheeses != null && Arrays.asList(cheeses).contains(Cheese.STILTON))
     System.out.println(“Jolly good, just the thing.”);

而不是下面这段代码:

if(Arrays.asList(shop.getCheeses()).contains(Cheese.STILTON))
     System.out.println(“Jolly good, just the thing.”);

 

posted @ 2013-08-10 14:08  那些年的事儿  阅读(296)  评论(0编辑  收藏  举报