【发布时间】:2015-09-10 16:27:47
【问题描述】:
@Test
public void test() {
MyProperties props = new MyProperties();
props.setProperty("value", new Date());
StringUtils.isNullOrEmpty(props.getProperty("value"));
}
public class MyProperties {
private Map<String, Object> properties = new HashMap<String, Object>();
public void setProperty(String name, Object value) {
properties.put(name, value);
}
@SuppressWarnings("unchecked")
public <T> T getProperty(String name) {
return (T) properties.get(name);
}
}
public class StringUtils {
public static boolean isNullOrEmpty(Object string) {
return isNullOrEmpty(valueOf(string));
}
public static String valueOf(Object string) {
if (string == null) {
return "";
}
return string.toString();
}
public static boolean isNullOrEmpty(String string) {
if (string == null || string.length() == 0) {
return false;
}
int strLength = string.length();
for (int i = 0; i < strLength; i++) {
char charAt = string.charAt(i);
if (charAt > ' ') {
return true;
}
}
return false;
}
}
多年来,这个单元测试一直通过。然后升级到Java 8后,在某些环境下,当通过javac编译代码时,会选择StringUtils.isNullOrEmpty(String)重载。这会导致单元测试失败并显示以下错误消息:
java.lang.ClassCastException: java.util.Date cannot be cast to java.lang.String
at com.foo.bar.StringUtils_UT.test(StringUtils_UT.java:35)
单元测试通过 ant(ant 1.9.6、jdk_8_u60、Windows 7 64bit)在我的机器上编译和运行时通过,但在另一个使用相同版本的 ant 和 java(ant 1.9.6 jdk_8_u60、Ubuntu 12.04. 4 32 位)。
Java 的 type inference 在编译时从所有适用的重载中选择最具体的重载,已在 Java 8 中更改。我认为我的问题与此有关。
我知道编译器将 MyProperties.getProperty(...) 方法的返回类型视为 T,而不是 Date。由于编译器不知道 getProperty(...) 方法的返回类型,为什么它选择 StringUtils.isNullorEmpty(String) 而不是 StringUtils.isNullorEmpty(Object) - 这应该总是有效的?
这是 Java 中的错误还是仅仅是 Java 8 类型推断更改的结果?还有,为什么不同的环境使用相同版本的java编译这段代码会不同?
【问题讨论】:
-
在您的情况下,所有 Java-8 JRE 都应仅选择
StringUtils.isNullOrEmpty(String)重载。检查 this SO 讨论在这种情况下将选择哪个重载... -
老实说
getProperty对我来说似乎是个糟糕的笑话。尽管它在 Java 8 中看起来像是一个问题,但您现在最好注意一下那个臭代码。由于除了Object之外,您没有为value 使用任何其他类型,因此T只能是Object。你能解释一下T会发生什么魔法吗?如果不是,则将其删除并返回properties.get(name)作为Object。顺便说一句,忽略警告很少是个好主意:)。 -
是的,您的代码一直被破坏,但它发生可以工作。现在是回报的时候了。
标签: java