Why is the Stream.sorted not type safe in Java 8?
Clash Royale CLAN TAG#URR8PPP
up vote
8
down vote
favorite
This is from the Stream interface from Oracles implementation of JDK 8:
public interface Stream<T> extends BaseStream<T, Stream<T>>
Stream<T> sorted();
and it is very easy to blow this in run-time and no warning will be generated in 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 in runtime:
Exception in thread "main" java.lang.ClassCastException: Foo cannot be cast to java.lang.Comparable
What can be the reason that sorted
method was not defined where 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 7 more comments
up vote
8
down vote
favorite
This is from the Stream interface from Oracles implementation of JDK 8:
public interface Stream<T> extends BaseStream<T, Stream<T>>
Stream<T> sorted();
and it is very easy to blow this in run-time and no warning will be generated in 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 in runtime:
Exception in thread "main" java.lang.ClassCastException: Foo cannot be cast to java.lang.Comparable
What can be the reason that sorted
method was not defined where 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
1
You meanComparator
? There's already an overload for that. Not sure why you needC
though.
â shmosel
1 hour ago
2
It's not possible to do that.
â shmosel
1 hour ago
1
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
1 hour ago
1
In yoursorted
example you're requiring an argument of type? extends Comparable
. Where is this argument going to come from?
â Slaw
1 hour ago
1
butsorted
does not take any arguments as input - where are you going to take this argument from?
â Eugene
1 hour ago
 |Â
show 7 more comments
up vote
8
down vote
favorite
up vote
8
down vote
favorite
This is from the Stream interface from Oracles implementation of JDK 8:
public interface Stream<T> extends BaseStream<T, Stream<T>>
Stream<T> sorted();
and it is very easy to blow this in run-time and no warning will be generated in 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 in runtime:
Exception in thread "main" java.lang.ClassCastException: Foo cannot be cast to java.lang.Comparable
What can be the reason that sorted
method was not defined where 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 Oracles implementation of JDK 8:
public interface Stream<T> extends BaseStream<T, Stream<T>>
Stream<T> sorted();
and it is very easy to blow this in run-time and no warning will be generated in 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 in runtime:
Exception in thread "main" java.lang.ClassCastException: Foo cannot be cast to java.lang.Comparable
What can be the reason that sorted
method was not defined where 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
asked 1 hour ago
Koray Tugay
8,11926108210
8,11926108210
1
You meanComparator
? There's already an overload for that. Not sure why you needC
though.
â shmosel
1 hour ago
2
It's not possible to do that.
â shmosel
1 hour ago
1
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
1 hour ago
1
In yoursorted
example you're requiring an argument of type? extends Comparable
. Where is this argument going to come from?
â Slaw
1 hour ago
1
butsorted
does not take any arguments as input - where are you going to take this argument from?
â Eugene
1 hour ago
 |Â
show 7 more comments
1
You meanComparator
? There's already an overload for that. Not sure why you needC
though.
â shmosel
1 hour ago
2
It's not possible to do that.
â shmosel
1 hour ago
1
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
1 hour ago
1
In yoursorted
example you're requiring an argument of type? extends Comparable
. Where is this argument going to come from?
â Slaw
1 hour ago
1
butsorted
does not take any arguments as input - where are you going to take this argument from?
â Eugene
1 hour ago
1
1
You mean
Comparator
? There's already an overload for that. Not sure why you need C
though.â shmosel
1 hour ago
You mean
Comparator
? There's already an overload for that. Not sure why you need C
though.â shmosel
1 hour ago
2
2
It's not possible to do that.
â shmosel
1 hour ago
It's not possible to do that.
â shmosel
1 hour ago
1
1
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
1 hour 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
1 hour ago
1
1
In your
sorted
example you're requiring an argument of type ? extends Comparable
. Where is this argument going to come from?â Slaw
1 hour ago
In your
sorted
example you're requiring an argument of type ? extends Comparable
. Where is this argument going to come from?â Slaw
1 hour ago
1
1
but
sorted
does not take any arguments as input - where are you going to take this argument from?â Eugene
1 hour ago
but
sorted
does not take any arguments as input - where are you going to take this argument from?â Eugene
1 hour ago
 |Â
show 7 more comments
2 Answers
2
active
oldest
votes
up vote
3
down vote
accepted
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.
1
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
â Koray Tugay
1 hour ago
@KorayTugay well yes, what is your point?
â Eugene
1 hour ago
add a comment |Â
up vote
5
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
.
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
1 hour ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
â Jacob G.
1 hour 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
1 hour 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.
1 hour ago
@user7 Yes, obviously that would be a disaster.. But can we not just define a method parameters type to be of generic type of the interface AND restrict it to also something else? (That is what I tried in the last code snipped in my question, at least I tried to..)
â Koray Tugay
1 hour ago
 |Â
show 1 more comment
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
accepted
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.
1
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
â Koray Tugay
1 hour ago
@KorayTugay well yes, what is your point?
â Eugene
1 hour ago
add a comment |Â
up vote
3
down vote
accepted
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.
1
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
â Koray Tugay
1 hour ago
@KorayTugay well yes, what is your point?
â Eugene
1 hour ago
add a comment |Â
up vote
3
down vote
accepted
up vote
3
down vote
accepted
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 1 hour ago
answered 1 hour ago
Eugene
65.8k992156
65.8k992156
1
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
â Koray Tugay
1 hour ago
@KorayTugay well yes, what is your point?
â Eugene
1 hour ago
add a comment |Â
1
Wellsorted
in this example knows the type again, that is a Stream<String>, isn 't it?
â Koray Tugay
1 hour ago
@KorayTugay well yes, what is your point?
â Eugene
1 hour ago
1
1
Well
sorted
in this example knows the type again, that is a Stream<String>, isn 't it?â Koray Tugay
1 hour ago
Well
sorted
in this example knows the type again, that is a Stream<String>, isn 't it?â Koray Tugay
1 hour ago
@KorayTugay well yes, what is your point?
â Eugene
1 hour ago
@KorayTugay well yes, what is your point?
â Eugene
1 hour ago
add a comment |Â
up vote
5
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
.
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
1 hour ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
â Jacob G.
1 hour 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
1 hour 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.
1 hour ago
@user7 Yes, obviously that would be a disaster.. But can we not just define a method parameters type to be of generic type of the interface AND restrict it to also something else? (That is what I tried in the last code snipped in my question, at least I tried to..)
â Koray Tugay
1 hour ago
 |Â
show 1 more comment
up vote
5
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
.
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
1 hour ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
â Jacob G.
1 hour 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
1 hour 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.
1 hour ago
@user7 Yes, obviously that would be a disaster.. But can we not just define a method parameters type to be of generic type of the interface AND restrict it to also something else? (That is what I tried in the last code snipped in my question, at least I tried to..)
â Koray Tugay
1 hour ago
 |Â
show 1 more comment
up vote
5
down vote
up vote
5
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 1 hour ago
answered 1 hour ago
Jacob G.
13.8k41859
13.8k41859
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
1 hour ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
â Jacob G.
1 hour 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
1 hour 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.
1 hour ago
@user7 Yes, obviously that would be a disaster.. But can we not just define a method parameters type to be of generic type of the interface AND restrict it to also something else? (That is what I tried in the last code snipped in my question, at least I tried to..)
â Koray Tugay
1 hour ago
 |Â
show 1 more comment
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
1 hour ago
There's already an overloadedStream#sorted
method that accepts aComparator
. It accepting aComparable
wouldn't make much sense.
â Jacob G.
1 hour 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
1 hour 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.
1 hour ago
@user7 Yes, obviously that would be a disaster.. But can we not just define a method parameters type to be of generic type of the interface AND restrict it to also something else? (That is what I tried in the last code snipped in my question, at least I tried to..)
â Koray Tugay
1 hour 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
1 hour 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
1 hour ago
There's already an overloaded
Stream#sorted
method that accepts a Comparator
. It accepting a Comparable
wouldn't make much sense.â Jacob G.
1 hour ago
There's already an overloaded
Stream#sorted
method that accepts a Comparator
. It accepting a Comparable
wouldn't make much sense.â Jacob G.
1 hour 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
1 hour 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
1 hour 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.
1 hour 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.
1 hour ago
@user7 Yes, obviously that would be a disaster.. But can we not just define a method parameters type to be of generic type of the interface AND restrict it to also something else? (That is what I tried in the last code snipped in my question, at least I tried to..)
â Koray Tugay
1 hour ago
@user7 Yes, obviously that would be a disaster.. But can we not just define a method parameters type to be of generic type of the interface AND restrict it to also something else? (That is what I tried in the last code snipped in my question, at least I tried to..)
â Koray Tugay
1 hour ago
 |Â
show 1 more comment
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-the-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
1
You mean
Comparator
? There's already an overload for that. Not sure why you needC
though.â shmosel
1 hour ago
2
It's not possible to do that.
â shmosel
1 hour ago
1
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
1 hour ago
1
In your
sorted
example you're requiring an argument of type? extends Comparable
. Where is this argument going to come from?â Slaw
1 hour ago
1
but
sorted
does not take any arguments as input - where are you going to take this argument from?â Eugene
1 hour ago