我从Java 8u5更新到8u45,一些以前工作的代码不再编译。问题是,发生这种情况的时间有一半,这是故意的改变,所以我无法弄清楚它是否是一个错误。
(我也测试过u25,每个版本都和u45一样。)
但实质上,它与方法的多个返回点有关。 e.g:
import java.sql.Connection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class CompilerIssue
{
public Set<String> test(int value)
{
return perform(connection -> {
if (value % 2 == 0)
{
return Collections.<String>emptySet();
}
else
{
return new HashSet<>(10);
}
});
}
<V> V perform(BusinessLogic<V> logic)
{
// would usually get a connection
return null;
}
interface BusinessLogic<V>
{
V execute(Connection connection) throws Exception;
}
}
javac给出:
Error:(12, 23) java: incompatible types: inferred type does not conform to upper bound(s)
inferred: java.util.Set<? extends java.lang.Object>
upper bound(s): java.util.Set<java.lang.String>,java.lang.Object
像这种情况一样,IDEA看不出任何问题。
我已经知道了修复程序 - 将HashSet<>
替换为HashSet<String>
。但是我们通过我们的代码普遍使用了这种结构,所以在我花时间改变它之前,我想知道:这是一个bug,还是旧行为的bug? < / p>
(如果这是一个错误,那么我必须向Oracle报告一个错误。如果它是一个功能,那么我必须向IDEA报告一个错误,认为它没关系。)
答案 0 :(得分:5)
据我所知,它是一个bug并且来自Oracle,它没有正确地推断出目标类型的类型(句子返回期望返回的类型),而是以某种方式比较两个返回句子的上限:(return Collections.<String>emptySet();
和return new HashSet<>(10);
)。
在第二个return语句中,只有new HashSet<>(10)
的上限是Object
,但是类型可以从确实为<String>
的返回类型推断出来。尝试作为测试注释掉第一个return语句并返回null而编译:
public class CompilerIssue
{
public Set<String> test(int value)
{
return perform(connection -> {
if (value % 2 == 0)
{
return null; // COMMENTED OUT FOR TESTING PURPOSES Collections.<String>emptySet();
}
else
{
return new HashSet<>(10);
}
});
}
<V> V perform(BusinessLogic<V> logic)
{
// would usually get a connection
return null;
}
interface BusinessLogic<V>
{
V execute(Connection connection) throws Exception;
}
}
这会编译,它会正确推断HashSet<>(10)
的正确值类型应为String
。