Обратный отсортировать поток

Я хочу отменить сортировку потока, как показано ниже, но получаю ошибку времени компиляции как "The method sorted() in the type IntStream is not applicable for the arguments ((<no type> o1, <no type> o2) -> {})". Кто-нибудь может это исправить

IntStream.range(1, 100)
         .filter(x -> x%2 != 0)
         .sorted((o1,o2) -> -o1.compareTo(o2))
         .forEach(System.out::println);

Мне любопытно, зачем вам использовать потоки для чего-то подобного. Казалось бы, это только добавило кучу накладных расходов.

JimmyJames 13.12.2018 18:25
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
11
1
1 222
3

Ответы 3

Объяснение

поскольку вы работаете с IntStream, у него есть только одна перегрузка метода отсортированный, и это естественный порядок (что имеет смысл).

вместо этого поместите поток из IntStream в Stream<Integer>, тогда этого должно хватить:

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

Однако, как упоминал @Holger в комментариях:

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)

Предложения по улучшению вашего кода. JDK8

Лучшим подходом было бы:

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

Зачем?

  • Уже есть встроенный компаратор для выполнения обратного порядка, как показано выше.
  • если вы хотите, чтобы гарантия отображал элементы в отсортированном порядке при печати, используйте forEachOrdered (большой привет @Holger, чтобы он всегда напоминал мне)

или, как предлагает @Holger, все это можно упростить до такой степени:

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

Вариант JDK9

Кстати, в JDK9, начиная с кода в вашем сообщении, вы можете сначала упростить его с помощью iterate, чтобы:

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

При таком подходе мы можем избежать промежуточной операции фильтрации и увеличения до 2.

и, наконец, вы можете еще больше упростить его с помощью:

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

При таком подходе мы можем избежать filter, boxed, sorted и др.

Когда мы используем обычные напоминания, никогда не используйте функцию компаратора, такую ​​как (o1,o2) -> -o1.compareTo(o2). Для реализации compareTo совершенно законно возвращать Integer.MIN_VALUE, и в этом случае отрицание не удастся и даст противоречивые результаты. Допустимым обратным компаратором может быть (o1,o2) -> o2.compareTo(o1) или просто Comparator.reverseOrder(), как вы показали, который уже выполняет свою работу правильно. Кстати, я бы использовал не iterate, а IntStream.range(0, 50).map(i -> 99-i*2), который во многих случаях более эффективен.

Holger 13.12.2018 18:25

@Holger очень признателен за обучение, как всегда. отредактирован с учетом ваших рекомендаций.

Ousmane D. 13.12.2018 18:37

Если это ваш настоящий код, то может быть более эффективным использовать IntStream.iterate и генерировать числа от 99 до 0:

IntStream.iterate(99, i -> i - 1)
    .limit(100)
    .filter(x -> x % 2 != 0)
    .forEachOrdered(System.out::println);

Как насчет простой утилиты, такой как:

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

Кредиты: Стюарт Маркс для обратного использования.

Другие вопросы по теме