Hurry! Try our new Interactive Courses for FREE. 🥳   🚀

Java 8 Stream API

Java Stream is a new concept added into Java 8 version that allows us to perform functional-style operations on streams of elements, such as map-reduce transformations on collections.

Java added a new package java.util.stream that consists of several classes, interfaces to perform the stream-based operations.

A Java Stream is a component that is capable to perform internal operations of its elements. For example, it can iterate its elements itself.

Stream operations are divided into intermediate and terminal operations. A stream source can be a Collection, an array, a generator function, or an I/O channel.

The intermediate operations are lazy operations and return a new stream. For example, executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream.

The terminal operations terminate the stream source pipeline after performing the operations. For example, Stream.forEach or IntStream.sum, may traverse the stream to produce a result.

Features Of Stream

Functional in nature

A stream is functional in nature that allows us to perform functional-style operations. An operation on a stream produces a result but does not modify its source. For example, filtering a Stream obtained from a collection produces a new Stream without the filtered elements, rather than removing elements from the source collection.

Laziness-seeking

Stream uses lazy loading to improve performance. We can use lazy loading in Many stream operations, such as filtering, mapping, or duplicate removal, etc. Stream Intermediate operations are always lazy.

No storage

A stream is not a data structure that stores elements, but it conveys elements from a source such as a collection, an array, or a generator function, through a pipeline of computational operations.

Possibly unbounded

While Java collections have a finite size, streams need not. Short-circuiting operations such as limit(n) or findFirst() can allow computations on infinite streams to complete in finite time.

Consumable

The elements of a stream are only visited once during the life of a stream. Reusing the stream reference again does not work. We need to create a new stream to revisit the same elements of the source.

How to Create a Stream?

In Collection, We can create stream via the stream() and parallelStream() methods and from an array via Arrays.stream(Object[]) method. We will see the practical examples of creating a stream, here.

Interfaces of java.util.stream

The following are the interfaces of java.util.stream package. We can use these to get stream in various programming scenarios.

Interface

Description

BaseStream<T,S extends BaseStream<T,S>>

It is a base interface for streams, which are sequences of elements supporting sequential and parallel aggregate operations.

Collector<T,A,R>

A mutable reduction operation that accumulates input elements into a mutable result container, optionally transforming the accumulated result into a final representation after all input elements have been processed.

DoubleStream

A sequence of primitive double-valued elements supporting sequential and parallel aggregate operations.

DoubleStream.Builder

A mutable builder for a DoubleStream.

IntStream

A sequence of primitive int-valued elements supporting sequential and parallel aggregate operations.

IntStream.Builder

A mutable builder for an IntStream.

LongStream

A sequence of primitive long-valued elements supporting sequential and parallel aggregate operations.

LongStream.Builder

A mutable builder for a LongStream.

Stream<T>

A sequence of elements supporting sequential and parallel aggregate operations.

Stream.Builder<T>

A mutable builder for a Stream.

Classes of java.util.stream

The following are the classes of java.util.stream package. we can use these classes to collect the intermediate data and manipulate the stream.

Class Description

Collectors

Implementations of Collector that implement various useful reduction operations, such as accumulating elements into collections, summarizing elements according to various criteria, etc.

StreamSupport

Low-level utility methods for creating and manipulating streams.

Time for an Example:

Let's take an example to create a stream from a list. Here, we are getting converting all the list elements into lowercase and iterating using the forEach() method.

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class STDemo {
	public static void main(String[] args){
		
		List<String> fruits = new ArrayList<String>();

		fruits.add("APPLE");
		fruits.add("BANANA");
		fruits.add("CHERRY");
		    
		Stream<String> stream = fruits.stream();
		    
		Stream<String> stringStream =
		    stream.map((value) -> { return value.toLowerCase(); });
        stringStream.forEach(System.out::println);
	}
}


apple
banana
cherry

Example: Filter List Elements

We can use the stream to filter Collection elements. Here, we are using the filter() method and collecting the result as a list. The filter() method takes a lambda expression as an argument.

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class STDemo {
	public static void main(String[] args){
		
		List<Integer> numbers = new ArrayList<Integer>();  
        numbers.add(100);
        numbers.add(110);
        numbers.add(120);
        numbers.add(150);
        
        List<Integer> newlist =numbers.stream()  
                                      .filter(n->n>110)
                                      .collect(Collectors.toList());
        System.out.println(newlist);  
	}
}


[120, 150]

Example: Iterating Elements

Traversing Collection elements is pretty easy in stream. we just need to call the forEach() method and get all the elements traversed. See, we passed a method reference in the forEach() method to print the stream result.

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class STDemo {
	public static void main(String[] args){
		
		List<Integer> numbers = new ArrayList<Integer>();  
        numbers.add(100);
        numbers.add(110);
        numbers.add(120);
        numbers.add(150);
        Stream<Integer> stream = numbers.stream();
        stream.forEach(System.out::println); 
	}
}


100
110
120
150

Example: Min and Max

If we want to get min or max value of a Collection then by using the stream, we can do it easily. Here, we are using min() and max() methods to get the result from the stream.

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class STDemo {
	public static void main(String[] args){
		
		List<Integer> numbers = new ArrayList<Integer>();  
        numbers.add(100);
        numbers.add(110);
        numbers.add(120);
        numbers.add(150);
        Stream<Integer> stream = numbers.stream();
        int max_val = stream.max((x,y)->x>y?1:-1).get();
        System.out.println("Max Value : "+max_val);
        int min_val = numbers.stream().min((x,y)->x<y?-1:1).get();
        System.out.println("Min Value : "+min_val);
        
	}
}


Max Value : 150
Min Value : 100

Example: Sum Using reduce() Method

The reduce() is a method that reduces elements in the stream to a single element and can be used, to get sum of all the elements. See the below example.

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class STDemo {
	public static void main(String[] args){
		
		List<Integer> numbers = new ArrayList<Integer>();  
        numbers.add(100);
        numbers.add(110);
        numbers.add(120);
        numbers.add(150);
        System.out.println(numbers);
        Stream<Integer> stream = numbers.stream();
        Optional<Integer> sum = stream.reduce(Integer::sum); 
        System.out.println("Sum = "+sum.get());
        
	}
}


[100, 110, 120, 150]
Sum = 480

Example: Count Stream Elements

There is a count() method that can be used to know the number of elements in the stream. See the example below.

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class STDemo {
	public static void main(String[] args){
		
		List<Integer> numbers = new ArrayList<Integer>();  
        numbers.add(100);
        numbers.add(110);
        numbers.add(120);
        numbers.add(150);
        System.out.println(numbers);
        Stream<Integer> stream = numbers.stream();
        long count = stream.count(); 
        System.out.println("Total Values = "+count);
        
	}
}


[100, 110, 120, 150]
Total Values = 4

Example: List to Set Conversion

Sometimes we need to convert the stream from one type to another then we have predefined methods in the Collectors class. For example, to convert a list to set we can use toSet() method.

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class STDemo {
	public static void main(String[] args){
		
		List<Integer> numbers = new ArrayList<Integer>();  
        numbers.add(100);
        numbers.add(110);
        numbers.add(120);
        numbers.add(150);
        numbers.add(110);
        System.out.println(numbers);
        Stream<Integer> stream = numbers.stream();
        Set<Integer> set = stream.collect(Collectors.toSet());
        System.out.println("Set Values = "+set);
        
	}
}


[100, 110, 120, 150, 110]
Set Values = [100, 150, 120, 110]

Example: List to Array Conversion

This is another example of conversion from one type to another. Here, we are converting a list into array using the toArray() method of the stream. It returns an array of Object.

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class STDemo {
	public static void main(String[] args){
		
		List<Integer> numbers = new ArrayList<Integer>();  
        numbers.add(100);
        numbers.add(110);
        numbers.add(120);
        numbers.add(150);
        numbers.add(110);
        System.out.println(numbers);
        Stream<Integer> stream = numbers.stream();
        Object[] intArray = stream.toArray();
        for(Object element:intArray) {
        	System.out.print(element+" ");
        }
	}
}


[100, 110, 120, 150, 110]
100 110 120 150 110