Что делает метод sequential() в Java Stream API?

Ответ

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

Пример использования

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Создаём параллельный стрим, затем явно делаем последовательным
Stream<Integer> stream = numbers.stream()
    .parallel()          // Включает параллельную обработку
    .map(n -> n * 2)     // Операция выполняется параллельно
    .sequential()        // Возвращает последовательный режим
    .filter(n -> n > 5); // Дальнейшая обработка — последовательная

System.out.println("Is parallel? " + stream.isParallel()); // false

Важные особенности

  1. Последний вызов определяет режим: stream.parallel().sequential().parallel() — результат будет параллельным.
  2. Производительность: Переключение режима добавляет небольшие накладные расходы.
  3. Типичный use-case:
    // Если нужно временно использовать параллельную обработку
    long count = data.stream()
    .parallel()              // Параллельная фильтрация
    .filter(this::heavyPredicate)
    .sequential()            // Возврат к последовательному режиму
    .map(this::complexMapping)
    .count();
  4. Альтернатива: Чаще используют отдельные стримы для разных режимов вместо переключения.

Рекомендация: Используйте parallel() только для CPU-интенсивных операций над большими наборами данных, когда профилирование подтверждает выигрыш в производительности.

Ответ 18+ 🔞

Слушай, а вот этот метод sequential() — он как будто для тех, кто сначала нажмёт на газ до упора, а потом резко передумает и вдавит тормоз. Ну, в смысле, берёшь ты свой стрим, делаешь его параллельным, а потом такой: «Ой, бля, не, давай обратно, по порядку!».

По дефолту-то все стримы и так последовательные, это ж очевидно. Но если ты уже вляпался в parallel(), а потом спохватился — вот тут sequential() и выручает, как скорая помощь для твоей распиздяйской архитектуры.

Смотри, как это выглядит в коде

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Начинаем умничать: делаем параллельность, а потом откатываемся
Stream<Integer> stream = numbers.stream()
    .parallel()          // Включили многопоточность — все побежали
    .map(n -> n * 2)     // Тут работа идёт вразнобой, как тараканы
    .sequential()        // А тут такой: «Стоп, мудаки! Построились в очередь!»
    .filter(n -> n > 5); // И дальше уже честно, по одному

System.out.println("Is parallel? " + stream.isParallel()); // false — ну конечно, мы же передумали!

Важные фишки, которые надо знать

  1. Кто последний, тот и папа: Если написать stream.parallel().sequential().parallel(), то в итоге будет параллельный режим. Это как в детстве: «Кто последний сказал, тот и прав!». Компилятору похуй на твои метания, берёт последнюю команду.
  2. Накладные расходы: Каждое переключение — это маленький пинок под жопу системе. Не то чтобы овердохуища, но если делать это в цикле — сам потом будешь плакать.
  3. Типичный сценарий использования:
    // Допустим, часть работы тяжёлая, её можно распараллелить
    long count = data.stream()
    .parallel()              // Пусть тут потоки поработают
    .filter(this::heavyPredicate) // Тяжёлая операция — пусть греют процессор
    .sequential()            // А дальше — стоп, нафиг, возвращаемся к порядку
    .map(this::complexMapping) // Что-то сложное, но не для параллели
    .count();
  4. Альтернативный подход: Чаще просто делают два отдельных стрима — один параллельный, другой последовательный. Так понятнее и без этих танцев с бубном.

Совет на посошок: parallel() — это не магия, а инструмент. Кидай его только на реально большие данные и CPU-интенсивные задачи, да и то после замеров. А то получится как всегда: хотел как лучше, а вышло «ёпта, оно ещё и медленнее работает».