为什么Stream.sorted在Java 8中不是类型安全的? [英] Why is Stream.sorted not type-safe in Java 8?
问题描述
这是来自Oracle JDK 8实现的Stream接口:
This is from the Stream interface from Oracle's implementation of JDK 8:
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> sorted();
}
,很容易在运行时将其炸毁,并且在编译时不会生成警告.这是一个示例:
and it is very easy to blow this up at run time and no warning will be generated at compile time. Here is an example:
class Foo {
public static void main(String[] args) {
Arrays.asList(new Foo(), new Foo()).stream().sorted().forEach(f -> {});
}
}
它将编译得很好,但是会在运行时引发异常:
which will compile just fine but will throw an exception at run time:
Exception in thread "main" java.lang.ClassCastException: Foo cannot be cast to java.lang.Comparable
未定义sorted
方法的原因可能是编译器实际上可以捕获此类问题的原因?也许我错了,但不是那么简单:
What could be the reason that the sorted
method was not defined where the compiler could actually catch such problems? Maybe I am wrong but isn't it this simple:
interface Stream<T> {
<C extends Comparable<T>> void sorted(C c);
}
?
显然,实现这一目标的人(就编程和工程学而言,比我快几年)必须有一个我看不见的很好的理由,但是那是什么原因呢?
Obviously the guys implementing this (who are light years ahead of me as far as programming and engineering is considered) must have a very good reason that I am unable to see, but what is that reason?
推荐答案
本质上,您在问是否有一种方法可以告诉编译器,"嘿,这个方法要求类型参数匹配比在课程级别定义".在Java中这是不可能的.这样的功能可能很有用,但我也会感到困惑和/或复杂.
Essentially, you're asking if there's a way to tell the compiler, "hey, this one method requires the type parameter match more specific bounds than defined at the class level". This is not possible in Java. Such a feature may be useful but I'd also expect confusing and/or complicated.
也没有办法使泛型的实现方式对Stream.sorted()
类型安全.如果不想避免使用Comparator
,则不会.例如,您提出的建议是:
There's also no way to make Stream.sorted()
type-safe with how generics is currently implemented; not if you want to avoid requiring a Comparator
. For instance, you were proposing something like:
public interface Stream<T> {
<C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
} // other Stream methods omitted for brevity
不幸的是,不能保证可以从Class<T>
分配Class<C>
.请考虑以下层次结构:
Unfortunately, there's no guarantee that Class<C>
is assignable from Class<T>
. Consider the following hierarchy:
public class Foo implements Comparable<Foo> { /* implementation */ }
public class Bar extends Foo {}
public class Qux extends Foo {}
您现在可以拥有Stream
个Bar
元素,但是请尝试对其进行排序,就好像它是一个Stream
个Qux
元素一样.
You can now have a Stream
of Bar
elements but try to sort it as if it was a Stream
of Qux
elements.
Stream<Bar> stream = barCollection.stream().sorted(Qux.class);
由于Bar
和Qux
都匹配Comparable<? super Foo>
,所以没有编译时错误,因此没有添加类型安全性.同样,需要Class
参数的含义是它将用于强制转换.如上所示,在运行时这仍然会导致ClassCastException
.如果不使用Class
进行强制转换,则该参数将完全无用.我什至认为这很有害.
Since both Bar
and Qux
match Comparable<? super Foo>
there is no compile-time error and thus no type-safety is added. Also, the implication of requiring a Class
argument is that it'll be used for casting. At runtime this can, as shown above, still result in ClassCastException
s. If the Class
isn't used for casting then the argument is completely useless; I'd even consider it harmful.
下一个逻辑步骤是尝试要求C
扩展T
和Comparable<? super T>
.例如:
The next logical step is to try and require C
extend T
as well as Comparable<? super T>
. For example:
<C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
在Java中这也是不可能的,并且会导致编译错误:类型参数不能跟随其他界限".即使这是可能的,我也不认为它可以解决所有问题(如果有的话).
This is also not possible in Java and results in a compilation error: "type parameter cannot be followed by other bounds". Even if this were possible, I don't think it'd solve everything (if anything at all).
一些相关注释.
关于Stream.sorted(Comparator)
:不是Stream
使此方法具有类型安全性,而是Comparator
. Comparator
确保可以比较元素.为了说明这一点,按元素的自然顺序对Stream
进行排序的类型安全方式为:
Regarding Stream.sorted(Comparator)
: It isn't the Stream
that makes this method type-safe, it's the Comparator
. The Comparator
ensures the elements can be compared. To illustrate, the type-safe way to sort a Stream
by the elements' natural order is:
Stream<String> stream = stringCollection.stream().sorted(Comparator.naturalOrder());
这是类型安全的,因为naturalOrder()
要求其类型参数扩展为Comparable
.如果Stream
的通用类型未扩展Comparable
,则边界将不匹配,从而导致编译错误.但同样,Comparator
要求元素为Comparable
* ,而Stream
根本不在乎.
This is type-safe because naturalOrder()
requires its type parameter extend Comparable
. If the generic type of the Stream
did not extend Comparable
then the bounds wouldn't match, resulting in a compilation error. But again, it's the Comparator
that requires the elements be Comparable
* while the Stream
simply doesn't care.
问题就变成了,为什么开发人员为什么首先要为Stream
包含无参数的sorted
方法?它似乎是出于历史原因,并在Hola的对另一个问题的答案中进行了解释.
So the question becomes, why did the developers include a no-argument sorted
method for Stream
in the first place? It appears to be for historical reasons and is explained in an answer to another question by Holger.
*在这种情况下,Comparator
要求元素为Comparable
.通常,Comparator
显然能够处理其定义为的任何类型.
* The Comparator
requires the elements be Comparable
in this case. In general, a Comparator
is obviously capable of handling any type it's defined to.
这篇关于为什么Stream.sorted在Java 8中不是类型安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!