Каков наилучший способ фильтрации коллекции Java?

Я хочу отфильтровать java.util.Collection основанный на предикате.

31 ответ

Решение

Java 8 ( 2014) решает эту проблему, используя потоки и лямбды в одной строке кода:

List<Person> beerDrinkers = persons.stream()
    .filter(p -> p.getAge() > 16).collect(Collectors.toList());

Вот учебник.

использование Collection#removeIf изменить коллекцию на месте. (Примечание: в этом случае предикат удалит объекты, которые удовлетворяют предикату):

persons.removeIf(p -> p.getAge() <= 16);

lambdaj позволяет фильтровать коллекции без написания циклов или внутренних классов:

List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
    greaterThan(16)));

Можете ли вы представить что-то более читаемое?

Правовая оговорка: я - участник на lambdaj

Предполагая, что вы используете Java 1.5, и что вы не можете добавить Google Collections, я бы сделал нечто очень похожее на то, что сделали ребята из Google. Это небольшое изменение в комментариях Джона.

Сначала добавьте этот интерфейс в вашу кодовую базу.

public interface IPredicate<T> { boolean apply(T type); }

Его разработчики могут ответить, когда определенный предикат является истинным для определенного типа. Например, если T мы User а также AuthorizedUserPredicate<User> инвентарь IPredicate<T>, затем AuthorizedUserPredicate#apply возвращает ли переданный в User авторизован.

Тогда в каком-то служебном классе вы могли бы сказать

public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
    Collection<T> result = new ArrayList<T>();
    for (T element: target) {
        if (predicate.apply(element)) {
            result.add(element);
        }
    }
    return result;
}

Таким образом, предполагая, что у вас есть использование выше, может быть

Predicate<User> isAuthorized = new Predicate<User>() {
    public boolean apply(User user) {
        // binds a boolean method in User to a reference
        return user.isAuthorized();
    }
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);

Если производительность при линейной проверке вызывает беспокойство, я мог бы захотеть иметь объект домена, имеющий целевую коллекцию. Доменный объект, имеющий целевую коллекцию, будет иметь логику фильтрации для методов, которые инициализируют, добавляют и устанавливают целевую коллекцию.

ОБНОВИТЬ:

В служебном классе (скажем, Predicate) я добавил метод select с опцией для значения по умолчанию, когда предикат не возвращает ожидаемое значение, а также статическое свойство для параметров, которые будут использоваться внутри нового IPredicate.

public class Predicate {
    public static Object predicateParams;

    public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
        Collection<T> result = new ArrayList<T>();
        for (T element : target) {
            if (predicate.apply(element)) {
                result.add(element);
            }
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
        T result = null;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
        T result = defaultValue;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }
}

В следующем примере выполняется поиск отсутствующих объектов между коллекциями:

List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
    new IPredicate<MyTypeA>() {
        public boolean apply(MyTypeA objectOfA) {
            Predicate.predicateParams = objectOfA.getName();
            return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
                public boolean apply(MyTypeB objectOfB) {
                    return objectOfB.getName().equals(Predicate.predicateParams.toString());
                }
            }) == null;
        }
    });

В следующем примере выполняется поиск экземпляра в коллекции и возвращается первый элемент коллекции в качестве значения по умолчанию, если экземпляр не найден:

MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
    return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));

ОБНОВЛЕНИЕ (после выпуска Java 8):

Прошло несколько лет с тех пор, как я (Алан) впервые опубликовал этот ответ, и я до сих пор не могу поверить, что набираю ТАК очки за этот ответ. Во всяком случае, теперь, когда Java 8 ввела замыкания в языке, мой ответ теперь будет значительно другим и более простым. В Java 8 нет необходимости в отдельном статическом служебном классе. Так что если вы хотите найти 1-й элемент, который соответствует вашему предикату.

final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).findFirst();

JDK 8 API для опций имеет возможность get(), isPresent(), orElse(defaultUser), orElseGet(userSupplier) а также orElseThrow(exceptionSupplier)а также другие "монадические" функции, такие как map, flatMap а также filter,

Если вы хотите просто собрать всех пользователей, которые соответствуют предикату, используйте Collectors прекратить поток в желаемой коллекции.

final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).collect(Collectors.toList());

Смотрите здесь для большего количества примеров того, как работают потоки Java 8.

Используйте CollectionUtils.filter(Collection,Predicate) от Apache Commons.

"Лучший" способ - это слишком широкая заявка. Это "самый короткий"? "Самый быстрый"? "Удобочитаемый"? Фильтр на месте или в другую коллекцию?

Простейший (но не самый читаемый) способ - выполнить итерацию и использовать метод Iterator.remove():

Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
  Foo foo = it.next();
  if( !condition(foo) ) it.remove();
}

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

CollectionUtils.filterInPlace(col,
  new IPredicate<Foo>(){
    public boolean keepIt(Foo foo) {
      return foo.isBar();
    }
  });

где filterInPlace() выполняет итерацию коллекции и вызывает Predicate.keepIt(), чтобы узнать, будет ли экземпляр храниться в коллекции.

Я не вижу оправдания для привлечения сторонней библиотеки только для этой задачи.

Рассмотрим Google Collections для обновленной структуры Collections, которая поддерживает дженерики.

ОБНОВЛЕНИЕ: Библиотека коллекций Google устарела. Вы должны использовать последнюю версию Guava вместо этого. Он все еще имеет все те же расширения для структуры коллекций, включая механизм фильтрации на основе предиката.

Ждите Java 8:

List<Person> olderThan30 = 
  //Create a Stream from the personList
  personList.stream().
  //filter the element to select only those with age >= 30
  filter(p -> p.age >= 30).
  //put those filtered elements into a new List.
  collect(Collectors.toList());

Начиная с раннего выпуска Java 8, вы можете попробовать что-то вроде:

Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);

Например, если у вас есть список целых чисел, и вы хотите отфильтровать числа, которые> 10, а затем распечатать эти числа на консоль, вы можете сделать что-то вроде:

List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);

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

Observable.from(Arrays.asList(1, 2, 3, 4, 5))
    .filter(new Func1<Integer, Boolean>() {
        public Boolean call(Integer i) {
            return i % 2 != 0;
        }
    })
    .subscribe(new Action1<Integer>() {
        public void call(Integer i) {
            System.out.println(i);
        }
    });

Выход:

1
3
5

Подробнее о RxJava filter можно найти здесь.

С ЯВА 9 Collectors.filtering включен:

public static <T, A, R>
    Collector<T, ?, R> filtering(Predicate<? super T> predicate,
                                 Collector<? super T, A, R> downstream)

При этом фильтрация должна быть:

collection.stream().collect(Collectors.filtering(predicate, collector))

Пример:

List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
            .collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));

Давайте посмотрим, как фильтровать встроенный список JDK и список MutableList с использованием коллекций Eclipse (ранее GS Collections).

List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);

Если вы хотите отфильтровать числа меньше 3, вы ожидаете следующих результатов.

List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);

Вот как вы можете фильтровать, используя анонимный внутренний класс в качестве Predicate,

Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
    public boolean accept(Integer each)
    {
        return each < 3;
    }
};

Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));

Assert.assertEquals(selected, ecList.select(lessThan3));

Вот несколько альтернатив фильтрации списков JDK и MutableList коллекций Eclipse с использованием фабрики Predicates.

Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));

Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));

Вот версия, которая не выделяет объект для предиката, используя вместо этого фабрику Predicates2 с selectWith метод, который принимает Predicate2,

Assert.assertEquals(
    selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));

Иногда вы хотите отфильтровать негативное состояние. В Eclipse Collections есть специальный метод, который называется reject,

Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));

Assert.assertEquals(rejected, ecList.reject(lessThan3));

Вот как вы можете фильтровать, используя лямбду Java 8 в качестве Predicate,

Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));

Assert.assertEquals(selected, gscList.select(each -> each < 3));
Assert.assertEquals(rejected, gscList.reject(each -> each < 3));

Метод partition вернет две коллекции, содержащие элементы, выбранные и отклоненные Predicate,

PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());

PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());

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

Вы уверены, что хотите отфильтровать саму коллекцию, а не итератор?

см. org.apache.commons.collections.iterators.FilterIterator

или используя версию 4 Apache Commons org.apache.commons.collections4.iterators.FilterIterator

Как насчет простой и понятной Java?

 List<Customer> list ...;
 List<Customer> newList = new ArrayList<>();
 for (Customer c : list){
    if (c.getName().equals("dd")) newList.add(c);
 }

Просто, читабельно и легко (и работает в Android!) Но если вы используете Java 8, вы можете сделать это в единственной строке:

List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());

Обратите внимание, что toList() статически импортируется

Настройка:

public interface Predicate<T> {
  public boolean filter(T t);
}

void filterCollection(Collection<T> col, Predicate<T> predicate) {
  for (Iterator i = col.iterator(); i.hasNext();) {
    T obj = i.next();
    if (predicate.filter(obj)) {
      i.remove();
    }
  }
}

Использование:

List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
  public boolean filter(MyObject obj) {
    return obj.shouldFilter();
  }
});

Метод Collections2.filter(Collection,Predicate) в библиотеке Google Guava делает именно то, что вы ищете.

С ForEach DSL вы можете написать

import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;

Collection<String> collection = ...

for (Select<String> each : select(collection)) {
    each.yield = each.value.length() > 3;
}

Collection<String> result = $result();

Для данной коллекции [Быстрый, коричневый, лиса, прыжки, через, ленивый, собака] это приводит к [быстрому, коричневому, прыжки, через, ленивый], то есть все строки длиннее трех символов.

Все стили итераций, поддерживаемые ForEach DSL,

  • AllSatisfy
  • AnySatisfy
  • Collect
  • Counnt
  • CutPieces
  • Detect
  • GroupedBy
  • IndexOf
  • InjectInto
  • Reject
  • Select

Для получения более подробной информации, пожалуйста, обратитесь к https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach

In Java 8, You can directly use this filter method and then do that.



 List<String> lines = Arrays.asList("java", "pramod", "example");

        List<String> result = lines.stream()              
                .filter(line -> !"pramod".equals(line))     
                .collect(Collectors.toList());              

        result.forEach(System.out::println); 

Это, в сочетании с отсутствием реальных замыканий, является моей самой большой проблемой для Java. Честно говоря, большинство методов, упомянутых выше, довольно легко читать и ДЕЙСТВИТЕЛЬНО эффективно; однако, потратив время на.Net, Erlang и т. д., понимание списка, интегрированное на уровне языка, делает все намного чище. Без дополнений на уровне языка Java не может быть настолько чистым, как многие другие языки в этой области.

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

А потом есть библиотека, которую я написал. Я буду игнорировать любые вопросы, касающиеся его эффективности (да, это так плохо)...... Да, я знаю, что он основан на отражениях, и нет, на самом деле я его не использую, но он работает:

LinkedList<Person> list = ......
LinkedList<Person> filtered = 
           Query.from(list).where(Condition.ensure("age", Op.GTE, 21));

ИЛИ ЖЕ

LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");

С помощью java 8конкретно lambda expressionВы можете сделать это просто, как показано ниже:

myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())

где для каждого product внутри myProducts сбор, если prod.price>10, а затем добавить этот продукт в новый отфильтрованный список.

Некоторые действительно отличные ответы здесь. Мне бы хотелось, чтобы текст был максимально простым и читабельным:

public abstract class AbstractFilter<T> {

    /**
     * Method that returns whether an item is to be included or not.
     * @param item an item from the given collection.
     * @return true if this item is to be included in the collection, false in case it has to be removed.
     */
    protected abstract boolean excludeItem(T item);

    public void filter(Collection<T> collection) {
        if (CollectionUtils.isNotEmpty(collection)) {
            Iterator<T> iterator = collection.iterator();
            while (iterator.hasNext()) {
                if (excludeItem(iterator.next())) {
                    iterator.remove();
                }
            }
        }
    }
}

Используйте механизм сбора запросов (CQEngine). Это, безусловно, самый быстрый способ сделать это.

См. Также: Как вы запрашиваете коллекции объектов в Java (Criteria/SQL-like)?

Я написал расширенный класс Iterable, который поддерживает применение функциональных алгоритмов без копирования содержимого коллекции.

Использование:

List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }

Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
    public Boolean call(Integer n) throws FunctionalException
    {
        return n % 2 == 0;
    }
})

for( int n : filtered )
{
    System.out.println(n);
}

Код выше на самом деле будет выполняться

for( int n : myList )
{
    if( n % 2 == 0 ) 
    {
        System.out.println(n);
    }
}

JFilter http://code.google.com/p/jfilter/ лучше всего подходит для ваших требований.

JFilter - это простая и высокопроизводительная библиотека с открытым исходным кодом для запроса коллекции Java-бинов.

Ключевая особенность

  • Поддержка коллекционных (java.util.Collection, java.util.Map и Array) свойств.
  • Поддержка коллекции внутри коллекции любой глубины.
  • Поддержка внутренних запросов.
  • Поддержка параметризованных запросов.
  • Может отфильтровать 1 миллион записей за несколько 100 мс.
  • Фильтр (запрос) дается в простом формате json, он похож на запросы Mangodb. Ниже приведены некоторые примеры.
  • {"id": {"$ le": "10"}
    • где свойство id объекта меньше чем равно 10.
  • {"id": {"$ in": ["0", "100"]}}
    • где свойство id объекта равно 0 или 100.
  • { "lineItems": { "lineAmount": "1"}}
    • где свойство коллекции lineItems параметризованного типа имеет значение lineAmount, равное 1.
  • {"$ and": [{"id": "0"}, {"billingAddress": {"city": "DEL"}}]}
    • где свойство id равно 0, а свойство billingAddress.city равно DEL.
  • {"lineItems": {"tax":{ "key":{"code":"GST"}, "value":{"$gt": "1.01"}}}}
    • где свойство коллекции lineItems параметризованного типа, имеющее свойство типа карты налогов параметризованного типа, имеет код, равный значению GST, превышающему 1,01.
  • {'$ или': [{'code': '10'},{'skus': {'$ and': [{'price': {'$ in': ['20', '40']} },{'code': 'RedApple'}]}}]}
    • Выберите все продукты, для которых код продукта 10 или цена sku в 20 и 40, а код sku - "RedApple".

Мне нужно было отфильтровать список в зависимости от значений, уже присутствующих в списке. Например, удалите все значения, следующие ниже, чем текущее значение. {2 5 3 4 7 5} -> {2 5 7}. Или, например, удалить все дубликаты {3 5 4 2 3 5 6} -> {3 5 4 2 6}.

public class Filter {
    public static <T> void List(List<T> list, Chooser<T> chooser) {
        List<Integer> toBeRemoved = new ArrayList<>();
        leftloop:
        for (int right = 1; right < list.size(); ++right) {
            for (int left = 0; left < right; ++left) {
                if (toBeRemoved.contains(left)) {
                    continue;
                }
                Keep keep = chooser.choose(list.get(left), list.get(right));
                switch (keep) {
                    case LEFT:
                        toBeRemoved.add(right);
                        continue leftloop;
                    case RIGHT:
                        toBeRemoved.add(left);
                        break;
                    case NONE:
                        toBeRemoved.add(left);
                        toBeRemoved.add(right);
                        continue leftloop;
                }
            }
        }

        Collections.sort(toBeRemoved, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int i : toBeRemoved) {
            if (i >= 0 && i < list.size()) {
                list.remove(i);
            }
        }
    }

    public static <T> void List(List<T> list, Keeper<T> keeper) {
        Iterator<T> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (!keeper.keep(iterator.next())) {
                iterator.remove();
            }
        }
    }

    public interface Keeper<E> {
        boolean keep(E obj);
    }

    public interface Chooser<E> {
        Keep choose(E left, E right);
    }

    public enum Keep {
        LEFT, RIGHT, BOTH, NONE;
    }
}

Это будет использоваться следующим образом.

List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
    @Override
    public Filter.Keep choose(String left, String right) {
        return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
    }
});

Мой ответ основан на этом от Кевина Вонга, здесь в качестве однострочника, использующего CollectionUtils от весны и лямбда- выражения Java 8.

CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);

Это так же кратко и читабельно, как и любая альтернатива, которую я видел (без использования библиотек аспектов)

Spring CollectionUtils доступен с весенней версии 4.0.2.RELEASE, и помните, что вам нужен JDK 1.8 и языковой уровень 8+.

https://code.google.com/p/joquery/

Поддерживает разные возможности,

Данная коллекция,

Collection<Dto> testList = new ArrayList<>();

типа,

class Dto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

Фильтр

Java 7

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property("id").eq().value(1);
Collection<Dto> filtered = query.list();

Java 8

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property(Dto::getId)
    .eq().value(1);
Collection<Dto> filtered = query.list();

Также,

Filter<Dto> query = CQ.<Dto>filter()
        .from(testList)
        .where()
        .property(Dto::getId).between().value(1).value(2)
        .and()
        .property(Dto::grtText).in().value(new string[]{"a","b"});

Сортировка (также доступна для Java 7)

Filter<Dto> query = CQ.<Dto>filter(testList)
        .orderBy()
        .property(Dto::getId)
        .property(Dto::getName)
    Collection<Dto> sorted = query.list();

Группировка (также доступна для Java 7)

GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
        .group()
        .groupBy(Dto::getId)
    Collection<Grouping<Integer,Dto>> grouped = query.list();

Объединения (также доступно для Java 7)

Дано,

class LeftDto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

class RightDto
{
    private int id;
    private int leftId;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getLeftId()
        {
            return leftId;
        }

    public int getText()
    {
        return text;
    }
}

class JoinedDto
{
    private int leftId;
    private int rightId;
    private String text;

    public JoinedDto(int leftId,int rightId,String text)
    {
        this.leftId = leftId;
        this.rightId = rightId;
        this.text = text;
    }

    public int getLeftId()
    {
        return leftId;
    }

    public int getRightId()
        {
            return rightId;
        }

    public int getText()
    {
        return text;
    }
}

Collection<LeftDto> leftList = new ArrayList<>();

Collection<RightDto> rightList = new ArrayList<>();

Может быть присоединен как,

Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
                .<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
                .on(LeftFyo::getId, RightDto::getLeftId)
                .transformDirect(selection ->  new JoinedDto(selection.getLeft().getText()
                                                     , selection.getLeft().getId()
                                                     , selection.getRight().getId())
                                 )
                .list();

Выражения

Filter<Dto> query = CQ.<Dto>filter()
    .from(testList)
    .where()
    .exec(s -> s.getId() + 1).eq().value(2);

Простое решение до Java8:

ArrayList<Item> filtered = new ArrayList<Item>(); 
for (Item item : items) if (condition(item)) filtered.add(item);

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

В моем случае я искал список с исключенным определенным нулевым полем. Это можно сделать с помощью цикла for и заполнить временный список объектов, у которых нет нулевых адресов. но благодаря Java 8 Streams

      List<Person> personsList = persons.stream()
.filter(p -> p.getAdrress() != null).collect(Collectors.toList());

#java #collection #collections # java8 #streams

Я предпочитаю этот способ:

      public static void main(String[] args) {
    
    //Create predicate
    Predicate<Integer> FILTER_ODD_ONES =
        number -> number % 2 != 0;
    
    //Apply predicate
    Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
        .stream()
        .filter(FILTER_ODD_ONES)
        .collect(Collectors.toList());
  }

Альтернативной (более легкой) альтернативой потокам коллекций Java является библиотека Ocl.java, в которой используются ванильные коллекции и лямбда-выражения: https://github.com/eclipse/agileuml/blob/master/Ocl.java

Например, простой фильтр и сумма слов ArrayList могут быть такими:

      ArrayList<Word> sel = Ocl.selectSequence(words, 
                             w -> w.pos.equals("NN")); 
int total = Ocl.sumint(Ocl.collectSequence(sel,
                             w -> w.text.length())); 

Где Word имеет строку pos; Текст строки; атрибуты. Эффективность похожа на вариант с потоками, например, 10000 слов обрабатываются примерно за 50 мс в обеих версиях.

Существуют эквивалентные библиотеки OCL для Python, Swift и т. Д. В основном потоки коллекций Java заново изобрели операции OCL ->select, -> collect и т. Д., Которые существовали в OCL с 1998 года.

С гуавой:

Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);

Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
    @Override
    public boolean apply(Integer i) {
        return i % 2 == 0;
    }
});

System.out.println(collection); // Prints 1, 3, 5
Другие вопросы по тегам