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
    yesterday







  • 4




    It's not possible to do that.
    – shmosel
    yesterday






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







  • 4




    but sorted does not take any arguments as input - where are you going to take this argument from?
    – Eugene
    yesterday







  • 6




    This problem predates java 8 btw
    – Bohemian
    yesterday














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
    yesterday







  • 4




    It's not possible to do that.
    – shmosel
    yesterday






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







  • 4




    but sorted does not take any arguments as input - where are you going to take this argument from?
    – Eugene
    yesterday







  • 6




    This problem predates java 8 btw
    – Bohemian
    yesterday












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 2 hours ago









Boann

36.2k1286118




36.2k1286118










asked yesterday









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
    yesterday







  • 4




    It's not possible to do that.
    – shmosel
    yesterday






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







  • 4




    but sorted does not take any arguments as input - where are you going to take this argument from?
    – Eugene
    yesterday







  • 6




    This problem predates java 8 btw
    – Bohemian
    yesterday












  • 4




    You mean Comparator? There's already an overload for that. Not sure why you need C though.
    – shmosel
    yesterday







  • 4




    It's not possible to do that.
    – shmosel
    yesterday






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







  • 4




    but sorted does not take any arguments as input - where are you going to take this argument from?
    – Eugene
    yesterday







  • 6




    This problem predates java 8 btw
    – Bohemian
    yesterday







4




4




You mean Comparator? There's already an overload for that. Not sure why you need C though.
– shmosel
yesterday





You mean Comparator? There's already an overload for that. Not sure why you need C though.
– shmosel
yesterday





4




4




It's not possible to do that.
– shmosel
yesterday




It's not possible to do that.
– shmosel
yesterday




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
yesterday





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
yesterday





4




4




but sorted does not take any arguments as input - where are you going to take this argument from?
– Eugene
yesterday





but sorted does not take any arguments as input - where are you going to take this argument from?
– Eugene
yesterday





6




6




This problem predates java 8 btw
– Bohemian
yesterday




This problem predates java 8 btw
– Bohemian
yesterday












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
      yesterday










    • @KorayTugay well yes, what is your point?
      – Eugene
      yesterday






    • 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
      21 hours ago










    • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
      – Koray Tugay
      12 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
      12 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
      yesterday










    • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
      – Jacob G.
      yesterday










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










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






    • 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
      21 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 22 hours ago

























        answered 22 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
              yesterday










            • @KorayTugay well yes, what is your point?
              – Eugene
              yesterday






            • 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
              21 hours ago










            • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
              – Koray Tugay
              12 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
              12 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
              yesterday










            • @KorayTugay well yes, what is your point?
              – Eugene
              yesterday






            • 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
              21 hours ago










            • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
              – Koray Tugay
              12 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
              12 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 yesterday

























            answered yesterday









            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
              yesterday










            • @KorayTugay well yes, what is your point?
              – Eugene
              yesterday






            • 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
              21 hours ago










            • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
              – Koray Tugay
              12 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
              12 hours ago












            • 2




              Well sorted in this example knows the type again, that is a Stream<String>, isn 't it?
              – Koray Tugay
              yesterday










            • @KorayTugay well yes, what is your point?
              – Eugene
              yesterday






            • 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
              21 hours ago










            • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
              – Koray Tugay
              12 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
              12 hours ago







            2




            2




            Well sorted in this example knows the type again, that is a Stream<String>, isn 't it?
            – Koray Tugay
            yesterday




            Well sorted in this example knows the type again, that is a Stream<String>, isn 't it?
            – Koray Tugay
            yesterday












            @KorayTugay well yes, what is your point?
            – Eugene
            yesterday




            @KorayTugay well yes, what is your point?
            – Eugene
            yesterday




            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
            21 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
            21 hours ago












            @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
            – Koray Tugay
            12 hours ago




            @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
            – Koray Tugay
            12 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
            12 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
            12 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
              yesterday










            • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
              – Jacob G.
              yesterday










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










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






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










            • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
              – Jacob G.
              yesterday










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










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






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

























            answered yesterday









            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
              yesterday










            • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
              – Jacob G.
              yesterday










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










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






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










            • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
              – Jacob G.
              yesterday










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










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






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




            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
            yesterday












            There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
            – Jacob G.
            yesterday




            There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
            – Jacob G.
            yesterday












            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
            yesterday




            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
            yesterday












            @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.
            yesterday




            @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.
            yesterday




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














































































            這個網誌中的熱門文章

            How to combine Bézier curves to a surface?

            Mutual Information Always Non-negative

            Why am i infinitely getting the same tweet with the Twitter Search API?