1. Обзор
В этой краткой статье мы обсудим общее Исключение , с которым мы можем столкнуться при работе с классом Stream в Java 8:
IllegalStateException: stream has already been operated upon or closed.
Мы рассмотрим сценарии, когда возникает это исключение, и возможные способы его избежать, а также практические примеры.
2. Причина
В Java 8 каждый класс Stream представляет собой одноразовую последовательность данных и поддерживает несколько операций ввода-вывода.
Поток следует запускать (вызывая промежуточную или конечную операцию потока) только один раз. Реализация потока может вызвать Исключение IllegalStateException , если оно обнаруживает, что Поток используется повторно.
Всякий раз, когда терминальная операция вызывается для объекта Stream , экземпляр потребляется и закрывается.
Поэтому нам разрешено выполнять только одну операцию, которая потребляет Поток , в противном случае мы получим исключение, в котором говорится, что Поток уже был обработан или закрыт.
Давайте посмотрим, как это можно перевести на практический пример:
StreamstringStream = Stream.of("A", "B", "C", "D"); Optional result1 = stringStream.findAny(); System.out.println(result1.get()); Optional result2 = stringStream.findFirst();
В результате:
A Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
После вызова метода #findAny() поток строк закрывается, поэтому любая дальнейшая операция с потоком вызовет исключение IllegalStateException , и это произошло после вызова метода #findFirst () .
3. Решение
Проще говоря, решение состоит в создании нового Потока каждый раз, когда он нам нужен.
Мы, конечно, можем сделать это вручную, но именно здесь функциональный интерфейс Поставщик становится действительно удобным:
Supplier> streamSupplier = () -> Stream.of("A", "B", "C", "D"); Optional result1 = streamSupplier.get().findAny(); System.out.println(result1.get()); Optional result2 = streamSupplier.get().findFirst(); System.out.println(result2.get());
В результате:
A A
Мы определили объект поставщик потока с типом Поток<Строка> , который является точно таким же типом, который возвращает метод #get () . Поставщик основан на лямбда-выражении, которое не принимает входных данных и возвращает новый Поток .
Вызов функционального метода get() на Поставщике возвращает только что созданный Поток объект, над которым мы можем безопасно выполнить другую Потоковую операцию.
5. Заключение
В этом кратком руководстве мы рассмотрели, как выполнять терминальные операции с Потоком несколько раз, избегая при этом известного исключения IllegalStateException , которое возникает, когда Поток уже закрыт или обработан.
Вы можете найти полный исходный код и все фрагменты кода для этой статьи на GitHub .