Java 8 changed the way we usually code in Java by introducing some Functional Programming concepts. It brings features like lambda expressions and Streams, which give birth to new patterns that result in clean code in Java.In this blog we would talk about one of the features of Java 8 which is Streams. The java package java.util.stream contains classes to support functional-style operations on streams i.e. map, filter etc. Streams is not a data structure that stores something instead of it a way to flow data from source to destination with some intermediate operation in between. Let’s take an example first so that we can grasp concepts fast.

Let’s say, we have a collection of books Collection<Book> where Book class has two attributes writer and price and we want to obtain the sum of price’s where the writer is “Deepak kumar”. In order to obtain the result, we need to do some like –
int totalPrice = collection.stream()
.filter(b -> b.getWriter() == "Deepak kumar")
.map(b -> b.getPrice())
.sum();
The stream is a series of operations that can be Intermediate or terminal operation.
- The Intermediate operations return a new stream as result and we can call multiple intermediate operations one after the other. The Intermediate operations are executed before terminal operation. These types of operation are always lazy in nature means they will not be executed until the result of a processing is needed.
- The Terminal operation allows us to produce a final result from the remaining data. After applying this operation on the stream means that the stream has consumed. Computation on the stream pipeline is performed when the terminal operation is initiated.
Properties of Lambda
- It’s functional in nature means if we apply streams on some data, results get some result, it doesn’t mean it will modify the source, rather it will create a new stream from the existing stream.
- Intermediate operations are always lazy.
- During the life of the stream, the element of the stream is only visited only once.
Stream creation
Let’s create a stream from Array of book –
private static Book[] arrayOfBook = {
new Book("Ravi sharma", 100.0),
new Book("Deepak kumar", 240.0),
new Book("Amit Tyagi", 343.0),
new Book("Chirag Gupta", 143.0)
};
Stream.of(arrayOfBook);
We can also use the stream() method directly to convert into streams from the list.
private static List<Book> bookList = Arrays.asList(arrayOfBook);
empList.stream();
Stream operations
- filter : It produces a new stream that contains the element which passes the predicate. i.e:
Integer[] bookPrice = { 100, 200, 300, 44 };
List<Integer> totalPrice = Stream.of(bookPrice)
.filter(e -> e >= 200)
.collect(Collectors.toList());
Result – { 200, 300 }
- map: It produces a new stream after applying a function to each element of the original stream.
List number = Arrays.asList(2,3,4,5)
.stream()
.map(s->s+s)
.collect(Collectors.toList());
Result: { 4, 6, 8, 10 }
- forEach: It is the simplest operation and looks the same as map but it’s a terminal operation, which means that after applying this operation we cannot use any other operations.
- flatMap : It’s a combination of flat and map functions.
List<List<Integer>> listOfList = Arrays.asList(
Arrays.asList(1,2,3),
Arrays.asList(4,2),
Arrays.asList(1,3));
List<Integer> list = listOfList.stream()
.flatMap(list -> list.stream())
.collect(Collectors.toList());
Result : { 1, 2, 3, 4, 2, 1, 3 }
- collect : The collect function is a terminal operation and convert the stream into some other collection or entity. i.e In the example we will convert stream to list.
List<Integer> IntSet = Stream.of(1,2,3,4,5)
.map(x -> x+1)
.collect(Collectors.toList());
Result : List(2, 3, 4, 5, 6 )