ПРИХОДИТЕ УЧИТЬСЯ НОВОЙ ПРОФЕССИИ ЛЕТОМ СО СКИДКОЙ ДО 70%Забронировать скидку

Ограничение потока в Java 8: аналог функции takeWhile

Пройдите тест, узнайте какой профессии подходите и получите бесплатную карьерную консультацию
В конце подарим скидку до 55% на обучение
Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Чтобы улучшить производительность потоков в Java, используйте метод takeWhile. Он прерывает поток, как только обнаруживается значение, не соответствующее условию предиката:

Java
Скопировать код
List<String> filtered = Stream.of("first", "second", "halt", "third")
                              .takeWhile(s -> !"halt".equals(s))
                              .collect(Collectors.toList());
// Результат: ["first", "second"]

Метод takeWhile можно рассматривать как надежный механизм слежения за выполнением потока.

Пройдите тест и узнайте подходит ли вам сфера IT
Пройти тест

Обходное решение для Java 8

Реализация takeWhile до выпуска JDK 9

В Java 8 можно самостоятельно применить функциональность, аналогичную takeWhile, используя Spliterator и StreamSupport:

Java
Скопировать код
public static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<T> predicate) {
    Spliterator<T> splitr = stream.spliterator();
    return StreamSupport.stream(
        new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
            boolean running = true; // Начальное состояние: без перерывов

            @Override
            public boolean tryAdvance(Consumer<? super T> action) {
                if (running) {
                    boolean hasMore = splitr.tryAdvance(elem -> {
                        if (predicate.test(elem)) {
                            action.accept(elem);
                        } else {
                            running = false; // Переходим в состояние перерыва
                        }
                    });
                    return hasMore && running;
                }
                return false;
            }
        }, false); // Параллельные потоки не предусматривают перерывы
}

StreamEx приходит с помощью

Библиотека StreamEx предоставляет собственный метод takeWhile, воссоздающий функциональность, внедренную в JDK 9:

Java
Скопировать код
List<String> list = StreamEx.of("one", "two", "stop", "three")
                            .takeWhile(s -> !"stop".equals(s))
                            .toList();
// Результат: ["one", "two"]

StreamEx обеспечивает отличную производительность, опираясь на MethodHandle.invokeExact.

Проект Protonpack не остается в стороне

Библиотека Protonpack включает функцию takeWhile, доступную для Java 8:

Java
Скопировать код
List<String> result = StreamUtils.takeWhile(Stream.of("1", "2", "stop", "3"), s -> !s.equals("stop"))
                                 .collect(Collectors.toList());
// Результат: ["1", "2"]

Обе библиотеки предоставляют возможность использования takeWhile в Java 8.

Использование IntStream с предикатом

С помощью метода iterate класса IntStream, добавив peek и allMatch, можно контролировать потоки следующим образом:

Java
Скопировать код
int[] nums = IntStream.iterate(1, i -> i + 1)
                      .peek(i -> { if (i > 5) throw new BreakerException(); }) // Неожиданный выход
                      .limit(10)
                      .toArray();

Внимание: Использование BreakerException для прекращения работы может привести к проблемам с обработкой исключений.

Визуализация

Наглядно Java Stream представляет собой конвейер:

Markdown
Скопировать код
Конвейер (🏭): [🔩, 📦, 🔧, 🔨, 🧰]

Predicate выступает в роли инспектора по контролю качества 🕵️‍♂️:

Java
Скопировать код
stream.filter(item -> inspectorLikes(item)); // Инспектор выбирает подходящие элементы

Как только встречается первый неподходящий элемент, Stream API прекращает обработку последующих:

Markdown
Скопировать код
Инспекция: [🔩✅, 📦✅, 🔧❌, 🔨⛔, 🧰⛔] // Как бы сказал Саймон Кауэлл: "Все, кончено"

Поток замирает, как автомат с напитками, сломанный в неопожеланный момент.

Важность эффективности

Сравнение Java 8 и Java 9+

Несмотря на то что пользовательский takeWhile для Java 8 кажется применимым, его исполнение занимает больше времени, чем работа с встроенным методом в Java 9 и выше.

Места для усовершенствований

Чтобы воспользоваться встроенными и оптимизированными возможностями, рекомендуется перейти на JDK 9 или более поздние версии.

StreamEx: Возможностей больше, чем кажется

StreamEx предлагает не только takeWhile. Стоит обратить внимание на его документацию — это ценный источник информации о потоках, который заслуживает изучения.

Полезные материалы

  1. Stream (Java Platform SE 8 )Документация Java 8 по потокам.
  2. Processing Data with Java SE 8 Streams, Part 1Руководство Oracle по работе с потоками данных в Java 8.
  3. java – Limit a stream by a predicate – Stack OverflowРешения сообщества по ограничению потока с использованием предиката.
  4. Java 8 – StreamsОсновы обработки потоков в Java 8.
  5. Open source Java projects: Vert.x – Пример использования Java на примере проекта Vert.x.