Why is Stream.sorted not type-safe in Java 8?









up vote
22
down vote

favorite
3












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?










share|improve this question



















  • 4




    You mean Comparator? There's already an overload for that. Not sure why you need C 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














up vote
22
down vote

favorite
3












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?










share|improve this question



















  • 4




    You mean Comparator? There's already an overload for that. Not sure why you need C 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












up vote
22
down vote

favorite
3









up vote
22
down vote

favorite
3






3





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?










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 1 hour ago









Boann

36.2k1286118




36.2k1286118










asked 23 hours ago









Koray Tugay

8,20026108212




8,20026108212







  • 4




    You mean Comparator? There's already an overload for that. Not sure why you need C 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












  • 4




    You mean Comparator? There's already an overload for that. Not sure why you need C 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







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












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 ClassCastExceptions 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.






share|improve this answer





























    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.






    share|improve this answer


















    • 2




      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






    • 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










    • @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

















    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.






    share|improve this answer


















    • 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 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










    • @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




      @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










    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    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






























    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 ClassCastExceptions 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.






    share|improve this answer


























      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 ClassCastExceptions 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.






      share|improve this answer
























        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 ClassCastExceptions 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.






        share|improve this answer














        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 ClassCastExceptions 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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 21 hours ago

























        answered 21 hours ago









        Slaw

        5,0832729




        5,0832729






















            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.






            share|improve this answer


















            • 2




              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






            • 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










            • @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














            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.






            share|improve this answer


















            • 2




              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






            • 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










            • @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












            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.






            share|improve this answer














            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.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 22 hours ago

























            answered 23 hours ago









            Eugene

            65.9k992158




            65.9k992158







            • 2




              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






            • 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










            • @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












            • 2




              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






            • 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










            • @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







            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










            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.






            share|improve this answer


















            • 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 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










            • @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




              @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














            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.






            share|improve this answer


















            • 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 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










            • @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




              @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












            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.






            share|improve this answer














            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.







            share|improve this answer














            share|improve this answer



            share|improve this answer








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










            • @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




              @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












            • 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 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










            • @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




              @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







            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

















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            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














































































            Popular posts from this blog

            Use pre created SQLite database for Android project in kotlin

            Darth Vader #20

            Ondo