Ответ
Метод 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
Важные особенности
- Последний вызов определяет режим:
stream.parallel().sequential().parallel()— результат будет параллельным. - Производительность: Переключение режима добавляет небольшие накладные расходы.
- Типичный use-case:
// Если нужно временно использовать параллельную обработку long count = data.stream() .parallel() // Параллельная фильтрация .filter(this::heavyPredicate) .sequential() // Возврат к последовательному режиму .map(this::complexMapping) .count(); - Альтернатива: Чаще используют отдельные стримы для разных режимов вместо переключения.
Рекомендация: Используйте 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 — ну конечно, мы же передумали!
Важные фишки, которые надо знать
- Кто последний, тот и папа: Если написать
stream.parallel().sequential().parallel(), то в итоге будет параллельный режим. Это как в детстве: «Кто последний сказал, тот и прав!». Компилятору похуй на твои метания, берёт последнюю команду. - Накладные расходы: Каждое переключение — это маленький пинок под жопу системе. Не то чтобы овердохуища, но если делать это в цикле — сам потом будешь плакать.
- Типичный сценарий использования:
// Допустим, часть работы тяжёлая, её можно распараллелить long count = data.stream() .parallel() // Пусть тут потоки поработают .filter(this::heavyPredicate) // Тяжёлая операция — пусть греют процессор .sequential() // А дальше — стоп, нафиг, возвращаемся к порядку .map(this::complexMapping) // Что-то сложное, но не для параллели .count(); - Альтернативный подход: Чаще просто делают два отдельных стрима — один параллельный, другой последовательный. Так понятнее и без этих танцев с бубном.
Совет на посошок: parallel() — это не магия, а инструмент. Кидай его только на реально большие данные и CPU-интенсивные задачи, да и то после замеров. А то получится как всегда: хотел как лучше, а вышло «ёпта, оно ещё и медленнее работает».