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 aConsumer
. 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 thanflatMap()
. - 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.