Java Streams - Java Stream API








Stream-related interfaces and classes are in the java.util.stream package.

AutoCloseable interface is from the java.lang package.

All stream interfaces inherit from the BaseStream interface, which inherits from the AutoCloseable interface.

AutoCloseable
 |
 +--BaseStream
     |
     +--IntStream
     |
     +--LongStream
     |
     +--DoubleStream
     |
     +--Stream<T>

If the streams use collections as their data source, and collections do not need to be closed.

If a stream is based on a closeable data source such as a file I/O channel, we can create the stream using a try-with-resources statement to get it closed automatically.





BaseStream

BaseStream interface defines all methods common to all types of streams.

  • Iterator<T> iterator()
    terminal operation
    returns an iterator for the stream.
  • sequential()
    intermediate operation
    returns a sequential stream. If the stream is already sequential, it returns itself. It converts a parallel stream into a sequential stream.
  • parallel()
    intermediate operation
    returns a parallel stream. If the stream is already parallel, it returns itself. It convert a parallel stream into a sequential stream.
  • boolean isParallel()
    returns true if the stream is parallel, false otherwise.
    Calling this method after invoking an terminal stream operation method may yield unpredictable results.
  • unordered()
    intermediate operation
    returns an unordered version of the stream. If the stream is already unordered, it returns itself.




Stream

Stream<T> interface represents a stream of the element type T.

A Stream<Student> represents a stream of Studentobjects.

The Stream<T> interface contains methods such as filter(), map(), reduce(), collect(), max(), min(), etc.

When working with primitive types we can use three specialized stream interfaces called IntStream, LongStream, and DoubleStream.

These interfaces provide methods to deal with primitive values.

For other primitive types such as float, short, byte, we can still use the three specialized stream interfaces.

In the following code we are going to use stream to calculate a sum of the squares of all odd integers in the list.

We will use the following steps to do the calculation.

Create a stream

The stream() method in the Collection interface returns a sequential stream. In this way the Collection acts as the data source.

The following code creates a List<Integer> and obtains a Stream<Integer> from the list:

List<Integer>  numbersList = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> numbersStream  = numbersList.stream();

Filter a stream

Stream<T> filter() uses a Predicate<T> to keep elements if the specified Predicate returns true for that element.

The following statement obtains a stream of only odd integers:

Stream<Integer> oddNumbersStream= numbersStream.filter(n ->n % 2 == 1);

Map a stream

Stream<T> map() uses a Function to map each element in the stream and create a new stream.

The following statement maps a stream to their squares:

Stream<Integer> aStream = stream.map(n -> n * n);

Reduce a stream

reduce(T identity, BinaryOperator<T> accumulator) reduces the stream to a single value.

It takes an initial value and an accumulator that is a BinaryOperator<T> as arguments.

reduce(T identity, BinaryOperator<T> accumulator) performs a reduction on the elements of this stream, using the provided initial value and an associative accumulation function, and returns the reduced value.

This is equivalent to:

T result = identity;
for (T element : this stream)
  result = accumulator.apply(result, element)
return result;

The following code sums all integers in the stream.

int sum = aStream.reduce(0, (n1, n2) -> n1 + n2);

The Integer.sum() method performs sum of two integers.

We can rewrite the code using a method reference.

int sum = aStream.reduce(0, Integer::sum);

Together

The following code links each step together.

import java.util.Arrays;
import java.util.List;
//from  w w  w  .ja va  2  s .c om
public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.stream()
        .filter(n -> n % 2  == 1)
        .map(n  -> n * n)
        .reduce(0, Integer::sum);

    System.out.println(sum);
  }
}

The code above generates the following result.

Ordered Streams vs. unordered Streams

A stream can be ordered or unordered.

An ordered stream keeps the order of its elements.

The Streams API can convert an ordered stream, which may represent an ordered data source such as a list or a sorted set, into an unordered stream.

We can also convert an unordered stream into an ordered stream by applying an sorting intermediate operation.

import java.util.Arrays;
import java.util.List;
/* ww  w . j  ava  2s  .  c o  m*/
public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(3,7,9,3,1,2,1, 2, 3, 4, 5);
    numbers.stream()
        .filter(n -> n % 2  == 1)
        .sorted()
        .forEach(System.out::println);
  }
}

The code above generates the following result.