Как использовать вызов 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());

Хотя это может показаться намного более легким для чтения, кажется, что потоки в этих сценариях немного медленнее, смотрите здесь