为什么Stream.sorted在Java 8中不是类型安全的? [英] Why is Stream.sorted not type-safe in Java 8?

查看:369
本文介绍了为什么Stream.sorted在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 {}

您现在可以拥有StreamBar元素,但是请尝试对其进行排序,就好像它是一个StreamQux元素一样.

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);

由于BarQux都匹配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 ClassCastExceptions. If the Class isn't used for casting then the argument is completely useless; I'd even consider it harmful.

下一个逻辑步骤是尝试要求C扩展TComparable<? 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆