Ответ 1
По сути, вы спрашиваете, есть ли способ сообщить компилятору: "эй, этот метод требует, чтобы параметр типа соответствовал более конкретным границам, чем определено на уровне класса". Это невозможно в Java. Такая функция может быть полезной, но я также ожидал бы запутанной и/или сложной.
Также нет способа сделать Stream.sorted()
типобезопасным с тем, как в настоящее время реализованы дженерики; нет, если вы хотите избежать использования Comparator
. Например, вы предлагали что-то вроде:
public interface Stream<T> {
<C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
} // other Stream methods omitted for brevity
К сожалению, нет гарантии, что Class<C>
можно назначить из Class<T>
. Рассмотрим следующую иерархию:
public class Foo implements Comparable<Foo> { /* implementation */ }
public class Bar extends Foo {}
public class Qux extends Foo {}
Теперь вы можете иметь элементы Stream
of Bar
но попробуйте отсортировать их, как если бы это были элементы Stream
of Qux
.
Stream<Bar> stream = barCollection.stream().sorted(Qux.class);
Поскольку и Bar
и Qux
соответствуют Qux
Comparable<? super Foo>
Comparable<? super Foo>
нет ошибки времени компиляции и, следовательно, безопасность типов не добавляется. Кроме того, следствием требования аргумента Class
является то, что он будет использоваться для приведения. Во время выполнения это может, как показано выше, по-прежнему приводить к ClassCastException
s. Если Class
не используется для приведения, то аргумент совершенно бесполезен; Я бы даже посчитал это вредным.
Следующий логический шаг - попытаться потребовать C
T
а также Comparable<? super T>
Comparable<? super T>
. Например:
<C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
Это также невозможно в Java и приводит к ошибке компиляции: "за параметром типа не могут следовать другие границы". Даже если бы это было возможно, я не думаю, что это решило бы все (если вообще что-нибудь).
Некоторые связанные заметки.
Относительно Stream.sorted(Comparator)
: не Stream
делает этот метод безопасным с точки Stream.sorted(Comparator)
типов, это Comparator
. Comparator
обеспечивает сравнение элементов. Для иллюстрации, типобезопасный способ сортировки Stream
по естественному порядку элементов:
Stream<String> stream = stringCollection.stream().sorted(Comparator.naturalOrder());
Это безопасно для типов, потому что naturalOrder()
требует, чтобы его параметр типа расширялся Comparable
. Если универсальный тип Stream
не расширяет Comparable
то границы не будут совпадать, что приведет к ошибке компиляции. Но опять же, это Comparator
который требует, чтобы элементы были Comparable
*, в то время как Stream
просто не важно.
Таким образом, возникает вопрос: почему разработчики изначально включили метод sorted
без аргументов для Stream
? Похоже, это связано с историческими причинами и объясняется в ответе Хольгера на другой вопрос.
* Comparator
требует, чтобы элементы были Comparable
в этом случае.В общем, Comparator
, очевидно, способен обрабатывать любой тип, который он определил.