Copy a Stream to Avoid "Stream Has Already Been Operated Upon or Closed"

Stream has already been operated upon or closed from supplier

Look at the message closely (emphasis mine):

java.lang.IllegalStateException: stream has already been operated
upon or closed

Since there is no terminal operation in your first statement, your stream has not been closed but has been operated upon which is the reason why you are getting the error when you try to operate on it the second time.

You can change it as follows to get rid of the error:

supplierUserStream.get().sorted().sorted();

ONLINE DEMO

However, it will be a kind of hiding a potential problem e.g. if you replace the test call in main, with the following statement, you will again get the same problem:

getStringStream(Stream.of("Hello", "World")).forEach(System.out::println);

A good way to deal with it can be as suggested by ernest_k:

It can also be resolved by keeping track of derived stream objects.
Stream stream = s.get().sorted(); stream = stream.sorted();
return stream.sorted();, to reuse those redundant sort() calls.

Demo:

import java.util.function.Supplier;
import java.util.stream.Stream;

public class Main {
public static void main(String[] args) {
getStringStream(Stream.of("World", "Hello", "Good morning!")).forEach(System.out::println);
}

private static Stream<String> getStringStream(Stream<String> testStream) {
Supplier<Stream<String>> supplierStringStream = () -> testStream;
Stream<String> stream = supplierStringStream.get().sorted();
return stream.sorted();
}
}

Output:

Good morning!
Hello
World

Still getting stream has already been operated upon or closed error

The problem is that your supplier isn't giving you two instances of the stream: it's giving you the same one each time. streamSupplier.get() is no different from using lines directly.

If you want to read two things from the stream, skip by offset, then limit by 2, then collect to a list:

List<String> items = lines.skip(offset).limit(2).collect(Collectors.toList());

Now you can get those items from the list:

Optional<String> line = items.size() > 0 ? Optional.of(items.get(0)) : Optional.empty();
Optional<String> nextLine = items.size() > 1 ? Optional.of(items.get(1)) : Optional.empty();

java.lang.IllegalStateException: stream has already been operated upon or closed in Java while working with list

After that

Supplier<Stream<Item>> streamSupplier = ()-> itemsList;
streamSupplier.get().filter(t-> t.getItemType().equals(ItemType.GOLD))
.forEach(item->item.setPrice(item.getWeightInGrams()*2700));

The stream is closed.

So the following line
itemsList.forEach(t->System.out.println(t)

calls the foreach terminal operation on a already closed stream . It is forbidden.

Stream supplier getting error 'stream has already been operated upon or closed'

The general problem is as Christian Ullenboom said: The stream has already been consumed. The exact location in your code is the call to resultStreamWithExpectedStatus.count() in the method getResultsWithExpectedStatusSupplier, as Stream.count is a reduction/terminal operation which consumes the stream.

As stated in e.g. this answer, you cannot get the streams size without consuming it. Fix it by storing the filtered items in a collection (e.g. Collectors.toList), querying the size there and returning the collection itself rather than the stream?

On a side note, I think you misuse Optional a bit too much. The code could be simpler passing empty streams (or even better: pass an empty, filtered collection).

Stream has already been operated upon or closed while loop the content of a file

The stream can only be iterated through once. You're iterating it for every element in the map.

Stop using lambdas (generally, a straight .forEach on a stream is bad java code; you're losing checked exception, control flow, and local variable transparency and you gain nothing) and the problem goes away:

static void main(String[] args) throws IOException {
var path = Paths.get(fileName);
var lines = Files.readAllLines(path);
for (var e : map.entrySet()) {
for (String line : lines) {
String cadenaWena = line.replace(caracterMal, caracterBien);
System.out.println(cadenaWena);
}
}
}

This fixes many things:

  • It reads the file once instead of over and over again. Memory access is a heck of a lot faster than disk access.
  • It doesn't have crazy error handling (print half of the error, toss the other half in the bin, and just keep going? That's not good code).
  • It's shorter.
  • It uses the proper replace (which replaces ALL occurrences). replaceAll is a misnamed method that interprets the first argument as a regexp, and it clearly isn't in your case.
  • It doesn't use pointless lambdas and thus is more flexible.

Stream has already been operated upon or closed - Java 8

You can't operate on Streams more than once so you are better off using Collections as these can be used more than once.

Set<String> titleExclusions = ResourceUtility.contentToUtf8TreeSet("+.txt")
.stream()
.filter(item -> !item.isEmpty())
.collect(Collectors.toSet());
// uses titleExclusions
boolean noMatches = titleExclusions.stream()
.noneMatch(tittle::contains);
// uses titleExclusions again.

Note: I assume you wanted the non-blank lines from your source file instead of the sets of blank ones. filter takes a Predicate of what is retained rather than what is discarded.

Thank you @Holger for simplifying the second statement.



Related Topics



Leave a reply



Submit