Why is Stream.sorted not type-safe in Java 8?
up vote
22
down vote
favorite
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
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 java-8 java-stream comparable
|
show 9 more comments
up vote
22
down vote
favorite
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
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 java-8 java-stream comparable
4
You meanComparator
? There's already an overload for that. Not sure why you needC
though.
– shmosel
23 hours ago
4
It's not possible to do that.
– shmosel
23 hours ago
5
Due to the nature of generics. The whole point of generics is that you're implementing generic functionality, which precludes type-specific logic. Your sample code doesn't make any sense. I think you're trying to redefineT
(which isn't possible), but you're actually just defining a type for a useless argument.
– shmosel
23 hours ago
4
butsorted
does not take any arguments as input - where are you going to take this argument from?
– Eugene
23 hours ago
6
This problem predates java 8 btw
– Bohemian♦
23 hours ago
|
show 9 more comments
up vote
22
down vote
favorite
up vote
22
down vote
favorite
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
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 java-8 java-stream comparable
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
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 java-8 java-stream comparable
java java-8 java-stream comparable
edited 1 hour ago
Boann
36.2k1286118
36.2k1286118
asked 23 hours ago
Koray Tugay
8,20026108212
8,20026108212
4
You meanComparator
? There's already an overload for that. Not sure why you needC
though.
– shmosel
23 hours ago
4
It's not possible to do that.
– shmosel
23 hours ago
5
Due to the nature of generics. The whole point of generics is that you're implementing generic functionality, which precludes type-specific logic. Your sample code doesn't make any sense. I think you're trying to redefineT
(which isn't possible), but you're actually just defining a type for a useless argument.
– shmosel
23 hours ago
4
butsorted
does not take any arguments as input - where are you going to take this argument from?
– Eugene
23 hours ago
6
This problem predates java 8 btw
– Bohemian♦
23 hours ago
|
show 9 more comments
4
You meanComparator
? There's already an overload for that. Not sure why you needC
though.
– shmosel
23 hours ago
4
It's not possible to do that.
– shmosel
23 hours ago
5
Due to the nature of generics. The whole point of generics is that you're implementing generic functionality, which precludes type-specific logic. Your sample code doesn't make any sense. I think you're trying to redefineT
(which isn't possible), but you're actually just defining a type for a useless argument.
– shmosel
23 hours ago
4
butsorted
does not take any arguments as input - where are you going to take this argument from?
– Eugene
23 hours ago
6
This problem predates java 8 btw
– Bohemian♦
23 hours ago
4
4
You mean
Comparator
? There's already an overload for that. Not sure why you need C
though.– shmosel
23 hours ago
You mean
Comparator
? There's already an overload for that. Not sure why you need C
though.– shmosel
23 hours ago
4
4
It's not possible to do that.
– shmosel
23 hours ago
It's not possible to do that.
– shmosel
23 hours ago
5
5
Due to the nature of generics. The whole point of generics is that you're implementing generic functionality, which precludes type-specific logic. Your sample code doesn't make any sense. I think you're trying to redefine
T
(which isn't possible), but you're actually just defining a type for a useless argument.– shmosel
23 hours ago
Due to the nature of generics. The whole point of generics is that you're implementing generic functionality, which precludes type-specific logic. Your sample code doesn't make any sense. I think you're trying to redefine
T
(which isn't possible), but you're actually just defining a type for a useless argument.– shmosel
23 hours ago
4
4
but
sorted
does not take any arguments as input - where are you going to take this argument from?– Eugene
23 hours ago
but
sorted
does not take any arguments as input - where are you going to take this argument from?– Eugene
23 hours ago
6
6
This problem predates java 8 btw
– Bohemian♦
23 hours ago
This problem predates java 8 btw
– Bohemian♦
23 hours ago
|
show 9 more comments
3 Answers
3
active
oldest
votes
up vote
13
down vote
accepted
Essentially, you're asking if a method can require the class' type parameter be more strict for only said method. This is not possible in Java. There is no way to tell the compiler, "hey, this one method requires that the type parameter match more specific bounds than defined at the class level". Such a feature may be useful but I'd also expect confusing and/or complicated.
There's also no way to work around this with the way generics is currently implemented. For instance, you were wondering why something like the following wouldn't work:
public interface Stream<T>
<C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
The problem is there's no guarantee that Class<C>
is assignable from Class<T>
. What if you had the following:
public class Foo implements Comparable<Foo> /* implementation */
public class Bar extends Foo
public class Other extends Foo
You could basically tell the Stream
that it's a Stream
of Bar
elements but sort as if it was a Stream
of Other
elements:
Stream<Bar> stream = barCollection.stream().sorted(Other.class);
And, if casting is done via the given Class
, you'd still have ClassCastException
s at runtime. If the Class
wasn't utilized for casting then the argument is useless since it adds no type-safety.
You also can't do something like:
public interface Stream<T>
<C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
Because <C extends T & ...>
is a compile-time error; type parameters cannot be followed by other bounds. Even if this was allowed I'm not sure if it'd be effective.
I'd also like to point out the Stream.sorted(Comparator<? super T>)
isn't type-safe because of Stream
's method signature. It's type-safe because the Comparator
enforces the correct types. In other words, it's the Comparator
that makes sure the elements can be compared, not the Stream
.
add a comment |
up vote
13
down vote
How would you implement that? sorted
is a intermediate operation (can be called anywhere between other intermediate operations), meaning you can start with a stream that is not Comparable, but call sorted
on one that is Comparable
:
Arrays.asList(new Foo(), new Foo())
.stream()
.map(Foo::getName) // name is a String for example
.sorted()
.forEach(f -> );
The thing that you are proposing takes an argument as input, but Stream::sorted
does not, so you can't do that. The overload version accepts a Comparator
- meaning you can sort something by a property, but still return Stream<T>
. I think that this is quite easy to understand if you would try to write your minimal skeleton of a Stream interface/implementation.
2
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
– Koray Tugay
23 hours ago
@KorayTugay well yes, what is your point?
– Eugene
23 hours ago
13
Well, the alternative would be not to have a zero-argsorted()
method, thus requiring you to usesorted(Comparator.naturalOrder())
instead. That would be type safe. It’s a trade off. Compare with this answer discussing the special treatment of sorting operations.
– Holger
19 hours ago
@Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
– Koray Tugay
11 hours ago
@Holger good point, and now that you have said this explicitly I don't really understand why plainsorted
was provided to begin with
– Eugene
11 hours ago
add a comment |
up vote
12
down vote
The documentation for Stream#sorted
explains it perfectly:
Returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.
You're using the overloaded method that accepts no arguments (not the one that accepts a Comparator
), and Foo
does not implement Comparable
.
If you're asking why the method doesn't throw a compiler error if the contents of the Stream
do not implement Comparable
, it would be because T
is not forced to extend Comparable
, and T
cannot be changed without a call to Stream#map
; it seems to only be a convenience method so no explicit Comparator
needs to be provided when the elements already implement Comparable
.
For it to be type-safe, T
would have to extend Comparable
, but that would be ridiculous, as it would prevent a stream from containing any objects that aren't Comparable
.
1
it would be because T is not forced to extend Comparable
I know, but why does sorted accept a T but not something like what I suggest at the end of my question?
– Koray Tugay
23 hours ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
– Jacob G.
23 hours ago
I guess the point you are trying to make is that sincesorted
is part of the Stream class (which has type parameterT
)T
should not implementComparable
as that will force all types using the stream pipeline to implement Comparable.
– user7
23 hours ago
@user7 Exactly :) which is why the documentation states "sorted according to natural order". Objects that don't implementComparable
don't have a natural order.
– Jacob G.
23 hours ago
7
@JacobG. actually, restricting the receiver’s type via method parameter is possible and such a method even exist, i.e.sorted(Comparator.naturalOrder())
can only be invoked on a stream, if its elements are comparable. It was a deliberate decision to add anothersorted()
method without parameters.
– Holger
19 hours ago
|
show 2 more comments
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
13
down vote
accepted
Essentially, you're asking if a method can require the class' type parameter be more strict for only said method. This is not possible in Java. There is no way to tell the compiler, "hey, this one method requires that the type parameter match more specific bounds than defined at the class level". Such a feature may be useful but I'd also expect confusing and/or complicated.
There's also no way to work around this with the way generics is currently implemented. For instance, you were wondering why something like the following wouldn't work:
public interface Stream<T>
<C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
The problem is there's no guarantee that Class<C>
is assignable from Class<T>
. What if you had the following:
public class Foo implements Comparable<Foo> /* implementation */
public class Bar extends Foo
public class Other extends Foo
You could basically tell the Stream
that it's a Stream
of Bar
elements but sort as if it was a Stream
of Other
elements:
Stream<Bar> stream = barCollection.stream().sorted(Other.class);
And, if casting is done via the given Class
, you'd still have ClassCastException
s at runtime. If the Class
wasn't utilized for casting then the argument is useless since it adds no type-safety.
You also can't do something like:
public interface Stream<T>
<C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
Because <C extends T & ...>
is a compile-time error; type parameters cannot be followed by other bounds. Even if this was allowed I'm not sure if it'd be effective.
I'd also like to point out the Stream.sorted(Comparator<? super T>)
isn't type-safe because of Stream
's method signature. It's type-safe because the Comparator
enforces the correct types. In other words, it's the Comparator
that makes sure the elements can be compared, not the Stream
.
add a comment |
up vote
13
down vote
accepted
Essentially, you're asking if a method can require the class' type parameter be more strict for only said method. This is not possible in Java. There is no way to tell the compiler, "hey, this one method requires that the type parameter match more specific bounds than defined at the class level". Such a feature may be useful but I'd also expect confusing and/or complicated.
There's also no way to work around this with the way generics is currently implemented. For instance, you were wondering why something like the following wouldn't work:
public interface Stream<T>
<C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
The problem is there's no guarantee that Class<C>
is assignable from Class<T>
. What if you had the following:
public class Foo implements Comparable<Foo> /* implementation */
public class Bar extends Foo
public class Other extends Foo
You could basically tell the Stream
that it's a Stream
of Bar
elements but sort as if it was a Stream
of Other
elements:
Stream<Bar> stream = barCollection.stream().sorted(Other.class);
And, if casting is done via the given Class
, you'd still have ClassCastException
s at runtime. If the Class
wasn't utilized for casting then the argument is useless since it adds no type-safety.
You also can't do something like:
public interface Stream<T>
<C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
Because <C extends T & ...>
is a compile-time error; type parameters cannot be followed by other bounds. Even if this was allowed I'm not sure if it'd be effective.
I'd also like to point out the Stream.sorted(Comparator<? super T>)
isn't type-safe because of Stream
's method signature. It's type-safe because the Comparator
enforces the correct types. In other words, it's the Comparator
that makes sure the elements can be compared, not the Stream
.
add a comment |
up vote
13
down vote
accepted
up vote
13
down vote
accepted
Essentially, you're asking if a method can require the class' type parameter be more strict for only said method. This is not possible in Java. There is no way to tell the compiler, "hey, this one method requires that the type parameter match more specific bounds than defined at the class level". Such a feature may be useful but I'd also expect confusing and/or complicated.
There's also no way to work around this with the way generics is currently implemented. For instance, you were wondering why something like the following wouldn't work:
public interface Stream<T>
<C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
The problem is there's no guarantee that Class<C>
is assignable from Class<T>
. What if you had the following:
public class Foo implements Comparable<Foo> /* implementation */
public class Bar extends Foo
public class Other extends Foo
You could basically tell the Stream
that it's a Stream
of Bar
elements but sort as if it was a Stream
of Other
elements:
Stream<Bar> stream = barCollection.stream().sorted(Other.class);
And, if casting is done via the given Class
, you'd still have ClassCastException
s at runtime. If the Class
wasn't utilized for casting then the argument is useless since it adds no type-safety.
You also can't do something like:
public interface Stream<T>
<C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
Because <C extends T & ...>
is a compile-time error; type parameters cannot be followed by other bounds. Even if this was allowed I'm not sure if it'd be effective.
I'd also like to point out the Stream.sorted(Comparator<? super T>)
isn't type-safe because of Stream
's method signature. It's type-safe because the Comparator
enforces the correct types. In other words, it's the Comparator
that makes sure the elements can be compared, not the Stream
.
Essentially, you're asking if a method can require the class' type parameter be more strict for only said method. This is not possible in Java. There is no way to tell the compiler, "hey, this one method requires that the type parameter match more specific bounds than defined at the class level". Such a feature may be useful but I'd also expect confusing and/or complicated.
There's also no way to work around this with the way generics is currently implemented. For instance, you were wondering why something like the following wouldn't work:
public interface Stream<T>
<C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
The problem is there's no guarantee that Class<C>
is assignable from Class<T>
. What if you had the following:
public class Foo implements Comparable<Foo> /* implementation */
public class Bar extends Foo
public class Other extends Foo
You could basically tell the Stream
that it's a Stream
of Bar
elements but sort as if it was a Stream
of Other
elements:
Stream<Bar> stream = barCollection.stream().sorted(Other.class);
And, if casting is done via the given Class
, you'd still have ClassCastException
s at runtime. If the Class
wasn't utilized for casting then the argument is useless since it adds no type-safety.
You also can't do something like:
public interface Stream<T>
<C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);
Because <C extends T & ...>
is a compile-time error; type parameters cannot be followed by other bounds. Even if this was allowed I'm not sure if it'd be effective.
I'd also like to point out the Stream.sorted(Comparator<? super T>)
isn't type-safe because of Stream
's method signature. It's type-safe because the Comparator
enforces the correct types. In other words, it's the Comparator
that makes sure the elements can be compared, not the Stream
.
edited 21 hours ago
answered 21 hours ago
Slaw
5,0832729
5,0832729
add a comment |
add a comment |
up vote
13
down vote
How would you implement that? sorted
is a intermediate operation (can be called anywhere between other intermediate operations), meaning you can start with a stream that is not Comparable, but call sorted
on one that is Comparable
:
Arrays.asList(new Foo(), new Foo())
.stream()
.map(Foo::getName) // name is a String for example
.sorted()
.forEach(f -> );
The thing that you are proposing takes an argument as input, but Stream::sorted
does not, so you can't do that. The overload version accepts a Comparator
- meaning you can sort something by a property, but still return Stream<T>
. I think that this is quite easy to understand if you would try to write your minimal skeleton of a Stream interface/implementation.
2
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
– Koray Tugay
23 hours ago
@KorayTugay well yes, what is your point?
– Eugene
23 hours ago
13
Well, the alternative would be not to have a zero-argsorted()
method, thus requiring you to usesorted(Comparator.naturalOrder())
instead. That would be type safe. It’s a trade off. Compare with this answer discussing the special treatment of sorting operations.
– Holger
19 hours ago
@Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
– Koray Tugay
11 hours ago
@Holger good point, and now that you have said this explicitly I don't really understand why plainsorted
was provided to begin with
– Eugene
11 hours ago
add a comment |
up vote
13
down vote
How would you implement that? sorted
is a intermediate operation (can be called anywhere between other intermediate operations), meaning you can start with a stream that is not Comparable, but call sorted
on one that is Comparable
:
Arrays.asList(new Foo(), new Foo())
.stream()
.map(Foo::getName) // name is a String for example
.sorted()
.forEach(f -> );
The thing that you are proposing takes an argument as input, but Stream::sorted
does not, so you can't do that. The overload version accepts a Comparator
- meaning you can sort something by a property, but still return Stream<T>
. I think that this is quite easy to understand if you would try to write your minimal skeleton of a Stream interface/implementation.
2
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
– Koray Tugay
23 hours ago
@KorayTugay well yes, what is your point?
– Eugene
23 hours ago
13
Well, the alternative would be not to have a zero-argsorted()
method, thus requiring you to usesorted(Comparator.naturalOrder())
instead. That would be type safe. It’s a trade off. Compare with this answer discussing the special treatment of sorting operations.
– Holger
19 hours ago
@Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
– Koray Tugay
11 hours ago
@Holger good point, and now that you have said this explicitly I don't really understand why plainsorted
was provided to begin with
– Eugene
11 hours ago
add a comment |
up vote
13
down vote
up vote
13
down vote
How would you implement that? sorted
is a intermediate operation (can be called anywhere between other intermediate operations), meaning you can start with a stream that is not Comparable, but call sorted
on one that is Comparable
:
Arrays.asList(new Foo(), new Foo())
.stream()
.map(Foo::getName) // name is a String for example
.sorted()
.forEach(f -> );
The thing that you are proposing takes an argument as input, but Stream::sorted
does not, so you can't do that. The overload version accepts a Comparator
- meaning you can sort something by a property, but still return Stream<T>
. I think that this is quite easy to understand if you would try to write your minimal skeleton of a Stream interface/implementation.
How would you implement that? sorted
is a intermediate operation (can be called anywhere between other intermediate operations), meaning you can start with a stream that is not Comparable, but call sorted
on one that is Comparable
:
Arrays.asList(new Foo(), new Foo())
.stream()
.map(Foo::getName) // name is a String for example
.sorted()
.forEach(f -> );
The thing that you are proposing takes an argument as input, but Stream::sorted
does not, so you can't do that. The overload version accepts a Comparator
- meaning you can sort something by a property, but still return Stream<T>
. I think that this is quite easy to understand if you would try to write your minimal skeleton of a Stream interface/implementation.
edited 22 hours ago
answered 23 hours ago
Eugene
65.9k992158
65.9k992158
2
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
– Koray Tugay
23 hours ago
@KorayTugay well yes, what is your point?
– Eugene
23 hours ago
13
Well, the alternative would be not to have a zero-argsorted()
method, thus requiring you to usesorted(Comparator.naturalOrder())
instead. That would be type safe. It’s a trade off. Compare with this answer discussing the special treatment of sorting operations.
– Holger
19 hours ago
@Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
– Koray Tugay
11 hours ago
@Holger good point, and now that you have said this explicitly I don't really understand why plainsorted
was provided to begin with
– Eugene
11 hours ago
add a comment |
2
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
– Koray Tugay
23 hours ago
@KorayTugay well yes, what is your point?
– Eugene
23 hours ago
13
Well, the alternative would be not to have a zero-argsorted()
method, thus requiring you to usesorted(Comparator.naturalOrder())
instead. That would be type safe. It’s a trade off. Compare with this answer discussing the special treatment of sorting operations.
– Holger
19 hours ago
@Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
– Koray Tugay
11 hours ago
@Holger good point, and now that you have said this explicitly I don't really understand why plainsorted
was provided to begin with
– Eugene
11 hours ago
2
2
Well
sorted
in this example knows the type again, that is a Stream<String>, isn 't it?– Koray Tugay
23 hours ago
Well
sorted
in this example knows the type again, that is a Stream<String>, isn 't it?– Koray Tugay
23 hours ago
@KorayTugay well yes, what is your point?
– Eugene
23 hours ago
@KorayTugay well yes, what is your point?
– Eugene
23 hours ago
13
13
Well, the alternative would be not to have a zero-arg
sorted()
method, thus requiring you to use sorted(Comparator.naturalOrder())
instead. That would be type safe. It’s a trade off. Compare with this answer discussing the special treatment of sorting operations.– Holger
19 hours ago
Well, the alternative would be not to have a zero-arg
sorted()
method, thus requiring you to use sorted(Comparator.naturalOrder())
instead. That would be type safe. It’s a trade off. Compare with this answer discussing the special treatment of sorting operations.– Holger
19 hours ago
@Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
– Koray Tugay
11 hours ago
@Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
– Koray Tugay
11 hours ago
@Holger good point, and now that you have said this explicitly I don't really understand why plain
sorted
was provided to begin with– Eugene
11 hours ago
@Holger good point, and now that you have said this explicitly I don't really understand why plain
sorted
was provided to begin with– Eugene
11 hours ago
add a comment |
up vote
12
down vote
The documentation for Stream#sorted
explains it perfectly:
Returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.
You're using the overloaded method that accepts no arguments (not the one that accepts a Comparator
), and Foo
does not implement Comparable
.
If you're asking why the method doesn't throw a compiler error if the contents of the Stream
do not implement Comparable
, it would be because T
is not forced to extend Comparable
, and T
cannot be changed without a call to Stream#map
; it seems to only be a convenience method so no explicit Comparator
needs to be provided when the elements already implement Comparable
.
For it to be type-safe, T
would have to extend Comparable
, but that would be ridiculous, as it would prevent a stream from containing any objects that aren't Comparable
.
1
it would be because T is not forced to extend Comparable
I know, but why does sorted accept a T but not something like what I suggest at the end of my question?
– Koray Tugay
23 hours ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
– Jacob G.
23 hours ago
I guess the point you are trying to make is that sincesorted
is part of the Stream class (which has type parameterT
)T
should not implementComparable
as that will force all types using the stream pipeline to implement Comparable.
– user7
23 hours ago
@user7 Exactly :) which is why the documentation states "sorted according to natural order". Objects that don't implementComparable
don't have a natural order.
– Jacob G.
23 hours ago
7
@JacobG. actually, restricting the receiver’s type via method parameter is possible and such a method even exist, i.e.sorted(Comparator.naturalOrder())
can only be invoked on a stream, if its elements are comparable. It was a deliberate decision to add anothersorted()
method without parameters.
– Holger
19 hours ago
|
show 2 more comments
up vote
12
down vote
The documentation for Stream#sorted
explains it perfectly:
Returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.
You're using the overloaded method that accepts no arguments (not the one that accepts a Comparator
), and Foo
does not implement Comparable
.
If you're asking why the method doesn't throw a compiler error if the contents of the Stream
do not implement Comparable
, it would be because T
is not forced to extend Comparable
, and T
cannot be changed without a call to Stream#map
; it seems to only be a convenience method so no explicit Comparator
needs to be provided when the elements already implement Comparable
.
For it to be type-safe, T
would have to extend Comparable
, but that would be ridiculous, as it would prevent a stream from containing any objects that aren't Comparable
.
1
it would be because T is not forced to extend Comparable
I know, but why does sorted accept a T but not something like what I suggest at the end of my question?
– Koray Tugay
23 hours ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
– Jacob G.
23 hours ago
I guess the point you are trying to make is that sincesorted
is part of the Stream class (which has type parameterT
)T
should not implementComparable
as that will force all types using the stream pipeline to implement Comparable.
– user7
23 hours ago
@user7 Exactly :) which is why the documentation states "sorted according to natural order". Objects that don't implementComparable
don't have a natural order.
– Jacob G.
23 hours ago
7
@JacobG. actually, restricting the receiver’s type via method parameter is possible and such a method even exist, i.e.sorted(Comparator.naturalOrder())
can only be invoked on a stream, if its elements are comparable. It was a deliberate decision to add anothersorted()
method without parameters.
– Holger
19 hours ago
|
show 2 more comments
up vote
12
down vote
up vote
12
down vote
The documentation for Stream#sorted
explains it perfectly:
Returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.
You're using the overloaded method that accepts no arguments (not the one that accepts a Comparator
), and Foo
does not implement Comparable
.
If you're asking why the method doesn't throw a compiler error if the contents of the Stream
do not implement Comparable
, it would be because T
is not forced to extend Comparable
, and T
cannot be changed without a call to Stream#map
; it seems to only be a convenience method so no explicit Comparator
needs to be provided when the elements already implement Comparable
.
For it to be type-safe, T
would have to extend Comparable
, but that would be ridiculous, as it would prevent a stream from containing any objects that aren't Comparable
.
The documentation for Stream#sorted
explains it perfectly:
Returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.
You're using the overloaded method that accepts no arguments (not the one that accepts a Comparator
), and Foo
does not implement Comparable
.
If you're asking why the method doesn't throw a compiler error if the contents of the Stream
do not implement Comparable
, it would be because T
is not forced to extend Comparable
, and T
cannot be changed without a call to Stream#map
; it seems to only be a convenience method so no explicit Comparator
needs to be provided when the elements already implement Comparable
.
For it to be type-safe, T
would have to extend Comparable
, but that would be ridiculous, as it would prevent a stream from containing any objects that aren't Comparable
.
edited 23 hours ago
answered 23 hours ago
Jacob G.
14k41860
14k41860
1
it would be because T is not forced to extend Comparable
I know, but why does sorted accept a T but not something like what I suggest at the end of my question?
– Koray Tugay
23 hours ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
– Jacob G.
23 hours ago
I guess the point you are trying to make is that sincesorted
is part of the Stream class (which has type parameterT
)T
should not implementComparable
as that will force all types using the stream pipeline to implement Comparable.
– user7
23 hours ago
@user7 Exactly :) which is why the documentation states "sorted according to natural order". Objects that don't implementComparable
don't have a natural order.
– Jacob G.
23 hours ago
7
@JacobG. actually, restricting the receiver’s type via method parameter is possible and such a method even exist, i.e.sorted(Comparator.naturalOrder())
can only be invoked on a stream, if its elements are comparable. It was a deliberate decision to add anothersorted()
method without parameters.
– Holger
19 hours ago
|
show 2 more comments
1
it would be because T is not forced to extend Comparable
I know, but why does sorted accept a T but not something like what I suggest at the end of my question?
– Koray Tugay
23 hours ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
– Jacob G.
23 hours ago
I guess the point you are trying to make is that sincesorted
is part of the Stream class (which has type parameterT
)T
should not implementComparable
as that will force all types using the stream pipeline to implement Comparable.
– user7
23 hours ago
@user7 Exactly :) which is why the documentation states "sorted according to natural order". Objects that don't implementComparable
don't have a natural order.
– Jacob G.
23 hours ago
7
@JacobG. actually, restricting the receiver’s type via method parameter is possible and such a method even exist, i.e.sorted(Comparator.naturalOrder())
can only be invoked on a stream, if its elements are comparable. It was a deliberate decision to add anothersorted()
method without parameters.
– Holger
19 hours ago
1
1
it would be because T is not forced to extend Comparable
I know, but why does sorted accept a T but not something like what I suggest at the end of my question?– Koray Tugay
23 hours ago
it would be because T is not forced to extend Comparable
I know, but why does sorted accept a T but not something like what I suggest at the end of my question?– Koray Tugay
23 hours ago
There's already an overloaded
Stream#sorted
method that accepts a Comparator
. It accepting a Comparable
wouldn't make much sense.– Jacob G.
23 hours ago
There's already an overloaded
Stream#sorted
method that accepts a Comparator
. It accepting a Comparable
wouldn't make much sense.– Jacob G.
23 hours ago
I guess the point you are trying to make is that since
sorted
is part of the Stream class (which has type parameter T
) T
should not implement Comparable
as that will force all types using the stream pipeline to implement Comparable.– user7
23 hours ago
I guess the point you are trying to make is that since
sorted
is part of the Stream class (which has type parameter T
) T
should not implement Comparable
as that will force all types using the stream pipeline to implement Comparable.– user7
23 hours ago
@user7 Exactly :) which is why the documentation states "sorted according to natural order". Objects that don't implement
Comparable
don't have a natural order.– Jacob G.
23 hours ago
@user7 Exactly :) which is why the documentation states "sorted according to natural order". Objects that don't implement
Comparable
don't have a natural order.– Jacob G.
23 hours ago
7
7
@JacobG. actually, restricting the receiver’s type via method parameter is possible and such a method even exist, i.e.
sorted(Comparator.naturalOrder())
can only be invoked on a stream, if its elements are comparable. It was a deliberate decision to add another sorted()
method without parameters.– Holger
19 hours ago
@JacobG. actually, restricting the receiver’s type via method parameter is possible and such a method even exist, i.e.
sorted(Comparator.naturalOrder())
can only be invoked on a stream, if its elements are comparable. It was a deliberate decision to add another sorted()
method without parameters.– Holger
19 hours ago
|
show 2 more comments
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53219523%2fwhy-is-stream-sorted-not-type-safe-in-java-8%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
4
You mean
Comparator
? There's already an overload for that. Not sure why you needC
though.– shmosel
23 hours ago
4
It's not possible to do that.
– shmosel
23 hours ago
5
Due to the nature of generics. The whole point of generics is that you're implementing generic functionality, which precludes type-specific logic. Your sample code doesn't make any sense. I think you're trying to redefine
T
(which isn't possible), but you're actually just defining a type for a useless argument.– shmosel
23 hours ago
4
but
sorted
does not take any arguments as input - where are you going to take this argument from?– Eugene
23 hours ago
6
This problem predates java 8 btw
– Bohemian♦
23 hours ago