I am testing out the new Stream
API in java-8 and want to check the outcome of 10000 random coinflips. So far I have:
public static void main(String[] args) {
Random r = new Random();
IntStream randomStream = r.ints(10000,0, 2);
System.out.println("Heads: " + randomStream.filter(x -> x==1).count());
System.out.println("Tails: " + randomStream.filter(x -> x==0).count());
}
but this throws the exception:
java.lang.IllegalStateException: stream has already been operated upon or closed
I understand why this is happenning but how can i print the count for heads and tails if I can only use the stream once?
Stream. concat() method creates a concatenated stream in which the elements are all the elements of the first stream followed by all the elements of the second stream. The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel. The calls to Stream.
An output stream object is a destination for bytes. The three most important output stream classes are ostream , ofstream , and ostringstream .
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. A stream implementation may throw IllegalStateException if it detects that the stream is being reused. So the answer is no, streams are not meant to be reused.
3.1. Merging Streams. Since it is an instance method, we can easily chain it and append multiple streams. Note that we could also create a List out of the stream by using toList() if we type the resultingStream variable to the StreamEx type.
This first solution is relying on the fact that counting the number of heads and tails of 10 000 coinflips follows a binomial law.
For this particular use case, you can use the summaryStatistics
method.
Random r = new Random();
IntStream randomStream = r.ints(10000,0, 2);
IntSummaryStatistics stats = randomStream.summaryStatistics();
System.out.println("Heads: "+ stats.getSum());
System.out.println("Tails: "+(stats.getCount()-stats.getSum()));
collect
operation to create a map which will map each possible result with its number of occurences in the stream.
Map<Integer, Integer> map = randomStream
.collect(HashMap::new,
(m, key) -> m.merge(key, 1, Integer::sum),
Map::putAll);
System.out.println(map); //{0=4976, 1=5024}
The advantage of the last solution is that this works for any bounds you give for the random integers you want to generate.
Example:
IntStream randomStream = r.ints(10000,0, 5);
....
map => {0=1991, 1=1961, 2=2048, 3=1985, 4=2015}
While all other answers are correct, they are formulated a bit cumbersome.
Map<Integer, Long>
, maps the flipped coin to a count.
Map<Integer, Long> coinCount = new Random().ints(10000, 0, 2)
.boxed()
.collect(Collectors.groupingBy(i -> i, Collectors.counting()));
This will first create the IntStream
, then box them to an Stream<Integer>
, as you will be storing them in their boxed version anyhow in this example. And lastly collect them with a groupingBy
function on the identity i -> i
, which gives you a Map<Integer, List<Integer>>
, which is not what you want, hence you replace the List<Integer>
with the operation Collectors.counting()
on it, such that the List<Integer>
becomes a Long
, hence resulting in a Map<Integer, Long>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With