Creating a Stream and Finding Statistics about Numerical Streams


Creating a Stream

All java Collection<E>s have stream() and parallelStream() methods from which a Stream<E> can be constructed:

Collection<String> stringList = new ArrayList<>();
Stream<String> stringStream = stringList.parallelStream();

A Stream<E> can be created from an array using one of two methods:

String[] values = { "aaa", "bbbb", "ddd", "cccc" };
Stream<String> stringStream = Arrays.stream(values);
Stream<String> stringStreamAlternative = Stream.of(values);

The difference between Arrays.stream() and Stream.of() is that Stream.of() has a varargs parameter, so it can be used like:

Stream<Integer> integerStream = Stream.of(1, 2, 3);

There are also primitive Streams that you can use. For example:

IntStream intStream = IntStream.of(1, 2, 3);
DoubleStream doubleStream = DoubleStream.of(1.0, 2.0, 3.0);

These primitive streams can also be constructed using the Arrays.stream() method:

IntStream intStream = Arrays.stream(new int[]{ 1, 2, 3 });

It is possible to create a Stream from an array with a specified range.

int[] values= new int[]{1, 2, 3, 4, 5};
IntStream intStram = Arrays.stream(values, 1, 3);

Note that any primitive stream can be converted to boxed type stream using the boxed method :

Stream<Integer> integerStream = intStream.boxed();

This can be useful in some case if you want to collect the data since primitive stream does not have any collect method that takes a Collector as argument.

Reusing intermediate operations of a stream chain

Stream is closed when ever terminal operation is called. Reusing the stream of intermediate operations, when only terminal operation is only varying. we could create a stream supplier to construct a new stream with all intermediate operations already set up.

Supplier<Stream<String>> streamSupplier = () -> Stream.of("apple", "banana","orange", "grapes", "melon","blueberry","blackberry")
.map(String::toUpperCase).sorted();
 
streamSupplier.get().filter(s -> s.startsWith("A")).forEach(System.out::println);
 
// APPLE
 
 streamSupplier.get().filter(s -> s.startsWith("B")).forEach(System.out::println);
 
// BANANA
// BLACKBERRY
// BLUEBERRY
 
int[] arrays can be converted to List<Integer> using streams
 
int[] ints = {1,2,3};
List<Integer> list = IntStream.of(ints).boxed().collect(Collectors.toList());

Finding Statistics about Numerical Streams

Java 8 provides classes called IntSummaryStatistics, DoubleSummaryStatistics and LongSummaryStatistics which give a state object for collecting statistics such as count, min, max, sum, and average.

Version ≥ Java SE 8
List<Integer> naturalNumbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
IntSummaryStatistics stats = naturalNumbers.stream()
					.mapToInt((x) -> x)
					.summaryStatistics();
System.out.println(stats);

Which will result in:

Version ≥ Java SE 8
IntSummaryStatistics{count=10, sum=55, min=1, max=10, average=5.500000}

Converting an iterator to a stream

Use Spliterators.spliterator() or Spliterators.spliteratorUnknownSize() to convert an iterator to a stream:

Iterator<String> iterator = Arrays.asList("A", "B", "C").iterator(); 
Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iterator, 0);
Stream<String> stream = StreamSupport.stream(spliterator, false);

Using IntStream to iterate over indexes

Streams of elements usually do not allow access to the index value of the current item. To iterate over an array or ArrayList while having access to indexes, use IntStream.range(start, endExclusive).

String[] names = { "Jon", "Darin", "Bauke", "Hans", "Marc" };
 
IntStream.range(0, names.length)
	.mapToObj(i -> String.format("#%d %s", i + 1, names[i]))
	.forEach(System.out::println);

The range(start, endExclusive) method returns another ÌntStream and the mapToObj(mapper) returns a stream of String.

Output:

#1 Jon
#2 Darin
#3 Bauke
#4 Hans
#5 Marc

This is very similar to using a normal for loop with a counter, but with the benefit of pipelining and parallelization:

for (int i = 0; i < names.length; i++) {
      String newName = String.format("#%d %s", i + 1, names[i]);
      System.out.println(newName);
}

Basic Programs