Tips
《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必不少人都读过,号称Java四大名著之一,不过第二版2009年出版,到如今已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深入的变化。
在这里第一时间翻译成中文版。供你们学习分享之用。java
使用泛型编程时,会看到许多编译器警告:未经检查的强制转换警告,未经检查的方法调用警告,未经检查的参数化可变长度类型警告以及未经检查的转换警告。 你使用泛型得到的经验越多,得到的警告越少,但不要指望新编写的代码可以干净地编译。编程
许多未经检查的警告很容易消除。 例如,假设你不当心写了如下声明:安全
Set<Lark> exaltation = new HashSet();
编译器会提醒你你作错了什么:学习
Venery.java:4: warning: [unchecked] unchecked conversion Set<Lark> exaltation = new HashSet(); ^ required: Set<Lark> found: HashSet
而后能够进行指示修正,让警告消失。 请注意,实际上并不须要指定类型参数,只是为了代表它与Java 7中引入的钻石运算符("<>")一同出现。而后编译器会推断出正确的实际类型参数(在本例中为Lark):ui
Set<Lark> exaltation = new HashSet<>();
但一些警告更难以消除。 本章充满了这种警告的例子。 当你收到须要进一步思考的警告时,坚持不懈! 尽量地消除每个未经检查的警告。 若是你消除全部的警告,你能够放心,你的代码是类型安全的,这是一件很是好的事情。 这意味着在运行时你将不会获得一个ClassCastException异常,而且增长了你的程序将按照你的意图行事的信心。翻译
若是你不能消除警告,但你能够证实引起警告的代码是类型安全的,那么(而且只能这样)用@SuppressWarnings(“unchecked”)
注解来抑制警告。 若是你在没有首先证实代码是类型安全的状况下压制警告,那么你给本身一个错误的安全感。 代码可能会在不发出任何警告的状况下进行编译,可是它仍然能够在运行时抛出ClassCastException异常。 可是,若是你忽略了你认为是安全的未经检查的警告(而不是抑制它们),那么当一个新的警告出现时,你将不会注意到这是一个真正的问题。 新出现的警告就会淹没在全部的错误警告当中。code
SuppressWarnings
注解可用于任何声明,从单个局部变量声明到整个类。 始终在尽量最小的范围内使用SuppressWarnings
注解。 一般这是一个变量声明或一个很是短的方法或构造方法。 切勿在整个类上使用SuppressWarnings
注解。 这样作可能会掩盖重要的警告。blog
若是你发现本身在长度超过一行的方法或构造方法上使用SuppressWarnings
注解,则能够将其移到局部变量声明上。 你可能须要声明一个新的局部变量,但这是值得的。 例如,考虑这个来自ArrayList的toArray方法:ip
public <T> T[] toArray(T[] a) { if (a.length < size) return (T[]) Arrays.copyOf(elements, size, a.getClass()); System.arraycopy(elements, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } 若是编译ArrayList类,则该方法会生成此警告: ArrayList.java:305: warning: [unchecked] unchecked cast return (T[]) Arrays.copyOf(elements, size, a.getClass()); ^ required: T[] found: Object[]
在返回语句中设置SuppressWarnings
注解是非法的,由于它不是一个声明[JLS,9.7]。 你可能会试图把注释放在整个方法上,可是不要这要作。 相反,声明一个局部变量来保存返回值并标注它的声明,以下所示:element
// Adding local variable to reduce scope of @SuppressWarnings public <T> T[] toArray(T[] a) { if (a.length < size) { // This cast is correct because the array we're creating // is of the same type as the one passed in, which is T[]. @SuppressWarnings("unchecked") T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass()); return result; } System.arraycopy(elements, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }
所产生的方法干净地编译,并最小化未经检查的警告被抑制的范围。
每当使用@SuppressWarnings(“unchecked”)
注解时,请添加注释,说明为何是安全的。 这将有助于他人理解代码,更重要的是,这将减小有人修改代码的可能性,从而使计算不安全。 若是你以为很难写这样的注释,请继续思考。 毕竟,你最终可能会发现未经检查的操做是不安全的。
总之,未经检查的警告是重要的。 不要忽视他们。 每一个未经检查的警告表明在运行时出现ClassCastException异常的可能性。 尽你所能消除这些警告。 若是没法消除未经检查的警告,而且能够证实引起该警告的代码是安全类型的,则能够在尽量小的范围内使用 @SuppressWarnings(“unchecked”)
注解来禁止警告。 记录你决定在注释中抑制此警告的理由。