Java 16 New Stream Methods – toList(), mapMulti(), ofNullable()

Java 16 introduced several new methods in the Stream API, enhancing the functionality and flexibility of streams in Java. These additions make it easier to work with streams by providing more options for processing, transforming, and collecting data. The new methods in Java 16 include Stream.toList(), Stream.mapMulti(), and Stream.ofNullable().

Key Points:

  • Stream.toList(): Provides a convenient way to collect elements from a stream into an immutable list.
  • Stream.mapMulti(): Offers a versatile way to transform each element of a stream into multiple elements.
  • Stream.ofNullable(): Creates a stream containing a single element if it is non-null, or an empty stream if it is null.

1. Stream.toList()

The toList() method collects elements from a stream into an immutable List. This method is similar to Collectors.toUnmodifiableList() but provides a more convenient and readable way to achieve the same result without using a collector.

Syntax

List<T> list = stream.toList();
  • stream: The stream of elements to be collected.
  • list: The resulting immutable list containing the stream’s elements.

Example: Using Stream.toList()

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

public class StreamToListExample {
    public static void main(String[] args) {
        Stream<String> namesStream = Stream.of("Ananya", "Rahul", "Meena");

        // Collect the stream into an immutable list
        List<String> namesList = namesStream.toList();

        // Print the list
        System.out.println("Names List: " + namesList);

        // Attempt to modify the list (throws UnsupportedOperationException)
        try {
            namesList.add("Vikas");
        } catch (UnsupportedOperationException e) {
            System.out.println("Cannot modify immutable list: " + e.getMessage());
        }
    }
}

Output:

Names List: [Ananya, Rahul, Meena]
Cannot modify immutable list: null

Explanation:

  • Immutable List: The toList() method collects the stream’s elements into an immutable list, preventing modifications.
  • Convenience: The method provides a straightforward and concise way to collect stream elements into a list.

2. Stream.mapMulti()

The mapMulti() method is a more flexible alternative to flatMap(). It allows you to transform each element of a stream into zero or more elements, similar to flatMap(), but with a more direct way of handling multiple mappings through a BiConsumer.

Syntax

<R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper)
  • mapper: A BiConsumer that accepts an element and a Consumer. It applies the transformation logic, allowing zero or more elements to be added to the output stream.

Example: Using Stream.mapMulti()

Let’s consider an example where we transform each string in a stream into multiple substrings.

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

public class MapMultiExample {
    public static void main(String[] args) {
        Stream<String> sentenceStream = Stream.of("Hello World", "Java Streams", "Pattern Matching");

        // Transform each string into individual words
        Stream<String> wordsStream = sentenceStream.mapMulti((sentence, downstream) -> {
            for (String word : sentence.split(" ")) {
                downstream.accept(word);
            }
        });

        // Collect the transformed stream into a list
        List<String> wordsList = wordsStream.toList();

        // Print the list of words
        System.out.println("Words List: " + wordsList);
    }
}

Output:

Words List: [Hello, World, Java, Streams, Pattern, Matching]

Explanation:

  • Flexible Transformation: The mapMulti() method allows each element to produce zero or more elements in the resulting stream, offering greater flexibility than flatMap().
  • Direct Handling: The BiConsumer provides a direct way to handle multiple mappings within the transformation logic.

3. Stream.ofNullable()

The ofNullable() method creates a stream containing a single element if the element is non-null, or an empty stream if the element is null. This method is useful for safely handling potentially null elements without explicitly checking for null values.

Syntax

Stream<T> ofNullable(T element)
  • element: The element to be wrapped in a stream.
  • Returns: A stream containing the element if non-null, or an empty stream if null.

Example: Using Stream.ofNullable()

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

public class OfNullableExample {
    public static void main(String[] args) {
        String name = "Vijay";
        String nullName = null;

        // Create streams using ofNullable
        Stream<String> nonNullStream = Stream.ofNullable(name);
        Stream<String> nullStream = Stream.ofNullable(nullName);

        // Collect the streams into lists
        List<String> nonNullList = nonNullStream.toList();
        List<String> nullList = nullStream.toList();

        // Print the results
        System.out.println("Non-Null List: " + nonNullList);
        System.out.println("Null List: " + nullList);
    }
}

Output:

Non-Null List: [Vijay]
Null List: []

Explanation:

  • Null Handling: The ofNullable() method safely handles potentially null elements, allowing you to create streams without explicit null checks.
  • Stream Creation: It creates a stream with a single element or an empty stream based on the element’s nullability.

Use Cases for New Stream Methods

Use Case 1: Creating Immutable Lists

The toList() method simplifies the creation of immutable lists from streams, making it easy to maintain immutable collections.

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

public class ImmutableListExample {
    public static void main(String[] args) {
        List<Integer> numbers = Stream.of(1, 2, 3, 4, 5).toList();

        System.out.println("Immutable Numbers List: " + numbers);
    }
}

Output:

Immutable Numbers List: [1, 2, 3, 4, 5]

Use Case 2: Flattening and Transforming Streams

The mapMulti() method provides a flexible way to transform and flatten streams, enabling complex transformations with ease.

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

public class FlatteningExample {
    public static void main(String[] args) {
        Stream<List<String>> nestedListStream = Stream.of(List.of("a", "b"), List.of("c", "d"));

        // Flatten the nested lists into a single stream
        Stream<String> flatStream = nestedListStream.mapMulti((list, downstream) -> {
            for (String item : list) {
                downstream.accept(item);
            }
        });

        List<String> flatList = flatStream.toList();
        System.out.println("Flattened List: " + flatList);
    }
}

Output:

Flattened List: [a, b, c, d]

Use Case 3: Handling Null Values

The ofNullable() method simplifies handling null values by safely creating streams with potentially null elements.

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

public class NullHandlingExample {
    public static void main(String[] args) {
        Integer number = null;

        // Use ofNullable to safely handle null values
        List<Integer> numberList = Stream.ofNullable(number).toList();

        System.out.println("Number List: " + numberList);
    }
}

Output:

Number List: []

Conclusion

Java 16 introduced new stream methods that enhance the flexibility and usability of the Stream API. These methods provide more convenient ways to collect, transform, and handle streams, making it easier to work with complex data processing tasks in Java.

Summary:

  • Stream.toList(): Collects elements into an immutable list.
  • Stream.mapMulti(): Transforms elements into multiple elements using a flexible mapping approach.
  • Stream.ofNullable(): Safely creates streams with potentially null elements.

By leveraging these new methods, developers can write more concise and efficient code when working with streams in Java applications.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top