Java 8 Stream Tutorial for Beginners

This tutorial is designed for Java beginners to quickly learn Java 8 stream API with lots of examples.

1. Overview

Java provides a new additional package in Java 8 called java.util.stream. This package consists of classes, interfaces, and an enum to allows functional-style operations on the elements. You can use stream by importing java.util.stream package in your programs.

1.1 Java Stream features

  • Stream does not store elements. It simply conveys elements from a source such as a data structure, an array, or an I/O channel, through a pipeline of computational operations.
  • Stream is functional in nature. Operations performed on a stream 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.
  • Stream is lazy and evaluates code only when required.
  • The elements of a stream are only visited once during the life of a stream. Like an Iterator, a new stream must be generated to revisit the same elements of the source.
You can use Stream to filter, collect, print, and convert from one data structure to other, etc.

1.2 Creating Empty Stream

The empty() method should be used in case of the creation of an empty stream:
Stream<String> stream = Stream.empty();
stream.forEach(System.out::println);
It's often the case that the empty() method is used upon creation to avoid returning null for streams with no element:
public Stream<String> streamOf(List<String> list) {
    return list == null || list.isEmpty() ? Stream.empty() : list.stream();
}

1.3 Creating Stream from From Collections

A stream can be created of any type of Collection (Collection, List, Set):
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

public class StreamCreationExamples {
    public static void main(String[] args) throws IOException {

        Collection<String> collection = Arrays.asList("JAVA", "J2EE", "Spring", "Hibernate");
        Stream<String> stream2 = collection.stream();
        stream2.forEach(System.out::println);

        List<String> list = Arrays.asList("JAVA", "J2EE", "Spring", "Hibernate");
        Stream<String> stream3 = list.stream();
        stream3.forEach(System.out::println);

        Set<String> set = new HashSet<>(list);
        Stream<String> stream4 = set.stream();
        stream4.forEach(System.out::println);
    }
}
Output:
JAVA
J2EE
Spring
Hibernate
JAVA
J2EE
Spring
Hibernate
JAVA
Hibernate
J2EE
Spring

1.4 Creating Stream object from Arrays

Array can be a source of a Stream or Array can be created from the existing array or of a part of an array:
import java.io.IOException;
import java.util.Arrays;
import java.util.stream.Stream;

public class StreamCreationExamples {
    public static void main(String[] args) throws IOException {

        // Array can also be a source of a Stream
        Stream<String> streamOfArray = Stream.of("a", "b", "c");
        streamOfArray.forEach(System.out::println);

        // creating from existing array or of a part of an array:
        String[] arr = new String[] { "a", "b", "c" };
        Stream<String> streamOfArrayFull = Arrays.stream(arr);
        streamOfArrayFull.forEach(System.out::println);

        Stream<String> streamOfArrayPart = Arrays.stream(arr, 1, 3);
        streamOfArrayPart.forEach(System.out::println);
    }
}
Output:
a
b
c
a
b
c
b
c

2. Java 8 Stream API Examples

Let's explore Stream API with examples.

Java Stream Example 1: Filtering Collection without using Stream

In the following example, we are filtering data without using a stream. This approach we are used before the stream package was released. 
First create a Product class, which is used in the below examples :
public class Product {
    private int id;
    private String name;
    private float price;
    public Product(int id, String name, float price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
}
Let's first discuss without using Stream API's examples then we will create the same examples using Stream API's.
import java.util.ArrayList;
import java.util.List;

/**
 * Filtering Collection without using Stream
 * @author Ramesh Fadatare
 *
 */
public class JavaWithoutStreamExample {
    private static List < Product > productsList = new ArrayList < Product > ();

    public static void main(String[] args) {

        // Adding Products
        productsList.add(new Product(1, "HP Laptop", 25000f));
        productsList.add(new Product(2, "Dell Laptop", 30000f));
        productsList.add(new Product(3, "Lenevo Laptop", 28000f));
        productsList.add(new Product(4, "Sony Laptop", 28000f));
        productsList.add(new Product(5, "Apple Laptop", 90000f));
        // Without Java 8 Stream API'S
        withoutStreamAPI();
    }

    private static void withoutStreamAPI() {
        // without Stream API's
        List < Float > productPriceList = new ArrayList < Float > ();
        // filtering data of list
        for (Product product: productsList) {
            if (product.getPrice() > 25000) {
                // adding price to a productPriceList
                productPriceList.add(product.getPrice());
            }
        }

        // displaying data
        for (Float price: productPriceList) {
            System.out.println(price);
        }
    }
}
Output:
30000.0
28000.0
28000.0
90000.0

Java Stream Example 2: filtering Collection by using Stream

Here, we are filtering data by using stream. You can see that code is optimized and maintained. The stream provides fast execution.
import java.util.ArrayList;

import java.util.List;
import java.util.stream.Collectors;

/**
 * filtering Collection by using Stream
 * @author Ramesh Fadatare
 *
 */
public class JavaStreamExample {
    private static List < Product > productsList = new ArrayList < Product > ();

    public static void main(String[] args) {

        // Adding Products
        productsList.add(new Product(1, "HP Laptop", 25000f));
        productsList.add(new Product(2, "Dell Laptop", 30000f));
        productsList.add(new Product(3, "Lenevo Laptop", 28000f));
        productsList.add(new Product(4, "Sony Laptop", 28000f));
        productsList.add(new Product(5, "Apple Laptop", 90000f));
        // With Java 8 Stream API'S
        withStreamAPI();
    }

    private static void withStreamAPI() {
        // filtering data of list
        List < Float > productPriceList = productsList.stream().filter((product) - > product.getPrice() > 25000)
            .map((product) - > product.getPrice()).collect(Collectors.toList());
        // displaying data
        productPriceList.forEach((price) - > System.out.println(price));
    }
}
Output:
30000.0
28000.0
28000.0
90000.0

Java Stream Example 3: Filtering and Iterating Collection

In the following example, we are using the filter() method for filtering and forEach() for iterating a stream:
package com.java.tutorials.java8;

import java.util.ArrayList;
import java.util.List;

/**
 * filtering Collection by using Stream
 * 
 * @author Ramesh Fadatare
 *
 */
public class FilteringAndIteratingCollection {
    public static void main(String[] args) {
        List < Product > productsList = new ArrayList < Product > ();
        // Adding Products
        productsList.add(new Product(1, "HP Laptop", 25000 f));
        productsList.add(new Product(2, "Dell Laptop", 30000 f));
        productsList.add(new Product(3, "Lenevo Laptop", 28000 f));
        productsList.add(new Product(4, "Sony Laptop", 28000 f));
        productsList.add(new Product(5, "Apple Laptop", 90000 f));
        // This is more compact approach for filtering data
        productsList.stream().filter(product - > product.getPrice() == 30000)
            .forEach(product - > System.out.println(product.getPrice()));
    }
}
Output:
30000.0

Java Stream Example 4: Sum by using Collectors Methods

We can also use collectors to compute a sum of numeric values.

In the following example, we are using the Collectors class and it's specified methods to compute the sum of all the product prices.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Sum by using Collectors Methods
 * 
 * @author Ramesh Fadatare
 *
 */
public class SumByUsingCollectorsMethods {
    public static void main(String[] args) {
        List < Product > productsList = new ArrayList < Product > ();
        //Adding Products  
        productsList.add(new Product(1, "HP Laptop", 25000f));
        productsList.add(new Product(2, "Dell Laptop", 30000f));
        productsList.add(new Product(3, "Lenevo Laptop", 28000f));
        productsList.add(new Product(4, "Sony Laptop", 28000f));
        productsList.add(new Product(5, "Apple Laptop", 90000f));
        // Using Collectors's method to sum the prices.  
        double totalPrice3 = productsList.stream()
            .collect(Collectors.summingDouble(product - > product.getPrice()));
        System.out.println(totalPrice3);

    }
}
Output:
201000.0

Java Stream Example 5: Find Max and Min Product Price

The following example finds min and max product prices by using stream. It provides a convenient way to find values without using the imperative approach.
import java.util.ArrayList;
import java.util.List;

/**
 * Find Max and Min Product Price
 * 
 * @author Ramesh Fadatare
 *
 */
public class FindMaxAndMinMethods {
    public static void main(String[] args) {
        List < Product > productsList = new ArrayList < Product > ();
        // Adding Products
        productsList.add(new Product(1, "HP Laptop", 25000f));
        productsList.add(new Product(2, "Dell Laptop", 30000f));
        productsList.add(new Product(3, "Lenevo Laptop", 28000f));
        productsList.add(new Product(4, "Sony Laptop", 28000f));
        productsList.add(new Product(5, "Apple Laptop", 90000f));
        // max() method to get max Product price
        Product productA = productsList.stream()
            .max((product1, product2) - > product1.getPrice() > product2.getPrice() ? 1 : -1).get();

        System.out.println(productA.getPrice());
        // min() method to get min Product price
        Product productB = productsList.stream()
            .max((product1, product2) - > product1.getPrice() < product2.getPrice() ? 1 : -1).get();
        System.out.println(productB.getPrice());
    }
}
Output:
90000.0
25000.0

Java Stream Example 6: Convert List into Set

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Convert List into Set
 * 
 * @author Ramesh Fadatare
 *
 */
public class ConvertListToSet {
    public static void main(String[] args) {
        List < Product > productsList = new ArrayList < Product > ();

        // Adding Products
        productsList.add(new Product(1, "HP Laptop", 25000 f));
        productsList.add(new Product(2, "Dell Laptop", 30000 f));
        productsList.add(new Product(3, "Lenevo Laptop", 28000 f));
        productsList.add(new Product(4, "Sony Laptop", 28000 f));
        productsList.add(new Product(5, "Apple Laptop", 90000 f));

        // Converting product List into Set
        Set < Float > productPriceList = productsList.stream().filter(product - > product.getPrice() < 30000)
            .map(product - > product.getPrice()).collect(Collectors.toSet());
        System.out.println(productPriceList);
    }
}
Output:
[25000.0, 28000.0]

Java Stream Example 7: Convert List into Map

public class ConvertListToMap {
    public static void main(String[] args) {
        List < Product > productsList = new ArrayList < Product > ();

        // Adding Products
        productsList.add(new Product(1, "HP Laptop", 25000 f));
        productsList.add(new Product(2, "Dell Laptop", 30000 f));
        productsList.add(new Product(3, "Lenevo Laptop", 28000 f));
        productsList.add(new Product(4, "Sony Laptop", 28000 f));
        productsList.add(new Product(5, "Apple Laptop", 90000 f));

        // Converting Product List into a Map
        Map < Integer, String > productPriceMap = productsList.stream()
            .collect(Collectors.toMap(p - > p.getId(), p - > p.getName()));
        System.out.println(productPriceMap);
    }
}

Java Stream Example 8: Using Method References in Stream map() method

public class MethodReferenceInStream {
    public static void main(String[] args) {

        List < Product > productsList = new ArrayList < Product > ();

        // Adding Products
        productsList.add(new Product(1, "HP Laptop", 25000 f));
        productsList.add(new Product(2, "Dell Laptop", 30000 f));
        productsList.add(new Product(3, "Lenevo Laptop", 28000 f));
        productsList.add(new Product(4, "Sony Laptop", 28000 f));
        productsList.add(new Product(5, "Apple Laptop", 90000 f));

        List < Float > productPriceList = productsList.stream()
            .filter(p - > p.getPrice() > 30000) // filtering data 
            .map(Product::getPrice) // fetching price by referring getPrice method
            .collect(Collectors.toList()); // collecting as list
        System.out.println(productPriceList);
    }
}

Java 8 Stream APIs Example 9: Sort List of String objects in Ascending

This example demonstrates different ways to sort List of String objects in Ascending order using Java 8 Stream APIs:
import java.util.ArrayList;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class StreamListSorting {
    public static void main(String[] args) {

        List < String > fruits = new ArrayList < String > ();
        fruits.add("Banana");
        fruits.add("Apple");
        fruits.add("Mango");
        fruits.add("Orange");

        List < String > sortedList = fruits.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
        System.out.println(sortedList);

        List < String > sortedList1 = fruits.stream().sorted((o1, o2) - > o1.compareTo(o2)).collect(Collectors.toList());
        System.out.println(sortedList1);

        List < String > sortedList2 = fruits.stream().sorted().collect(Collectors.toList());
        System.out.println(sortedList2);
    }
}
Output:
[Apple, Banana, Mango, Orange]
[Apple, Banana, Mango, Orange]
[Apple, Banana, Mango, Orange]

Java 8 Stream API Example 10: Sort List of String objects in Descending order

This example demonstrates different ways to sort List of String objects in descending order using Java 8 Stream APIs:
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class StreamListSorting {
    public static void main(String[] args) {

        List < String > fruits = new ArrayList < String > ();
        fruits.add("Banana");
        fruits.add("Apple");
        fruits.add("Mango");
        fruits.add("Orange");

        // descending order
        List < String > sortedList3 = fruits.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        System.out.println(sortedList3);

        List < String > sortedList4 = fruits.stream().sorted((o1, o2) - > o2.compareTo(o1)).collect(Collectors.toList());
        System.out.println(sortedList4);
    }
}
Output:
[Orange, Mango, Banana, Apple]
[Orange, Mango, Banana, Apple]

Related Java 8 Tutorials

Comments