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.”);