我遇到了一个编译器问题,我可以将其简化为这个示例。这段代码
class A<T> {
Optional<Integer> op;
public Optional<Integer> getOp() {
return op;
}
}
List<A> l = null;
l.stream().map(x -> x.getOp().orElse(0)).max(Comparator.naturalOrder());
无法编译
error: incompatible types: inference variable T has incompatible bounds
[javac] l.stream().map(x -> x.getOp().orElse(0)).max(Comparator.naturalOrder());
[javac] ^
如果我删除通用参数
<T>
(类中根本没有使用),则此代码片段将编译。这是怎么回事?我正在使用 Java 8。
这里的问题是在
A
中使用原始类型 List<A>
,而不是通用类型(例如 List<A<?>>
)。 将 l
的类型从 List<A>
更改为 List<A<?>>
足以解决编译问题。
List<A<?>> l = null;
由于
A
是原始类型,getOp
返回 Optional
,而不是 Optional<Integer>
。 由于特定类型未知,因此 x.getOp().orElse(0)
返回 Object
而不是 Integer
。 Comparator.naturalOrder()
只能比较Comparable
值,Object
则不能。 因此编译失败在.max(Comparator.naturalOrder())
。
Java 语言规范 解释说,原始类型只是为了支持前通用(Java 4 及更早版本)代码而存在,并且特别不鼓励在新代码中使用原始类型:
为了方便与非泛型遗留代码的接口,可以使用参数化类型(§4.5)的擦除(§4.6)或数组类型(§10.1)的擦除作为类型其元素类型是参数化类型。这样的类型称为 raw 类型。
[…]
仅允许使用原始类型作为对遗留代码兼容性的让步。强烈建议不要在 Java 编程语言中引入泛型之后编写的代码中使用原始类型。 Java 编程语言的未来版本可能会禁止使用原始类型。