Есть ли способ повторно использовать Stream?

Я изучаю новые функции Java 8, и, экспериментируя с streamами ( java.util.stream.Stream ) и сборщиками, я понял, что stream нельзя использовать дважды.

Есть ли способ его повторно использовать?

Из документации :

Поток должен управляться (вызывая операцию промежуточного или терминального streamа) только один раз.

Реализация streamа может вызывать исключение IllegalStateException, если оно обнаруживает, что stream повторно используется.

Таким образом, ответ отрицательный, streamи не предназначены для повторного использования.

Если вы хотите, чтобы эффект повторного использования streamа, вы можете обернуть выражение streamа в Поставщике и вызвать myStreamSupplier.get() всякий раз, когда хотите новый. Например:

 Supplier> sup = () -> someList.stream(); List nonEmptyStrings = sup.get().filter(s -> !s.isEmpty()).collect(Collectors.toList()); Set uniqueStrings = sup.get().collect(Collectors.toSet()); 

Как говорили другие, «нет, вы не можете».

Но полезно запомнить summaryStatistics() для многих основных операций:

Поэтому вместо:

 List personList = getPersons(); personList.stream().mapToInt(p -> p.getAge()).average().getAsDouble(); personList.stream().mapToInt(p -> p.getAge()).min().getAsInt(); personList.stream().mapToInt(p -> p.getAge()).max().getAsInt(); 

Ты можешь:

 // Can also be DoubleSummaryStatistics from mapToDouble() IntSummaryStatistics stats = personList.stream() .mapToInt(p-> p.getAge()) .summaryStatistics(); stats.getAverage(); stats.getMin(); stats.getMax(); 

Вся идея Stream состоит в том, что он разом. Это позволяет создавать не возвращаемые источники (например, чтение строк из сетевого подключения) без промежуточного хранения. Если вы, однако, хотите повторно использовать контент Stream, вы можете отправить его в промежуточную коллекцию, чтобы получить «печатную копию»:

 Stream stream = // get the stream from somewhere List list = stream.collect(Collectors.toList()); // materialize the stream contents list.stream().doSomething // create a new stream from the list list.stream().doSomethingElse // create one more stream from the list 

Если вы не хотите материализовать stream, в некоторых случаях есть способы сделать несколько вещей с одним и тем же streamом сразу. Например, вы можете обратиться к этому или к этому вопросу для получения дополнительной информации.

Как отмечали другие, сам объект streamа не может быть повторно использован.

Но одним из способов получить эффект повторного использования streamа является извлечение кода создания streamа в функцию .

Вы можете сделать это, создав метод или объект функции, который содержит код создания streamа. Затем вы можете использовать его несколько раз.

Пример:

 public static void main(String[] args) { List list = Arrays.asList(1, 2, 3, 4, 5); // The normal way to use a stream: List result1 = list.stream() .filter(i -> i % 2 == 1) .map(i -> i * i) .limit(10) .map(i -> "i :" + i) .collect(toList()); // The stream operation can be extracted to a local function to // be reused on multiple sources: Function, List> listOperation = l -> l.stream() .filter(i -> i % 2 == 1) .map(i -> i * i) .limit(10) .map(i -> "i :" + i) .collect(toList()); List result2 = listOperation.apply(list); List result3 = listOperation.apply(Arrays.asList(1, 2, 3)); // Or the stream operation can be extracted to a static method, // if it doesn't refer to any local variables: List result4 = streamMethod(list); // The stream operation can also have Stream as argument and return value, // so that it can be used as a component of a longer stream pipeline: Function, Stream> streamOperation = s -> s .filter(i -> i % 2 == 1) .map(i -> i * i) .limit(10) .map(i -> "i :" + i); List result5 = streamOperation.apply(list.stream().map(i -> i * 2)) .filter(s -> s.length() < 7) .sorted() .collect(toCollection(LinkedList::new)); } public static List streamMethod(List l) { return l.stream() .filter(i -> i % 2 == 1) .map(i -> i * i) .limit(10) .map(i -> "i :" + i) .collect(toList()); } 

Если, с другой стороны, у вас уже есть объект streamа, который вы хотите перебирать несколько раз, тогда вы должны сохранить содержимое streamа в каком-либо объекте коллекции.

Затем вы можете получить несколько streamов с тем же содержимым, что и коллекция.

Пример:

 public void test(Stream stream) { // Create a copy of the stream elements List streamCopy = stream.collect(toList()); // Use the copy to get multiple streams List result1 = streamCopy.stream() ... List result2 = streamCopy.stream() ... } 

Подумайте об этом, эта воля «повторного использования» streamа – это просто желание выполнить желаемый результат с хорошей встроенной операцией. Итак, в основном, о чем мы говорим здесь, что мы можем сделать, чтобы продолжить обработку после того, как мы написали операцию терминала?

1) если операция терминала возвращает коллекцию , проблема сразу решена, так как каждая коллекция может быть возвращена в stream (JDK 8).

 List l=Arrays.asList(5,10,14); l.stream() .filter(nth-> nth>5) .collect(Collectors.toList()) .stream() .filter(nth-> nth%2==0).forEach(nth-> System.out.println(nth)); 

2) если ваши операции с терминалом возвращают необязательный , с усовершенствованиями JDK 9 в class «Дополнительно», вы можете превратить Необязательный результат в stream и получить желаемую приятную встроенную операцию:

 List l=Arrays.asList(5,10,14); l.stream() .filter(nth-> nth>5) .findAny() .stream() .filter(nth-> nth%2==0).forEach(nth-> System.out.println(nth)); 

3) если операция терминала возвращает что-то еще , я действительно сомневаюсь, что вы должны рассмотреть stream для обработки такого результата:

 List l=Arrays.asList(5,10,14); boolean allEven=l.stream() .filter(nth-> nth>5) .allMatch(nth-> nth%2==0); if(allEven){ ... }