Wednesday, 10 September 2014

Streams In Java 8


What Is Stream ?
Stream is like a pipeline for data. Streams can be sequential or parallel. The parallel streams are designed to take advantage of the multicore hardware design. Streams allow you to write collections processing code at a higher level of abstraction.

The Stream API in Java8 uses some of the Java's most advanced features. To fully utilize and understand streams, requires a solid understanding of Generics and Lambda expressions, and also basic concepts of parallelism and working knowledge of the collection framework is needed. 

A Stream operates on a data source, such as an array or a collection. Streams allow a collection to send its values out one at a time, through pipeline like mechanism, where they can be processed in various ways with varying degree of parallelism.

In Java 8, Stream is a Generic Interface in java.util.stream package.

Creating A Stream :
Streams are of 2 types,
1. Sequential Streams
2. Parallel Streams

In Java 8, 2 default methods are included in Collection interface. i.e stream() - which returns a sequential stream, parallelStream() - which returns a parallel stream.

You can create a stream from an array by use of static stream() method in Arrays class, which was added in Java 8.

Creating A Sequential Stream : 

for example, if you have a ArrayList of String objects, then you can create a sequential stream in the following way.
 
package com.speakingcs.streams;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamDemo {

    public static void main(String[] args) {
 List strList = new ArrayList();
 strList.add("www");
 strList.add("speakingcs");
 strList.add("com");
 
 Stream< String > strStream = strList.stream();  
    }
 
}

Creating A Parallel Stream :

Creating parallel stream is simple and easy, there are 2 ways to create a parallel stream.

1. calling parallel() method on Stream object .
2. calling parallelStream() method on collection object.

If you have already created a sequential stream, then you can convert this stream into parallel stream by calling parallel() method on it. below is the code.
 
package com.speakingcs.streams;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamDemo {

    public static void main(String[] args) {
 List strList = new ArrayList();
 strList.add("www");
 strList.add("speakingcs");
 strList.add("com");
 
 Stream< String > strStream = strList.stream().parallel();  
    }
 
}

Instead of calling parallel() method on existing stream, you can directly create parallel stream on collection object as shown below.

Stream< String > parllelSteam = strList.parallelStream();
Creating A Stream From Array Object :

You can create a stream from an array by use of static stream() method available in Arrays class, or of() method of Stream. of() method is static method in Stream interface.

consider you have an array of String,
String[] strArray = {"www","speakingcs","com"};
now lets create a Stream object from this, using of() method
Stream< String > arrStream = Stream.of(strArray);
The another way to create is calling stream() method of Arrays class and passing array reference to it. here is the code.
Stream< String > arrStream = Arrays.stream(strArray);
Applying Operations On Streams :

Operations that can be applied on Streams are of two types.
1. Intermediate Operations.
2. Terminal Operations.

Intermediate Operations :

Intermediate operations produce another stream. So, these can be used to create a pipeline that performs a sequence of actions.

These operations don't execute immediately, once the user performs terminal operation, then the intermediate operations evaluated in the order specified and the terminal operation is executed on the new stream produced by intermediate operations.

This  mechanism is called as lazy behavior, and intermediate operations are treated as lazy. The use of lazy behavior enables the stream API to perform efficiently.

methods that perform intermediate operations are filter(), flatMap(), map(), limit() etc. Let's see a simple example, in this i am going to use filter() method. filter() takes Predicate as an argument and produces a stream of objects which satisfies the condition provided in the predicate.

Here is the example,
 Stream< String > strStream = strList.stream().filter(s1 -> s1.length() >= 3); 
in the above code, we are producing a stream of String objects, and filtering based upon a condition i.e strings whose length should be greater or equals to 3. Here filter() method performs intermediate operation. like this you can pipeline as many intermediate operations as you require.

Terminal Operations On Streams :

A terminal operation on stream, consumes the stream and produces a result. Once the stream is consumed, it cannot be reused. count(), forEach(), max(), min(), toArray() , these are some methods of this category. lets see an example.
 long count = strList.stream().filter(s1 -> s1.length() >= 3).count(); 
Calling terminal operation on the consumed Stream results run time error "java.lang.IllegalStateException: stream has already been operated upon or closed".

0 comments:

Post a Comment

Note: only a member of this blog may post a comment.