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.
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
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 {}
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);
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.
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);
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).
Some related notes.
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());
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.
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.
* 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.