【发布时间】:2015-05-28 21:58:17
【问题描述】:
我们目前正在将应用程序从 Java 7 迁移到 Java 8。在修复了一些编译问题后,我偶然发现了一个类似于以下问题的问题:ClassCast Error: Java 7 vs Java 8。
总而言之,这是一个显示问题的示例代码:
public class Test {
public static void main(String[] args) {
System.out.println(String.valueOf(getVal("xxx"))); // 7: prints the result, 8: Exception
}
@SuppressWarnings("unchecked")
public static <T> T getVal(String param) {
// do some computation based on param...
return (T) result; // actual return type only depends on param so the caller knows what to expect
}
}
我们的想法是,我们会强调调用者知道预期的类型,这样可以避免他显式转换(我并不是说这是个好主意……)。在很多情况下,调用者只需要一个Object,所以根本没有隐式转换。
如上述问题所述,String.valueOf 示例在 Java 7 中运行良好,因为没有类型推断,因此假定为 Object。现在在 Java 8 中,编译器会选择最具体的类型(此处为 char[]),这会在运行时生成 ClastCastException。
问题是我们有大约 350 次调用此 getVal 方法。 有没有办法检测 Java 7 和 Java 8 之间不同的重载方法调用?检测 Java 8 编译器何时会选择与 Java 7 编译器不同的方法。
【问题讨论】:
-
我们有一个类似的方法,也被数百个地方调用过。我替换了它,引入了额外的
Class<T> clazz参数。通过这种方式,您可以进行显式错误处理:返回 null 或抛出一些更具体的异常。我只是手动花费了大约半个小时。我建议你也这样做。我不知道如何使其自动化,因此这不能作为您问题的答案。 -
有一个简单的答案:不要抑制“未经检查的”警告。他们已经告诉你你的代码是错误的。如果你现在想修复你的代码已经太晚了,只需搜索出现的
@SuppressWarnings("unchecked")... -
@Holger 你能告诉我的同事,当他在 2011 年实施这个时? ;-) 我一开始就知道这是一个坏主意(尽管不像现在在 Java 8 中那么糟糕)。另外,方法调用本身没有
@SuppressWarnings,它只在getVal的声明中。因此,在此处删除此注释不会显示任何有问题的用法。 -
好吧,
getVal的声明方式是的问题。因此,寻找注释将引导您到正确的位置。然后,修复签名当然会在调用者处引发编译器错误,因此很容易找到它们。除非您使用一次性重构签名和调用者的 IDE,否则这是一个可行的替代方案。当然,一旦注释将您引导到有问题的方法,如果您使用体面的 IDE,即使不更改它也可以找到它的调用者。所以有必要的工具...... -
我认为这确实是要走的路。这并不能真正回答这个问题,因为与少数有问题的调用相比,我必须更改更多的代码,但至少它会解决我们的问题。此外,似乎将返回类型更改为
Object将自动修复有问题的调用,因此具有讽刺意味的是那里不会有任何更改(我可能永远不会知道它们在哪里:-)。
标签: java generics java-8 classcastexception overloading