Как использовать вызов collect в Java 8?
Допустим, у нас есть эта скучная часть кода, которую мы все должны были использовать:
ArrayList<Long> ids = new ArrayList<Long>();
for (MyObj obj : myList){
ids.add(obj.getId());
}
После перехода на Java 8 моя IDE сообщает мне, что я могу заменить этот код на collect call
, и он автоматически генерирует:
ArrayList<Long> ids = myList.stream().map(MyObj::getId).collect(Collectors.toList());
Однако это дает мне эту ошибку:
collect(java.util.stream.Collector<? super java.lang.Long,A,R>) in Steam cannot be
applied to: (java.util.stream.Collector<T>, capture<?>, java.util.List<T>>)
Я попробовал лить параметр, но он дал мне undefined A
и R
, а среда IDE больше не предлагает.
Мне любопытно, как вы можете использовать collect call
в этом сценарии, и я не мог найти никакой информации, которая могла бы вести меня правильно. Может ли кто-нибудь пролить свет?
Ответы
Ответ 1
Проблема заключается в том, что Collectors.toList
, что неудивительно, возвращает List<T>
. Не ArrayList
.
List<Long> ids = remove.stream()
.map(MyObj::getId)
.collect(Collectors.toList());
Программа для interface
.
Из документации:
Возвращает a Collector
, который накапливает входные элементы в новый List
. нет гарантий по типу, изменчивости, сериализуемость или безопасность потоков List
; если больше требуется контроль над возвращенным списком, используйте toCollection(Supplier)
.
Подчеркните минус - вы даже не можете предположить, что возвращаемый List
является изменяемым, не говоря уже о том, что он имеет определенный класс. Если вы хотите ArrayList
:
ArrayList<Long> ids = remove.stream()
.map(MyObj::getId)
.collect(Collectors.toCollection(ArrayList::new));
Обратите также внимание на то, что традиционно использовать import static
с API Java 8 Stream
, добавляя:
import static java.util.stream.Collectors.toCollection;
(Я ненавижу starred import static
, он ничего не делает, кроме как загрязняет пространство имен и добавляет путаницу, но выборочный import static
, особенно с классами служебных программ Java 8, может значительно уменьшить избыточный код)
Результат:
ArrayList<Long> ids = remove.stream()
.map(MyObj::getId)
.collect(toCollection(ArrayList::new));
Ответ 2
Я использую множество блоков коллектора, где я создаю пустой массив и заполняю его с помощью цикла, поэтому решил, что мне нужен собственный класс утилиты, чтобы снова не повторять одно и то же сообщение снова, вот оно:
public class Collections {
public static <T, O> List<T> collect(Set<O> items, Function<? super O, ? extends T> mapper) {
return items.stream().map(mapper).collect(Collectors.toCollection(ArrayList::new));
}
}
и используйте его так:
List<Product> prods = Collections.collect(basket.getOrderItems(), OrderItem::getProduct);
или как это
List<Long> prods = Collections.collect(basket.getOrderItems(), (item)->item.getProduct().getId());
Хотя это может показаться намного более легким для чтения, кажется, что потоки в этих сценариях немного медленнее, смотрите здесь