Srikanth Technologies

Streams in Java8

One of the new features of Java8 is Streams. The other major additions are Lambda Expressions and New Date and Time API.

Before you work with streams, you need to understand how lambda expressions work in Java8. Please read my blog on Lambda Expressions to know how to use Lambda expressions before proceeding with this blog.

A stream is a sequence of elements supporting sequential and parallel aggregate operations.

The following are important points about Streams.

Stream Interface

Stream interface in java.util.stream package provides the following methods.

Creating a stream

We can create a stream using one of the following ways:

Using Stream.of() method

// Create a stream from a set of discrete values
Stream<Integer> s1 = Stream.of(31,1,23,224,23,22)
Remember, starting from Java8 an interface can have static methods. In the above code we are using a static method of() of Stream interface.

Creating a stream from an array

// Create a stream from an array 
String names[] = {"Rod Jonson","Craig McClanahan","Gavin King"};
Stream<String> s =  Stream.of(names);        // using Stream.of() 

Using Arrays.stream() method

// Create a stream from an array 
String names[] = {"Rod Johnson","Craig McClanahan","Gavin King"};
Stream<String> s =  Arrays.stream(names);        

Getting a stream from a collection

ArrayList<String> names = new ArrayList<>();
names.add("Rod Johnson");
names.add("Craig McClanahan");
Stream<String> s = names.stream();

Getting a Stream from a File

Path  p = Paths.get("c:\\java\\names.txt");
Stream<String> s = Files.lines(p);
Apart from lines() method in Files class, BufferedReader class also provides lines() method that returns a Stream.

Using Stream Methods

The following examples show how to use methods in Stream class to filter, print, limit and sort.
Stream<Integer> s = Stream.of(31,1,5,224,23,4);
s = s.filter(n -> n > 10);
s.forEach(System.out::println);
The result of one intermediate method can be passed to another method as follows :
Stream.of(31,1,5,224,23,4)
         .filter(n -> n > 10)
         .forEach(System.out::println);
The following code is used to sort lines of file and print them.
Path  p = Paths.get("c:\\java\\names.txt");
Files.lines(p).sorted().forEach( System.out::println);
In the above code, method Files.lines() returns a Stream of Strings, which is sorted by sorted() method. The result of sorted() method is passed to terminal operation forEach(), which prints each line using System.out.println() using method reference syntax.

Mapping

At times it is required to convert objects of a Stream to another type. To enable conversion from one type to another we can use any of the map methods provided by Stream.

The following code illustrates how to use mapToInt() to convert each object in the stream to int and then use those integers as source for sum() method.

Path  p = Paths.get("c:\\java\\names.txt");
int sum = Files.lines(p).mapToInt( s -> s.length()).sum();
System.out.println(sum);
The following code maps Integer to MyTime object using map() method of Stream. Source stream is a collection of integers and target stream is a collection of MyTime objects.
ArrayList<Integer> hours = new ArrayList<>();
hours.add(10);
hours.add(15);
hours.add(20);
           
Stream<MyTime> times = hours.stream().map( t ->  new MyTime(t,0,0));
times.forEach( System.out::println);

Creating Collection from Stream

It is possible to create a collection from a Stream using collect() method of Stream and one of the methods provided in Collectors class.

The following code shows how to convert a Stream of String objects to a List of String objects using collect() method using Collectors.toList() method.

Path  p = Paths.get("c:\\java\\names.txt");
List<String> lines = Files.lines(p).filter( l -> l.length() > 15).collect( Collectors.toList());
for(String line : lines) {
     System.out.println(line);
}

Parallel Streams

Operations on streams can be done either in serial or parallel. When a parallel stream is obtained using parallelStream() method, Java runtime divides stream into multiple substreams and performs the operation on those substreams in parallel and then combines the results.

The following code obtains a parallel stream from a collection, filters data in parallel and prints it.

Path  p = Paths.get("c:\\java\\names.txt");
List<String> lines = Files.readAllLines(p); 
// print lines that are more than 12 characters 
lines.parallelStream().filter( line -> line.length() > 12 )
     .forEach(System.out::println);