11

I want to reverse sort a stream such as below but getting compile time error as "The method sorted() in the type IntStream is not applicable for the arguments ((<no type> o1, <no type> o2) -> {})". Can anyone correct this

IntStream.range(1, 100)
         .filter(x -> x%2 != 0)
         .sorted((o1,o2) -> -o1.compareTo(o2))
         .forEach(System.out::println);
user2357112
  • 260,549
  • 28
  • 431
  • 505
Sundresh
  • 185
  • 5
  • 5
    I'm curious as to why you would use streams for something like this. It would seem to only add a bunch of overhead. – JimmyJames Dec 13 '18 at 17:25

3 Answers3

16

Explanation

since you're working with an IntStream it only has one overload of the sorted method and it's the natural order (which makes sense).

instead, box the stream from IntStream to Stream<Integer> then it should suffice:

 IntStream.range(1, 100)
          .filter(x -> x % 2 != 0)
          .boxed()  // <--- boxed to Stream<Integer>
          .sorted((o1,o2) -> -o1.compareTo(o2)) // now we can call compareTo on Integer
          .forEach(System.out::println);

However, as mentioned by @Holger in the comments:

never use a comparator function like (o1,o2) -> -o1.compareTo(o2). It is perfectly legal for a compareTo implementation to return Integer.MIN_VALUE, in which case negation will fail and produce inconsistent results. A valid reverse comparator would be (o1,o2) -> o2.compareTo(o1)

Suggestions to improve your code. JDK8

A better approach would be:

IntStream.range(1, 100)
         .filter(x -> x % 2 != 0)
         .boxed()
         .sorted(Comparator.reverseOrder())
         .forEachOrdered(System.out::println);

why?

  • There's already a built-in comparator to perform reverse order as shown above.
  • if you want to guarantee that the elements are to be seen in the sorted order when printing then utilise forEachOrdered (big shout out to @Holger for always reminding me)

or as suggested by @Holger it can all be simplified to as little as this:

 IntStream.range(0, 50)
          .map(i -> 99-i*2)
          .forEachOrdered(System.out::println);

JDK9 variant

btw, in JDK9 starting from the code in your post, you can first simplify it via iterate to:

IntStream.iterate(1, i  -> i <= 99, i -> i + 2)
         .boxed()
         .sorted(Comparator.reverseOrder())
         .forEachOrdered(System.out::println);

With this approach, we can avoid the filter intermediate operation and increment in 2's.

and finally you could simplify it even further with:

IntStream.iterate(99, i  -> i > 0 , i -> i - 2)
         .forEachOrdered(System.out::println);

With this approach, we can avoid filter, boxed,sorted et al.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • 4
    When we are at usual reminders, never use a comparator function like `(o1,o2) -> -o1.compareTo(o2)`. It is perfectly legal for a `compareTo` implementation to return `Integer.MIN_VALUE`, in which case negation will fail and produce inconsistent results. A valid reverse comparator would be `(o1,o2) -> o2.compareTo(o1)`, or just `Comparator.reverseOrder()` as you have shown, which does already the job right. By the way, I wouldn’t use `iterate` but rather `IntStream.range(0, 50).map(i -> 99-i*2)` which is more efficient in a lot of cases. – Holger Dec 13 '18 at 17:25
  • 2
    @Holger really appreciated, learning as always. edited to accommodate your recommendations. – Ousmane D. Dec 13 '18 at 17:37
4

If that is your real code, then it may be more efficient to use IntStream.iterate and generate numbers from 99 to 0:

IntStream.iterate(99, i -> i - 1)
    .limit(100)
    .filter(x -> x % 2 != 0)
    .forEachOrdered(System.out::println);
ernest_k
  • 44,416
  • 5
  • 53
  • 99
3

How about simple util such as :

private IntStream reverseSort(int from, int to) {
    return IntStream.range(from, to)
                    .filter(x -> x % 2 != 0)
                    .sorted()
                    .map(i -> to - i + from - 1);
}

Credits: Stuart Marks for the reverse util.

Naman
  • 27,789
  • 26
  • 218
  • 353