it-roy-ru.com

Java 8 - без утомительного метода сбора

Java 8 stream api - очень приятная функция, и мне она очень нравится. Одна вещь, которая действует мне на нервы, это то, что 90% времени я хочу, чтобы входные данные представляли собой коллекцию, а выходные - коллекции. Следствием этого является необходимость постоянно вызывать методы stream() и collect():

collection.stream().filter(p->p.isCorrect()).collect(Collectors.toList());

Есть ли Java API, который позволил бы мне пропустить поток и напрямую работать с коллекциями (например, linq в c #?):

collection.filter(p->p.isCorrect)
56
user3364192

Если вы хотите работать с коллекциями FluentIterable Guava это путь!

Пример (получить идентификаторы 10 первых VIP-клиентов):

FluentIterable
       .from(customers)
       .filter(customer -> customer.isVIP())
       .transform(Client::getId)
       .limit(10);
10
Jakub Dziworski

Да, используя Collection#removeIf(Predicate) :

Удаляет все элементы этой коллекции, которые удовлетворяют данному предикату.

Обратите внимание, что это изменит данную коллекцию, а не вернет новую. Но вы можете создать копию коллекции и изменить ее. Также обратите внимание, что предикат должен быть отменен, чтобы действовать как фильтр:

public static <E> Collection<E> getFilteredCollection(Collection<E> unfiltered,
                                                      Predicate<? super E> filter) {
    List<E> copyList = new ArrayList<>(unfiltered);

    // removeIf takes the negation of filter 
    copyList.removeIf(e -> { return !filter.test(e);});  

    return copyList;
}

Но, как подсказывает @Holger в комментариях, если вы решите определить этот метод утилиты в своем коде и использовать его везде, где вам нужно получить отфильтрованную коллекцию, просто делегируйте вызов методу collect в этой утилите. Ваш код вызывающего абонента будет более кратким.

public static <E> Collection<E> getFilteredCollection(Collection<E> unfiltered,
                                                      Predicate<? super E> filter) {
   return unfiltered.stream()
                    .filter(filter)
                    .collect(Collectors.toList());
}
42
manouti

Вы можете использовать StreamEx

StreamEx.of(collection).filter(PClass::isCorrect).toList();

Это имеет то преимущество, что немного более кратко, сохраняя неизменность.

17
GuiSim

У потоков была четко определенная архитектура, о которой вы можете прочитать много . Возможно, вы захотите прочитать об этом, прежде чем начать этот путь.

Но почему бы не реализовать коллекцию, которая реализует подобный интерфейс потока, который оборачивает этот код для вас? 

public class StreamableCollection implements Collection, Stream {
...
}

Тогда вы могли бы сделать некоторые хитрые предположения для вашего варианта использования. Вы по-прежнему можете открывать поток из интерфейса коллекций, но вы также можете прыгнуть прямо внутрь, а затем, на внутренней стороне этой ручки, открыть поток, я полагаю. 

    streamableCollection cs = new streamableCollection();
    cs.filter();
    cs.stream();

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

7
TheNorthWes

Если вам нужно отфильтрованное представление без изменения исходной коллекции, рассмотрите Guava's Collections2.filter() .

7
shmosel

Я также думаю, что Stream API хорош, но многословен для коротких операций. Я использовал эти служебные методы в нескольких проектах:

import Java.util.List;
import Java.util.function.Function;
import Java.util.function.Predicate;
import Java.util.stream.Collectors;
import Java.util.stream.Stream;

public class Functions {

    public static <T,V> List<V> map(final List<T> in, final Function<T, V> function) {
        return in == null ? null : map(in.stream(), function);
    }

    public static <T,V> List<V> map(final Stream<T> in, final Function<T, V> function) {
        return in == null ? null : in
            .map(function)
            .collect(Collectors.toList());
    }

    public static <T> List<T> filter(final List<T> in, final Predicate<T> predicate) {
        return in == null ? null : filter(in.stream(), predicate);
    }

    public static <T> List<T> filter(final Stream<T> in, final Predicate<T> predicate) {
        return in == null ? null : in
            .filter(predicate)
            .collect(Collectors.toList());
    }
}

Это позволяет мне сделать, например,.

List<String> wrapped = Functions.map(myList, each -> "[" + each + "]");

Обычно я также импортирую статический метод.

6
Rory Hunter

Если вы открыты для использования сторонней библиотеки, вы можете использовать Eclipse Collections , которая имеет богатые API, непосредственно доступные в коллекциях. Ваш пример может быть написан как ниже с Eclipse Collections.

collection.select(p->p.isCorrect)
collection.select(MyClass::isCorrect)

Примечание: я являюсь коммиттером для Eclipse Collections.

3
itohro

Да, есть несколько библиотек, которые обращаются к потоковой детализации Java 8. Неполный список:

Мои предпочтения идут с JOOL. Я использовал это в моих последних проектах. Другие, которых я знаю, но на самом деле я ими не пользовался, поэтому не могу произвести на вас впечатление.

Ваш пример с jOOL будет:

Seq.seq(collection).filter(p->p.isCorrect()).toList();
1
sargue

Вы можете попробовать это из библиотеки гуавы. Это кажется немного менее загроможденным, чем подход Stream.

 ImmutableList.copyOf(Iterables.filter(collection, MyClass::isCorrect));

См. Коллекции Google (библиотеки Guava): ImmutableSet/List/Map and Filtering для обсуждения техники.

1
Hank D

С Циклоп-реагировать у вас есть несколько вариантов.

Мы можем использовать Lazy Extended Collections

  CollectionX<String> collection = ListX.of("hello","world");
  CollectionX<String> filtered = collection.filter(p->p.isCorrect());

Существует поддержка изменяемых, неизменных и постоянных расширенных коллекций. Функциональные операции над коллекциями ленивы (то есть ведут себя как воспроизводимые потоки) и материализуются только при первом доступе.

Мы можем использовать мощный расширенный тип потока

  ReactiveSeq.fromIterable(collection)
             .filter(p->p.isCorrect())
             .toList();

[Раскрытие Я ведущий разработчик циклоп-реакции]

0
John McClean