当开发人员与非通用API交互时,他们通常会遇到“未经检查”的警告。请考虑以下示例:
import java.util.AbstractList;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class IterableNodeList<T extends Node> extends AbstractList<T>
{
private NodeList list;
public IterableNodeList(NodeList list)
{
this.list = list;
}
public T get(int index)
{
return (T)this.list.item(index);
}
public int size()
{
return this.list.getLength();
}
}
当然,人们可以投入努力以这样的方式编写它,即没有警告:在类上使用类型参数T
和构造函数参数Class<T>
,匹配成员变量和cast()
致电。
或者,可以考虑简单地编辑IDE配置和构建脚本(例如Maven POM)以完全禁用此编译器警告。现在,如果我们这样做,代码可以保持原样,但我确信做必须有缺点。但是,我想不出任何合理,现实的例子
@SuppressWarnings
此处,无论如何都没有其他选项”,以及你能想到这样的例子或者说出为什么在全球范围内禁用这些“未经检查”的警告是个坏主意的另一个原因吗?或者这实际上是个好主意?
之前的例子实际上没有引发警告。现在有些答案不再有意义了。很抱歉给您带来不便。
答案 0 :(得分:5)
根据Item 24
的{{1}},广泛而频繁地使用Effective Java 2nd Edition
通常是个坏主意,特别是如果你将这个注释应用于整个班级,因为这样的警告显示你可能有危险的部分您的代码,可能会导致@SupressWarnings
。
但在某些情况下,它可能很有用,例如在ClassCastException
的{{1}}方法实现中:
ArrayList
答案 1 :(得分:2)
你的第二个例子不会在我的日食中产生编译器警告,也不能想出它为什么会这样做的原因。因此,这是我的首选解决方案。
存在未经检查的警告的原因是忽略它们会导致堆污染:
检查普通演员表,如果该值与所需类型不兼容,则会导致ClassCastException
。未经检查的强制转换不保证,即使值不是正确类型,它们也可以成功。这可能导致变量保存的值不是其声明类型的子类型,这是Java规范calls“堆污染”的条件。为了确保运行时类型系统的完整性,只要使用泛型类型的变量,Java编译器就会插入普通的强制转换。在存在堆污染的情况下,这些铸件会失效。
例如,程序:
static void appendTo(List list) {
list.add(1); // unchecked warning
}
static void printLengths(List<String> strings) {
for (String s : strings) { // throws ClassCastException
System.out.println(s.length());
}
}
public static void main(String[] args) throws Exception {
List<String> strings = new ArrayList<>();
strings.add("hello");
appendTo(strings);
printLengths(strings);
}
在源代码中不包含强制转换的行抛出ClassCastException
。这可能会使大多数程序员感到非常困惑。
这就是为什么我建议尽可能使用经过检查的强制转换,使用非泛型强制转换,或者(在通用代码中)使用反射强制转换:
class Habitat<T> {
private final Class<T> clazz;
private List<T> inhabitants;
void add(Object o) {
inhabitants.add(clazz.cast(o));
}
}
答案 2 :(得分:2)
来自 Effective Java 2nd Edition :
SuppressWarnings
注释可用于任何粒度,来自 单个局部变量声明到整个类。 始终在尽可能小的范围内使用SuppressWarnings
注释。通常这将是一个 变量声明或非常短的方法或构造函数。切勿在整个班级上使用SuppressWarnings
。这样做可能会掩盖严重警告。如果您发现自己在方法或方法上使用
SuppressWarnings
注释 构造函数超过一行,您可以将它移动到本地 变量声明。您可能必须声明一个新的局部变量,但它是值得的 它在return语句中放置
SuppressWarnings
注释是违法的, 因为它不是声明[JLS,9.7]。您可能想要添加注释 关于整个方法,但不要。相反,声明一个局部变量来保存 返回值并注释其声明