I want to reuse stream object in my method, but when I call second time from supplier I saw stream has already been operated upon or closed error.
private Stream<User> getUserStream(Stream<User> testStream) {
Supplier<Stream<User>> supplierUserStream=()->userStream;
supplierUserStream.get().sorted();
supplierUserStream.get().sorted();// throw exception Stream has already been operated upon or closed
return userStream;
}
I don't want to convert stream to a list. I saw a lot of examples like that.
Supplier<Stream<User>> streamSupplier
= () -> Stream.of(userStream.toArray(size -> new User[size]));
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
Related
This question already has answers here:
java.util.NoSuchElementException: No value present even though we use stream
(2 answers)
Closed 9 months ago.
While filtering through a list of user defined class type using Stream API has been encountered some cases where no element has been found in the list for given condition.
How to prevent exception in such case and handle according to business logic using optional class?
Stream API method looks like :
public static Optional<Policy> getPolicy(ReturnTermPolicy policyType,
String policyKey) {
Optional<Policy> policy = Optional.of(policyType.getPolicies().stream()
.filter(temp -> temp.getPolicyKey().equals(policyKey))
.findFirst().get());
return policy;
}
The calling code looks like that:
Optional<Policy> updatedPolicyOptional = getPolicy(updatedPolies,policykey); // <- exception is being generated here
if (updatedPolicyOptional.isPresent()) {
// business logic
}
else {
// business logic
}
Output :
Verify audit report for update made in TC_08
java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
There's no need to extract the result from the optional object just in order to wrap it with an optional again.
It's pointless and will trigger NoSuchElementException if result is not present. To solve the problem, remove the call of get() which both unsafe and redundant in this case:
public static Optional<Policy> getPolicy(ReturnTermPolicy policyType,
String policyKey) {
return policyType.getPolicies().stream()
.filter(temp -> temp.getPolicyKey().equals(policyKey))
.findFirst();
}
In order implement your conditional logic fluently you can make use of Optional.ifPresentOrElse() which expects a Consumer that would be executed if result is present and a Runnable that will be fired in case if optional is empty. Note, this method is accessible with Java 9.
getPolicy(updatedPolies,policykey).ifPresentOrElse(policy -> doSomething(policy),
() -> doSomethingElse());
With Java 8 you can use Optional.ifPresentOrElse() that expects consumer and can cave the if part of conditional logic. And for the case of empty optional, you will need a condition.
Optional<Policy> policy = getPolicy(updatedPolies,policykey);
policy.ifPresentOrElse(policy -> doSomething(policy));
if (!policy.isPresent()) doSomethingElse();
findFirst() already returns an Optional, trying to get() it leads to an error when it is empty. So your function should be:
public static Optional<Policy> getPolicy(ReturnTermPolicy policyType,
String policyKey) {
return = policyType.getPolicies().stream()
.filter(temp -> temp.getPolicyKey().equals(policyKey))
.findFirst();
}
And depending on your Java version (and your business logic) you can use things like:
Java 8.
if (updatedPolicyOptional.isPresent()) {
// business logic
}
else {
// business logic
}
or
T value = updatedPolicyOptional(mapToTFunctor).orElse(someTValue);
Java 9.
updatedPolicyOptional.ifPresentOrElse(someConsumer,someNoParamFunctor);
This question already has answers here:
Why does Java8 Stream generate nothing?
(3 answers)
Closed 4 years ago.
When I use count() function "inside test" message called three times as expected but when I remove count() function call test() function doesn't called. From count() function documentation I understand that it returns the count of elements in given stream.
public class Start {
public static int test(int input) {
System.out.println("inside processRecord");
return input;
}
public static void main(String[] args) throws InterruptedException {
List<Integer> data = Arrays.asList(1,2,3);
data.parallelStream().map(Start::test).count();
}
}
because count is a terminal operation, and streams are invoked/executed only when a terminal one is present; they are said to be lazy...
Just notice that in java-9 and above, your example would not print those statements from map either way, since all you care about is how many and map is sort of useless...
Intermediate operations (like map) return a stream and are being invoked by terminal operations that return non-stream values.
Running the following code sample ends with:
"Exception in thread "main" java.lang.StackOverflowError"
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class TestStream {
public static void main(String[] args) {
Stream<String> reducedStream = IntStream.range(0, 15000)
.mapToObj(Abc::new)
.reduce(
Stream.of("Test")
, (str , abc) -> abc.process(str)
, (a , b) -> {throw new IllegalStateException();}
);
System.out.println(reducedStream.findFirst().get());
}
private static class Abc {
public Abc(int id) {
}
public Stream<String> process(Stream<String> batch) {
return batch.map(this::doNothing);
}
private String doNothing(String test) {
return test;
}
}
}
What exactly is causing that issue? Which part of this code is recursive and why?
Your code isn't recursively looping. You can test with smaller numbers for the IntStream range (i.e. 1 or 100). In your case it's the actual stack size limit that causes the problem. As pointed out in some of the comments, its the way the streams are processes.
Each invocation on the stream creates a new wrapper stream around the original one. The 'findFirst()' method asks the previous stream for elements, which in turn asks the previous stream for elements. As the streams are no real containers but only pointers on the elements of the result.
The wrapper explosion happens in the reduce methods' accumulator '(str , abc) -> abc.process(str)'. The implementation of the method creates a new stream wrapper on the result (str) of the previous operation, feeding into the next iteration, creating a new wrapper on the result(result(str))). So the accumulation mechanism is one of a wrapper (recursion) and not of an appender (iteration). So creating a new stream of the actual (flattened) result and not on reference to the potential result would stop the explosion, i.e.
public Stream<String> process(Stream<String> batch) {
return Stream.of(batch.map(this::doNothing).collect(Collectors.joining()));
}
This method is just an example, as your original example doesn't make any sense because it does nothing, and neither does this example. Its just an illustration. It basically flattens the elements of the stream returned by the map method into a single string and creates a new stream on this concrete string and not on a stream itself, thats the difference to your original code.
You could tune the stacksize using the '-Xss' parameter which defines the size of the stack per thread. The default value depends on the platform, see also this question 'What is the maximum depth of the java call stack?' But take care when increasing, this setting applies to all threads.
This question already has answers here:
Why is this java Stream operated upon twice?
(4 answers)
Closed 6 years ago.
I would like to implement a pagination in stream api.
I used if statement to modify the stream, but I was surprise when I encountered
java.lang.IllegalStateException: stream has already been operated upon or closed
Here is my code
#Override
public List<Foo> search(String[] names, Integer offset, Integer size) {
final Stream<Foo> fooStream = findAllFoos().stream();
if(offset!=null) {
fooStream
.skip(offset)
.limit(size);
}
if(ArrayUtils.isNotEmpty(names)) {
fooStream.filter(foo -> ArrayUtils.contains(names, foo.getName()));
}
final List<Foo> foos = fooStream.collect(Collectors.toList()); //this lines throws the exception, according to stacktrace
return foos;
}
Here is my Foo.class
public class Foo {
private String name;
//..setters and getters
}
Here is sample call to that search method
fooService.search(fooNamesArray, 0, 1);
fooService.search(fooNamesArray, null, null);
fooStream.skip(offset)
does nothing by itself. It returns a new Stream; it does not modify fooStream.
Generally speaking you can only use a Stream for one operation, though that might be a transformation into another Stream.
What you could do, though it would still make your code awkward, would be to write fooStream = fooStream.skip(offset).limit(size).
You may want to add all your validation before hand and combine all stream operations in one go.
List<Foo> foos = fooStream.skip(offset)
.limit(size)
.filter(foo -> ArrayUtils.contains(names, foo.getName()))
.collect(Collectors.toList());
In other case, you can take the result of each stream operation into another stream and operate on them.
Stream<Foo> skippedFooStream = Collections.<Foo>emptyList().stream();
if(offset!=null) {
skippedFooStream = fooStream
.skip(offset)
.limit(size);
}
if(ArrayUtils.isNotEmpty(names)) {
// take this into another temp stream and proceed
skippedFooStream.filter(foo -> ArrayUtils.contains(names, foo.getName()));
}
This question already has answers here:
Limit a stream by a predicate
(19 answers)
Closed 8 years ago.
I have a set and a method:
private static Set<String> set = ...;
public static String method(){
final String returnVal[] = new String[1];
set.forEach((String str) -> {
returnVal[0] += str;
//if something: goto mark
});
//mark
return returnVal[0];
}
Can I terminate the forEach inside the lambda (with or without using exceptions)?
Should I use an anonymous class?
I could do this:
set.forEach((String str) -> {
if(someConditions()){
returnVal[0] += str;
}
});
but it wastes time.
implementation using stream.reduce
return set.parallelStream().reduce((output, next) -> {
return someConditions() ? next : output;
}).get(); //should avoid empty set before
I am looking for the fastest solution so exception and a 'real' for each loop are acceptable if they are fast enough.
I'm reluctant to answer this even though I'm not entirely sure what you're attempting to accomplish, but the simple answer is no, you can't terminate a forEach when it's halfway through processing elements.
The official Javadoc states that it is a terminal operation that applies against all elements in the stream.
Performs an action for each element of this stream.
This is a terminal operation.
If you want to gather the results into a single result, you want to use reduction instead.
Be sure to consider what it is a stream is doing. It is acting on all elements contained in it - and if it's filtered along the way, each step in the chain can be said to act on all elements in its stream, even if it's a subset of the original.
In case you were curious as to why simply putting a return wouldn't have any effect, here's the implementation of forEach.
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
The consumer is explicitly passed in, ad this is done independently of the actual iteration going on. I imagine you could throw an exception, but that would be tacky when more elegant solutions likely exist.