Home > Software Development > Java 8 New Features: Stream API

Java 8 New Features: Stream API

Java Collections APIs consists of well designed classes and interfaces for managing all sorts of data structures. With Java 8, there is a new enhancement called Stream API related to the Collection APIs (see What’s New in JDK 8). I spent some time to study the new feature last week as part of my effort to bring myself up to date with Java 8.

According to the API doc (there is a class called Streams. Don’t confuse them), a Stream is “A sequence of elements supporting sequential and parallel bulk operations. Streams support lazy transformative operations (transforming a stream to another stream) such as filter and map, and consuming operations, such as forEach, findFirst, and iterator. Once an operation has been performed on a stream, it is considered consumed and no longer usable for other operations.”

Time to learn how to "Google" and manage your VMware and clouds in a fast and secure


This Stream API has been integrated into the collection API so that you can get a new stream from a collection and act on the steam using lambda functions. By the way, one of the operation is map, the map in map-reduce for Hadoop. I will show a sample on Map Reduce in Java 8 using Steam API later.

Still too abstract? Let’s take a look at a small sample code while studying the new API. As it uses lambda, you may want to read this article before moving on.

package org.doublecloud.jave8demo.stream;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamDemo
  public static void main(String[] args)
    List<Integer> al = Arrays.asList( new Integer[] { -1, 1, 2, 3});
    // filter the stream for positive numbers and count them
    Stream s = al.stream();
    long positiveNum = s.filter(e -> ((Integer)e).intValue() > 0).count();
    System.out.println("Total count of postive numbers: " + positiveNum);
    // test whether all the element are positive
    s = al.parallelStream();
    boolean allMatch = s.allMatch(e -> ((Integer)e).intValue() > 0);
    System.out.println("Are all numbers positive? " + allMatch);
    // add all the element's values - using forEach
    s = al.parallelStream();
    final Sum sum = new Sum(); // lambda only takes final variable
    s.forEach(e -> { sum.sum += ((Integer)e).intValue(); } );
    System.out.println("Sum of the numbers: " + sum.sum);
    // add all the element's values - using sum()
    // stream has to be recreated after its use
    int total = al.parallelStream().mapToInt( e -> e.intValue() ).sum();
    System.out.println("Sum of the numbers (short version): " + total);
class Sum
  public int sum = 0;

If you run the code, it would print out the following on console:

Total count of postive numbers: 3
Are all numbers positive? false
Sum of the numbers: 5
Sum of the numbers (short version): 5

Two things to remember while using the Stream API. First, you can use either stream() or parallelStream() from a collection. The later one can leverage the power of multicore CPU, and therefore faster for a large number of elements. The parallel stream processing is still slower than the Fork/Join framework introduced in JDK 1.7, but usage wise, it’s a lot easier. In fact, other than calling parallelStream instead of stream, you don’t need to do anything more.

Second, a stream object cannot be re-used, meaning you have to create a new stream for each new operation. That is why you have seen steam() and parallelStream() methods are called multiple times. It’s not because I didn’t want to re-use, but no choice. :)