Соберите поток Java в неизменную коллекцию
1. Вступление
В этой быстрой статье мы рассмотрим различные способы сбораStreamsиз Java в неизменяемыеCollections –, которые требуют особого подхода, поскольку стандартныеCollectorsработают только с изменяемыми структурами данных.
2. Maven Dependency
Мы собираемся использовать библиотеку Google Guava для работы с некоторыми из наших примеров:
com.google.guava
guava
22.0
Мы можем получить последнюю версию этой зависимости изhere.
3. ИспользованиеcollectingAndThen() в Java
МетодcollectingAndThen() из класса JavaCollectors принимаетCollector иfinisherFunction, которые применяются к результату, возвращенному изCollector:
@Test
public void whenUsingCollectingToImmutableList_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c");
List result = givenList.stream()
.collect(collectingAndThen(toList(), ImmutableList::copyOf));
System.out.println(result.getClass());
}
Поскольку мы не можем использовать toCollection() Collector напрямую,, нам нужно собрать элементы во временный список, а затем построить из него неизменяемый список.
В этом примере мы конвертируемStream вList с помощью сборщикаtoList(), а затем создаемImmutableList. ImmutableList является частью библиотеки Guava. Если мы запишем вывод в консоль, мы получим класс базового
Если мы запишем вывод в консоль, мы получим класс базовой реализацииList:
class com.google.common.collect.RegularImmutableList
4. ИспользованиеCollectors Гуавы
Начиная с Guava 21, с каждым неизменяемым классом идет сопутствующийCollector, который так же прост в использовании, как и стандартныйCollectors:
@Test
public void whenCollectToImmutableList_thenSuccess() {
List list = IntStream.range(0, 9)
.boxed()
.collect(ImmutableList.toImmutableList());
}
Результирующий экземпляр -RegularImmutableList:
class com.google.common.collect.RegularImmutableList
5. Создание собственного коллектора
Теперь давайте сделаем еще один шаг и реализуем наш собственныйCollector. Для достижения этой цели мы собираемся использовать статический методCollector.of():
public static Collector, List> toImmutableList() {
return Collector.of(ArrayList::new, List::add,
(left, right) -> {
left.addAll(right);
return left;
}, Collections::unmodifiableList);
}
Чтобы узнать больше о реализации пользовательскогоCollectors, ознакомьтесь с разделом 4this article. Вот и все. Вышеуказанный метод является частью нашего пользовательского класса
Теперь мы можем использовать его, как любой другой встроенныйCollectors:
@Test
public void whenCollectToMyImmutableListCollector_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c", "d");
List result = givenList.stream()
.collect(MyImmutableListCollector.toImmutableList());
}
Наконец, давайте проверим вывод:
class java.util.Collections$UnmodifiableRandomAccessList
5.1. ДелаемMyImmutableListCollector универсальным
Наша реализация имеет одно ограничение - она всегда возвращает неизменяемый экземпляр, поддерживаемыйArrayList. Однако, с небольшим улучшением, мы можем заставить этот сборщик возвращать указанный пользователем тип:
public static > Collector> toImmutableList(
Supplier supplier) {
return Collector.of(
supplier,
List::add, (left, right) -> {
left.addAll(right);
return left;
}, Collections::unmodifiableList);
}
Теперь вместо определенияsupplier в реализации метода мы запрашиваемsupplier у пользователя:
@Test
public void whenPassingSupplier_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c", "d");
List result = givenList.stream()
.collect(MyImmutableListCollector.toImmutableList(LinkedList::new));
}
Обратите внимание, что теперь мы используемLinkedList вместоArrayList. Давайте запустим это и посмотрим на результаты:
class java.util.Collections$UnmodifiableList
На этот раз мы получилиUnmodifiableList вместоUnmodifiableRandomAccessList.
6. Заключение
В этой короткой статье мы увидели различные способы собратьStream в неизменяемыйCollection.
Обязательно ознакомьтесь с полным исходным кодом этой статьиover on GitHub.