2

i wanted to try out some of the functionality of lambdas and wanted to write filter an ArrayList and use the methods of IntStream to calculate the average and maximum of an ArrayList of numbers

My first thought was to just filter the ArrayList, save the stream and then use the methods to calculate:

ArrayList<Integer> arr = new ArrayList<>();
arr.add(5);
arr.add(7);
arr.add(11);

IntStream s = arr.stream().filter(i -> i < 10).mapToInt(i -> (int)i);
int maxBelowTen = s.max().getAsInt();
double avgBelowTen = s.average().getAsDouble();
System.out.println("Maximum below ten: " + maxBelowTen);
System.out.println("Average below ten: " + avgBelowTen);

However, this throws an java.lang.IllegalStateException: stream has already been operated upon or closed

With this information, i brought it to work of course, by opening two streams and filtering twice

int maxBelowTen = arr.stream().filter(i -> i < 10).mapToInt(i -> (int) i).max().getAsInt();
double avgBelowTen = arr.stream().filter(i -> i < 10).mapToInt(i -> (int) i).average().getAsDouble();

But my question now is about performance. Isn't that pretty slow, if i have to filter and map the stream twice. Why can't I operate more than once on a stream, i fail to understand why they implemented it this way. Wouldn't it be possible to leave a stream open after an operation, because every operator method returns a new stream or a single value.

What is the reason for this, or am I just using it wrong?

2 Answers 2

8

If you did it the good old way, by using a loop, you would compute the max element and the average using a single loop. So you just need to do the same thing here. And fortunately, the Stream API can do it for you :

IntStream s = arr.stream().mapToInt(i -> Integer::intValue).filter(i < 10);
IntSummaryStatistics stats = s.summaryStatistics();

double average = stats.getAverage();
int max = stats.getMax();

Reading the javadoc of IntSummaryStatistics should help you understand how you could implement such an operation by yourself.

Sign up to request clarification or add additional context in comments.

1 Comment

Wow, I wasn't aware of summaryStatistics(). How on earth did that end up being important enough, given all the other features that were stripped? :-)
3

If you want to "save" the result of intermediate stream operations, you can do that; you just have to do it explicitly: you'd have to do arr.stream().filter(i -> i < 10).mapToInt(i -> (int) i).toArray(), store that int[], and then do the operations on that.

Streams are not a data structure, they're a pending computation that hasn't been run yet, and might merge future operations together in nonstandard ways. If you want to store intermediate results in a proper data structure, you have to do it yourself.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.