Collecting data from Optional using Collectors

1. Overview

In this article we will convert Optional<T> to Collection. Let us first understand the use-case here. Optional can contain either 0 or 1 element in it. If Optional was a Collection it would have been an empty collection or singleton collection.

This article is part of ongoing series of Optional. Read about it more here.

We can create our own methods that returns a Collection. If value is present in Optional we would return singleton Collection else return empty Collection.

2. toList(Optional<T> opt)

If the value is present in Optional then we create a SingletonList with that value else we return emptyList.

List<String> toList(Optional<String> optString) {
	return optString
			.map(Collections::singletonList)
			.orElseGet(Collections::emptyList);
}
 
List<String> list = toList(Optional.of("abc"))

3. toMap(Optional<T> opt)

If the value is present in Optional then we create a SingletonMap with that value else we return emptyMap. The returned Map will have same key-value pair.

Map<String, String> toMap(Optional<String> optString) {
	return optString
			.map(value -> Collections.singletonMap(value, value))
			.orElseGet(Collections::emptyMap);
}
 
Map<String, String> map = toMap(Optional.of("abc"))

4. collect(Optional<T> opt, Collector<T, A, R> collector)

In order to leverage existing interface for Collecting data into container we can use Collector interface.

It is a great way to collect data as we can pass a behavior of our container instead of writing toList, toSet, toMap methods of our own.

1. Get the mutable result container from the Supplier. 

A accumulator = collector.supplier().get();

2. If value is present in Optional then just insert that value in mutable result container.

optional
	.ifPresent(value -> collector.accumulator()
	.accept(a, value));

3. Convert intermediate result container into result container and return it.

collector.finisher().apply(a)
<A, T, R> R collect(
				Optional<T> optional, 
				Collector<T, A, R> collector) {
	A a = collector.supplier().get();
	optional.ifPresent(value -> collector.accumulator()
			.accept(a, value));
	return collector.finisher().apply(a);
}

Collect method with collector can be used in several different ways.

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.*;
 
// To List
collect(optional, toList())
 
// To unmodifiableList
collect(optional, collectingAndThen(
                      toList(), 
                      Collections::unmodifiableList))
 
// To Set
collect(optional, toSet())
 
// To unmodifiableSet
collect(optional, collectingAndThen(
                      toSet(), 
                      Collections::unmodifiableSet))
 
// To Map
collect(optional, toMap(identity(), identity()))
 
// To unmodifiableMap
collect(optional, collectingAndThen(
					toMap(identity(), identity()), 
					Collections::unmodifiableMap))

5. Conclusion

In this article, we saw how we can convert an Optional to Collection using Collector interface. This method can come in handy when the expected return type of method is some Collection.

Leave a Reply

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