以下代码使用javac和Eclipse 4.6.1/4.6进行编译,但在Eclipse 4.6.2:中产生错误
package ecbug;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Foo
{
class A
{
public int getStart() { return 0; }
}
void someMethod(List<A> toRemove)
{
Collections.sort(toRemove, Comparator.comparing(t -> -t.getStart()));
}
}
Eclipse 4.6.2在-t.getStart()
下抱怨存在类型不匹配:无法从int转换为Comparable<?超级可比<?超级U>gt。
我认为Comparator.comparing(...)
的自变量应该是Comparable<T>
和T = A
,函数方法compareTo返回int
。Eclipse似乎认为lambda函数应该返回Comparable<?超级可比<?超级U>gt。
我强烈怀疑是Eclipse错误,但在某些情况下,Eclipse确实正确地实现了语言规范,而javac没有,所以似乎值得一问:这是Eclipse错误还是javacbug?有语言律师能指出语言规范的相关部分吗?
可能相关的问题,在我看来不是重复的:
Java 8流flatMap和group-by-code编译器错误-类似的错误消息,但不清楚是否是完全相同的问题;Answer声称这是一个Eclipse错误,但没有提供错误链接,也没有JLS报价;指的是旧的Eclipse版本。
为什么没有';这个java 8示例使用类型推理在Eclipse中编译吗?-类似于以前的
flatMap返回List<对象>而不是List<字符串>-同样,这可能是一个不同的问题;注释声明了Eclipse问题,但并没有通过引用JLS来证明,也没有提供到Eclipse错误报告的链接。
您的解释不符合要求。Comparator.comparing(...)
(单参数版本)的参数不应该是Comparable<T>
,而是Function<? super T,? extends U>
,而T := A
,但U
是U extends Comparable<? super U>
。
所以当你说
Eclipse似乎认为lambda函数应该返回
Comparable<? super Comparable<? super U>>
您对Eclipse的期望是正确的,Eclipse对此也抱有正确的期望。
但是您的函数返回一个应该进行比较的int
值,当您将该值框入Integer
时,您就得到了一个满足预期U extends Comparable<? super U>
约束的类型,因为Integer
实现了Comparable<Integer>
。换句话说,U
应该被推断为Integer
,但显然,由于int
到Integer
需要装箱,这个特定的Eclipse版本无法做到这一点。
附带说明一下,当您想要比较int
属性时,您可能无论如何都要使用Comparator.comparingInt(...)
。使用此工厂,返回的比较器完全避免了int
到Integer
的装箱。
此外,不应通过求反来反转整数排序。问题是-Integer.MIN_VALUE == Integer.MIN_VALUE
,因为试图否定最小可能的int
值会导致溢出,再次评估最小的int
值,而不是最大的值。使用否定来反转订单可能在很多情况下都有效,在其中一些情况下,它可能是合理的,因为可以排除这种特殊值,然而,它会产生一种坏习惯,在这种情况下可能会适得其反,当然,这种情况很少发生,通常只发生在客户身上…
正确的习语应该是
Collections.sort(toRemove, Comparator.comparingInt(A::getStart).reversed());
它通过交换两个元素来进行比较,这在所有场景中都是有效的,并且没有性能缺陷。