Reputation: 215
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?
Upvotes: 2
Views: 1590
Reputation: 692121
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.
Upvotes: 8
Reputation: 198471
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.
Upvotes: 3