Effective Java中文第五章第24节(个人渣翻)

来源:互联网 发布:云创客软件骗局揭秘 编辑:程序博客网 时间:2024/06/05 17:37

第24节:消除未检测警告

当你使用泛型编程的时候,你会看到许多编译器报出的警告:未检测转换警告,未检测方法调用警告,未检测泛型数组创建警告以及未检测对话警告。随着你使用泛型的经验越来越丰富,这样的警告也会越来越少,但请不要对你新写的使用泛型的代码能够完美通过编译抱有期待。
许多未检测的警告都很容易消除。举个例子,假设你不小心写了如下声明:

Set<Lark> exaltation = new HashSet();

编译器会非常绅士地提醒您错在哪里:

   Venery.java:4: warning: [unchecked] unchecked conversion   found   : HashSet, required: Set<Lark>       Set<Lark> exaltation = new HashSet();                            ^

你可以根据以上提示进行修正,将警告消除:

Set<Lark> exaltation = new HashSet<Lark>();

某些警告的消除可能困难的多。这样的例子在本章随处可见。当你遇到的警告需要几经思考,请不要犹豫!尽可能地消除每一个未检测警告。一旦你消除了所有的警告,你就可以放心,因为你的代码是类型安全的,这是一件好事。它意味着程序在运行时不会产生ClassCastException,你的程序行为也和预期一致。
如果你无法消除警告,但可以确认报出警告的代码是类型安全的,那么当且仅当这种情况下,你可以使用@SuppressWarnings(“unchecked”)来抑制这种警告。如果你在没有确认代码是类型安全的情况下抑制了警告,那就等于欺骗了自己。这段代码在编译时不会产生任何警告,但在运行时仍有可能抛出ClassCastException异常。然而,万一你忽略了你知道是类型安全的代码报出的警告(并且没有抑制),那么当真正有问题的新警告产生时你也不会注意到。新警告会被淹没在你没有抑制的假警告中。
SuppressWarnings注解可以用在任意粒度下,小到局部变量,大到整个类。尽量把SuppressWarnings注解用在粒度更细的地方。通常用在变量声明、短方法或者构造器上,禁止用于整个类。因为这么做容易忽略掉关键警告。
如果你发现你的SuppressWarnings注解跟随的方法或构造器长度超过了1行,那你最好将它放到局部变量上。你可能需要声明一个新的局部变量,但物有所值。例如,来看以下toArray方法,摘自ArrayList:

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   found   : Object[], required: T[]       return (T[]) Arrays.copyOf(elements, size, a.getClass());                                 ^

在return语句上增加SuppressWarnings注解是非法的,因为它并不属于声明语句。你可能倾向于将这个注解放到整个方法头上,但请不要这么做。取而代之的,就是声明一个局部变量,并赋予返回值,再加上这个注解,如下:

// 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”)注解来抑制警告。最后,在注释中说明你抑制了警告的理由。

阅读全文
0 0
原创粉丝点击