1. Обзор

В этой статье мы преобразуем Optional‹T› в Collection. Необязательный может содержать 0 или 1 элемент. Если бы Optional был Collection, это была бы пустая коллекция или коллекция-одиночка.

Мы можем создать собственные методы, которые преобразуют Optional в Collection. Если значение присутствует в необязательных параметрах, мы вернем одноэлементную коллекцию, иначе вернем пустую коллекцию.

2. в список (необязательно‹T› opt)

Если значение присутствует в Optional, мы создаем SingletonList с этим значением, в противном случае мы возвращаем emptyList.

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

3. toMap(Необязательно‹T› opt)

Если значение присутствует в Optional, мы создаем SingletonMap с этим значением, в противном случае мы возвращаем emptyMap. Возвращаемая Map будет иметь тот же ключ и значение.

import static java.util.Collections.*;
Map<String, String> toMap(Optional<String> optional) {
    return optional
                .map(value -> singletonMap(value, value))
                .orElseGet(Collections::emptyMap);
}

Map<String, String> map = toMap(Optional.of("abc"))

4. Собрать(Опционально‹T› opt, Коллектор‹T, A, R› коллектор)

Чтобы использовать существующий интерфейс для сбора данных в контейнер, мы можем использовать интерфейс Collector.

Это отличный способ сбора данных, поскольку мы можем передавать поведение нашего контейнера вместо того, чтобы писать собственные методы toList, toSet, toMap.

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

Вышеприведенный код принимает необязательный и сборщик в качестве параметра. Если значение существует в необязательном, оно добавляется в контейнер, иначе контейнер остается пустым.

  1. Получите изменяемый контейнер результатов от поставщика.
A accumulator = coll.supplier().get();

2. Если значение присутствует в необязательных параметрах, просто вставьте это значение в изменяемый контейнер результатов.

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

3. Преобразовать контейнер промежуточных результатов в контейнер результатов и вернуть его.

coll.finisher().apply(a)

Метод сбора с коллектором можно использовать несколькими способами.

Собрать в изменяемые контейнеры:

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.*;
 
// To mutable List
collect(optional, toList());
  
// To mutable Set
collect(optional, toSet());
  
// To mutable Map
collect(optional, toMap(identity(), identity()));

Возвращаемые коллекции являются изменяемыми, что означает, что вызывающая сторона этого API может повредить данные в коллекции. Для того, чтобы сделать эту коллекцию немодифицируемой, нам нужно использовать метод collectionAndThen класса Collectors.

Собрать в неизменяемые контейнеры:

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

5. Заключение

В этой статье мы увидели, как можно преобразовать Optional в Collection с помощью интерфейса Collector.

Первоначально опубликовано на https://justamonad.com 4 октября 2019 г.