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











up vote
34
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
    Nov 9 at 3:41








  • 4




    It's not possible to do that.
    – shmosel
    Nov 9 at 3:53






  • 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
    Nov 9 at 4:01








  • 4




    but sorted does not take any arguments as input - where are you going to take this argument from?
    – Eugene
    Nov 9 at 4:07








  • 6




    This problem predates java 8 btw
    – Bohemian
    Nov 9 at 4:12















up vote
34
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
    Nov 9 at 3:41








  • 4




    It's not possible to do that.
    – shmosel
    Nov 9 at 3:53






  • 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
    Nov 9 at 4:01








  • 4




    but sorted does not take any arguments as input - where are you going to take this argument from?
    – Eugene
    Nov 9 at 4:07








  • 6




    This problem predates java 8 btw
    – Bohemian
    Nov 9 at 4:12













up vote
34
down vote

favorite
3









up vote
34
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 Nov 10 at 1:32









Boann

36.5k1286119




36.5k1286119










asked Nov 9 at 3:40









Koray Tugay

8,45726109216




8,45726109216








  • 4




    You mean Comparator? There's already an overload for that. Not sure why you need C though.
    – shmosel
    Nov 9 at 3:41








  • 4




    It's not possible to do that.
    – shmosel
    Nov 9 at 3:53






  • 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
    Nov 9 at 4:01








  • 4




    but sorted does not take any arguments as input - where are you going to take this argument from?
    – Eugene
    Nov 9 at 4:07








  • 6




    This problem predates java 8 btw
    – Bohemian
    Nov 9 at 4:12














  • 4




    You mean Comparator? There's already an overload for that. Not sure why you need C though.
    – shmosel
    Nov 9 at 3:41








  • 4




    It's not possible to do that.
    – shmosel
    Nov 9 at 3:53






  • 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
    Nov 9 at 4:01








  • 4




    but sorted does not take any arguments as input - where are you going to take this argument from?
    – Eugene
    Nov 9 at 4:07








  • 6




    This problem predates java 8 btw
    – Bohemian
    Nov 9 at 4:12








4




4




You mean Comparator? There's already an overload for that. Not sure why you need C though.
– shmosel
Nov 9 at 3:41






You mean Comparator? There's already an overload for that. Not sure why you need C though.
– shmosel
Nov 9 at 3:41






4




4




It's not possible to do that.
– shmosel
Nov 9 at 3:53




It's not possible to do that.
– shmosel
Nov 9 at 3:53




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
Nov 9 at 4:01






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
Nov 9 at 4:01






4




4




but sorted does not take any arguments as input - where are you going to take this argument from?
– Eugene
Nov 9 at 4:07






but sorted does not take any arguments as input - where are you going to take this argument from?
– Eugene
Nov 9 at 4:07






6




6




This problem predates java 8 btw
– Bohemian
Nov 9 at 4:12




This problem predates java 8 btw
– Bohemian
Nov 9 at 4:12












3 Answers
3






active

oldest

votes

















up vote
24
down vote



accepted










Essentially, you're asking if there's a way to tell the compiler, "hey, this one method requires the type parameter match more specific bounds than defined at the class level". This is not possible in Java. Such a feature may be useful but I'd also expect confusing and/or complicated.



There's also no way to make Stream.sorted() type-safe with how generics is currently implemented; not if you want to avoid requiring a Comparator. For instance, you were proposing something like:



public interface Stream<T> {

<C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);

} // other Stream methods omitted for brevity


Unfortunately, there's no guarantee that Class<C> is assignable from Class<T>. Consider the following hierarchy:



public class Foo implements Comparable<Foo> { /* implementation */ }

public class Bar extends Foo {}

public class Qux extends Foo {}


You can now have a Stream of Bar elements but try to sort it as if it was a Stream of Qux elements.



Stream<Bar> stream = barCollection.stream().sorted(Qux.class);


Since both Bar and Qux match Comparable<? super Foo> there is no compile-time error and thus no type-safety is added. Also, the implication of requiring a Class argument is that it'll be used for casting. At runtime this can, as shown above, still result in ClassCastExceptions. If the Class isn't used for casting then the argument is completely useless; I'd even consider it harmful.



The next logical step is to try and require C extend T as well as Comparable<? super T>. For example:



<C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);


This is also not possible in Java and results in a compilation error: "type parameter cannot be followed by other bounds". Even if this were possible, I don't think it'd solve everything (if anything at all).





Some related notes.



Regarding Stream.sorted(Comparator): It isn't the Stream that makes this method type-safe, it's the Comparator. The Comparator ensures the elements can be compared. To illustrate, the type-safe way to sort a Stream by the elements' natural order is:



Stream<String> stream = stringCollection.stream().sorted(Comparator.naturalOrder());


This is type-safe because naturalOrder() requires its type parameter extend Comparable. If the generic type of the Stream did not extend Comparable then the bounds wouldn't match, resulting in a compilation error. But again, it's the Comparator that requires the elements be Comparable* while the Stream simply doesn't care.



So the question becomes, why did the developers include a no-argument sorted method for Stream in the first place? It appears to be for historical reasons and is explained in an answer to another question by Holger.





* The Comparator requires the elements be Comparable in this case. In general, a Comparator is obviously capable of handling any type it's defined to.






share|improve this answer






























    up vote
    18
    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
      Nov 9 at 3:58










    • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
      – Jacob G.
      Nov 9 at 4:00










    • 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
      Nov 9 at 4:04










    • @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.
      Nov 9 at 4:06






    • 8




      @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
      Nov 9 at 7:26


















    up vote
    15
    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
      Nov 9 at 3:47










    • @KorayTugay well yes, what is your point?
      – Eugene
      Nov 9 at 3:47






    • 14




      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
      Nov 9 at 7:21










    • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
      – Koray Tugay
      Nov 9 at 15:31










    • @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
      Nov 9 at 15:46











    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















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    24
    down vote



    accepted










    Essentially, you're asking if there's a way to tell the compiler, "hey, this one method requires the type parameter match more specific bounds than defined at the class level". This is not possible in Java. Such a feature may be useful but I'd also expect confusing and/or complicated.



    There's also no way to make Stream.sorted() type-safe with how generics is currently implemented; not if you want to avoid requiring a Comparator. For instance, you were proposing something like:



    public interface Stream<T> {

    <C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);

    } // other Stream methods omitted for brevity


    Unfortunately, there's no guarantee that Class<C> is assignable from Class<T>. Consider the following hierarchy:



    public class Foo implements Comparable<Foo> { /* implementation */ }

    public class Bar extends Foo {}

    public class Qux extends Foo {}


    You can now have a Stream of Bar elements but try to sort it as if it was a Stream of Qux elements.



    Stream<Bar> stream = barCollection.stream().sorted(Qux.class);


    Since both Bar and Qux match Comparable<? super Foo> there is no compile-time error and thus no type-safety is added. Also, the implication of requiring a Class argument is that it'll be used for casting. At runtime this can, as shown above, still result in ClassCastExceptions. If the Class isn't used for casting then the argument is completely useless; I'd even consider it harmful.



    The next logical step is to try and require C extend T as well as Comparable<? super T>. For example:



    <C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);


    This is also not possible in Java and results in a compilation error: "type parameter cannot be followed by other bounds". Even if this were possible, I don't think it'd solve everything (if anything at all).





    Some related notes.



    Regarding Stream.sorted(Comparator): It isn't the Stream that makes this method type-safe, it's the Comparator. The Comparator ensures the elements can be compared. To illustrate, the type-safe way to sort a Stream by the elements' natural order is:



    Stream<String> stream = stringCollection.stream().sorted(Comparator.naturalOrder());


    This is type-safe because naturalOrder() requires its type parameter extend Comparable. If the generic type of the Stream did not extend Comparable then the bounds wouldn't match, resulting in a compilation error. But again, it's the Comparator that requires the elements be Comparable* while the Stream simply doesn't care.



    So the question becomes, why did the developers include a no-argument sorted method for Stream in the first place? It appears to be for historical reasons and is explained in an answer to another question by Holger.





    * The Comparator requires the elements be Comparable in this case. In general, a Comparator is obviously capable of handling any type it's defined to.






    share|improve this answer



























      up vote
      24
      down vote



      accepted










      Essentially, you're asking if there's a way to tell the compiler, "hey, this one method requires the type parameter match more specific bounds than defined at the class level". This is not possible in Java. Such a feature may be useful but I'd also expect confusing and/or complicated.



      There's also no way to make Stream.sorted() type-safe with how generics is currently implemented; not if you want to avoid requiring a Comparator. For instance, you were proposing something like:



      public interface Stream<T> {

      <C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);

      } // other Stream methods omitted for brevity


      Unfortunately, there's no guarantee that Class<C> is assignable from Class<T>. Consider the following hierarchy:



      public class Foo implements Comparable<Foo> { /* implementation */ }

      public class Bar extends Foo {}

      public class Qux extends Foo {}


      You can now have a Stream of Bar elements but try to sort it as if it was a Stream of Qux elements.



      Stream<Bar> stream = barCollection.stream().sorted(Qux.class);


      Since both Bar and Qux match Comparable<? super Foo> there is no compile-time error and thus no type-safety is added. Also, the implication of requiring a Class argument is that it'll be used for casting. At runtime this can, as shown above, still result in ClassCastExceptions. If the Class isn't used for casting then the argument is completely useless; I'd even consider it harmful.



      The next logical step is to try and require C extend T as well as Comparable<? super T>. For example:



      <C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);


      This is also not possible in Java and results in a compilation error: "type parameter cannot be followed by other bounds". Even if this were possible, I don't think it'd solve everything (if anything at all).





      Some related notes.



      Regarding Stream.sorted(Comparator): It isn't the Stream that makes this method type-safe, it's the Comparator. The Comparator ensures the elements can be compared. To illustrate, the type-safe way to sort a Stream by the elements' natural order is:



      Stream<String> stream = stringCollection.stream().sorted(Comparator.naturalOrder());


      This is type-safe because naturalOrder() requires its type parameter extend Comparable. If the generic type of the Stream did not extend Comparable then the bounds wouldn't match, resulting in a compilation error. But again, it's the Comparator that requires the elements be Comparable* while the Stream simply doesn't care.



      So the question becomes, why did the developers include a no-argument sorted method for Stream in the first place? It appears to be for historical reasons and is explained in an answer to another question by Holger.





      * The Comparator requires the elements be Comparable in this case. In general, a Comparator is obviously capable of handling any type it's defined to.






      share|improve this answer

























        up vote
        24
        down vote



        accepted







        up vote
        24
        down vote



        accepted






        Essentially, you're asking if there's a way to tell the compiler, "hey, this one method requires the type parameter match more specific bounds than defined at the class level". This is not possible in Java. Such a feature may be useful but I'd also expect confusing and/or complicated.



        There's also no way to make Stream.sorted() type-safe with how generics is currently implemented; not if you want to avoid requiring a Comparator. For instance, you were proposing something like:



        public interface Stream<T> {

        <C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);

        } // other Stream methods omitted for brevity


        Unfortunately, there's no guarantee that Class<C> is assignable from Class<T>. Consider the following hierarchy:



        public class Foo implements Comparable<Foo> { /* implementation */ }

        public class Bar extends Foo {}

        public class Qux extends Foo {}


        You can now have a Stream of Bar elements but try to sort it as if it was a Stream of Qux elements.



        Stream<Bar> stream = barCollection.stream().sorted(Qux.class);


        Since both Bar and Qux match Comparable<? super Foo> there is no compile-time error and thus no type-safety is added. Also, the implication of requiring a Class argument is that it'll be used for casting. At runtime this can, as shown above, still result in ClassCastExceptions. If the Class isn't used for casting then the argument is completely useless; I'd even consider it harmful.



        The next logical step is to try and require C extend T as well as Comparable<? super T>. For example:



        <C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);


        This is also not possible in Java and results in a compilation error: "type parameter cannot be followed by other bounds". Even if this were possible, I don't think it'd solve everything (if anything at all).





        Some related notes.



        Regarding Stream.sorted(Comparator): It isn't the Stream that makes this method type-safe, it's the Comparator. The Comparator ensures the elements can be compared. To illustrate, the type-safe way to sort a Stream by the elements' natural order is:



        Stream<String> stream = stringCollection.stream().sorted(Comparator.naturalOrder());


        This is type-safe because naturalOrder() requires its type parameter extend Comparable. If the generic type of the Stream did not extend Comparable then the bounds wouldn't match, resulting in a compilation error. But again, it's the Comparator that requires the elements be Comparable* while the Stream simply doesn't care.



        So the question becomes, why did the developers include a no-argument sorted method for Stream in the first place? It appears to be for historical reasons and is explained in an answer to another question by Holger.





        * The Comparator requires the elements be Comparable in this case. In general, a Comparator is obviously capable of handling any type it's defined to.






        share|improve this answer














        Essentially, you're asking if there's a way to tell the compiler, "hey, this one method requires the type parameter match more specific bounds than defined at the class level". This is not possible in Java. Such a feature may be useful but I'd also expect confusing and/or complicated.



        There's also no way to make Stream.sorted() type-safe with how generics is currently implemented; not if you want to avoid requiring a Comparator. For instance, you were proposing something like:



        public interface Stream<T> {

        <C extends Comparable<? super T>> Stream<T> sorted(Class<C> clazz);

        } // other Stream methods omitted for brevity


        Unfortunately, there's no guarantee that Class<C> is assignable from Class<T>. Consider the following hierarchy:



        public class Foo implements Comparable<Foo> { /* implementation */ }

        public class Bar extends Foo {}

        public class Qux extends Foo {}


        You can now have a Stream of Bar elements but try to sort it as if it was a Stream of Qux elements.



        Stream<Bar> stream = barCollection.stream().sorted(Qux.class);


        Since both Bar and Qux match Comparable<? super Foo> there is no compile-time error and thus no type-safety is added. Also, the implication of requiring a Class argument is that it'll be used for casting. At runtime this can, as shown above, still result in ClassCastExceptions. If the Class isn't used for casting then the argument is completely useless; I'd even consider it harmful.



        The next logical step is to try and require C extend T as well as Comparable<? super T>. For example:



        <C extends T & Comparable<? super T>> Stream<T> sorted(Class<C> clazz);


        This is also not possible in Java and results in a compilation error: "type parameter cannot be followed by other bounds". Even if this were possible, I don't think it'd solve everything (if anything at all).





        Some related notes.



        Regarding Stream.sorted(Comparator): It isn't the Stream that makes this method type-safe, it's the Comparator. The Comparator ensures the elements can be compared. To illustrate, the type-safe way to sort a Stream by the elements' natural order is:



        Stream<String> stream = stringCollection.stream().sorted(Comparator.naturalOrder());


        This is type-safe because naturalOrder() requires its type parameter extend Comparable. If the generic type of the Stream did not extend Comparable then the bounds wouldn't match, resulting in a compilation error. But again, it's the Comparator that requires the elements be Comparable* while the Stream simply doesn't care.



        So the question becomes, why did the developers include a no-argument sorted method for Stream in the first place? It appears to be for historical reasons and is explained in an answer to another question by Holger.





        * The Comparator requires the elements be Comparable in this case. In general, a Comparator is obviously capable of handling any type it's defined to.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 14 at 8:57

























        answered Nov 9 at 5:32









        Slaw

        5,6482729




        5,6482729
























            up vote
            18
            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
              Nov 9 at 3:58










            • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
              – Jacob G.
              Nov 9 at 4:00










            • 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
              Nov 9 at 4:04










            • @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.
              Nov 9 at 4:06






            • 8




              @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
              Nov 9 at 7:26















            up vote
            18
            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
              Nov 9 at 3:58










            • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
              – Jacob G.
              Nov 9 at 4:00










            • 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
              Nov 9 at 4:04










            • @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.
              Nov 9 at 4:06






            • 8




              @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
              Nov 9 at 7:26













            up vote
            18
            down vote










            up vote
            18
            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 Nov 9 at 4:12

























            answered Nov 9 at 3:44









            Jacob G.

            14.6k51961




            14.6k51961








            • 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
              Nov 9 at 3:58










            • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
              – Jacob G.
              Nov 9 at 4:00










            • 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
              Nov 9 at 4:04










            • @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.
              Nov 9 at 4:06






            • 8




              @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
              Nov 9 at 7:26














            • 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
              Nov 9 at 3:58










            • There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
              – Jacob G.
              Nov 9 at 4:00










            • 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
              Nov 9 at 4:04










            • @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.
              Nov 9 at 4:06






            • 8




              @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
              Nov 9 at 7:26








            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
            Nov 9 at 3:58




            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
            Nov 9 at 3:58












            There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
            – Jacob G.
            Nov 9 at 4:00




            There's already an overloaded Stream#sorted method that accepts a Comparator. It accepting a Comparable wouldn't make much sense.
            – Jacob G.
            Nov 9 at 4:00












            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
            Nov 9 at 4:04




            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
            Nov 9 at 4:04












            @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.
            Nov 9 at 4:06




            @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.
            Nov 9 at 4:06




            8




            8




            @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
            Nov 9 at 7:26




            @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
            Nov 9 at 7:26










            up vote
            15
            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
              Nov 9 at 3:47










            • @KorayTugay well yes, what is your point?
              – Eugene
              Nov 9 at 3:47






            • 14




              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
              Nov 9 at 7:21










            • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
              – Koray Tugay
              Nov 9 at 15:31










            • @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
              Nov 9 at 15:46















            up vote
            15
            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
              Nov 9 at 3:47










            • @KorayTugay well yes, what is your point?
              – Eugene
              Nov 9 at 3:47






            • 14




              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
              Nov 9 at 7:21










            • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
              – Koray Tugay
              Nov 9 at 15:31










            • @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
              Nov 9 at 15:46













            up vote
            15
            down vote










            up vote
            15
            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 Nov 9 at 4:18

























            answered Nov 9 at 3:44









            Eugene

            66.4k996159




            66.4k996159








            • 2




              Well sorted in this example knows the type again, that is a Stream<String>, isn 't it?
              – Koray Tugay
              Nov 9 at 3:47










            • @KorayTugay well yes, what is your point?
              – Eugene
              Nov 9 at 3:47






            • 14




              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
              Nov 9 at 7:21










            • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
              – Koray Tugay
              Nov 9 at 15:31










            • @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
              Nov 9 at 15:46














            • 2




              Well sorted in this example knows the type again, that is a Stream<String>, isn 't it?
              – Koray Tugay
              Nov 9 at 3:47










            • @KorayTugay well yes, what is your point?
              – Eugene
              Nov 9 at 3:47






            • 14




              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
              Nov 9 at 7:21










            • @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
              – Koray Tugay
              Nov 9 at 15:31










            • @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
              Nov 9 at 15:46








            2




            2




            Well sorted in this example knows the type again, that is a Stream<String>, isn 't it?
            – Koray Tugay
            Nov 9 at 3:47




            Well sorted in this example knows the type again, that is a Stream<String>, isn 't it?
            – Koray Tugay
            Nov 9 at 3:47












            @KorayTugay well yes, what is your point?
            – Eugene
            Nov 9 at 3:47




            @KorayTugay well yes, what is your point?
            – Eugene
            Nov 9 at 3:47




            14




            14




            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
            Nov 9 at 7:21




            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
            Nov 9 at 7:21












            @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
            – Koray Tugay
            Nov 9 at 15:31




            @Holger I wish you provided an answer, what you share in comments is very valuable but might be overlooked.
            – Koray Tugay
            Nov 9 at 15:31












            @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
            Nov 9 at 15:46




            @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
            Nov 9 at 15:46


















             

            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















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Landwehr

            Reims

            Schenkenzell