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


Ответы:


699

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


34
Хорошо, но статический импорт запутывает происходящее. Для справки, выберите / имеющие / включены статический импорт в ch.lambdaj.Lambda, больше - org.hamcrest.Matchers
MikePatel

11
LambdaJ действительно сексуален, но стоит отметить, что он подразумевает значительные накладные расходы (в среднем 2,6): code.google.com/p/lambdaj/wiki/PerformanceAnalysis .
Док Давлуз

7
Очевидно, не работает на Android: groups.google.com/forum/#!msg/lambdaj/km7uFgvSd3k/grJhgl3ik5sJ
Мориц

7
Очень нравится этот пример LamdaJ ... похож на встроенные функции .NET лямбда .NET. А где человек может пить в 16 лет? Мы должны рассмотреть возможность добавления ограничения локализации. : P
MAbraham1

3
removeIf пример должен бытьpersons.removeIf(p -> p.getAge() <= 16);
vim

224

Предполагая, что вы используете 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.


27
Да, но я ненавижу изобретать велосипед, снова и снова. Я предпочел бы найти какую-нибудь служебную библиотеку, которая делает, когда я хочу.
Кевин Вонг

2
Это не лучший способ, если вы не хотите новую коллекцию. Используйте метафору итератора фильтра, которая может вводить в новую коллекцию, или это может быть все, что вам нужно.
Джош

@Nestor: в понимании Scala фильтрация была бы намного проще:val authorized = for (user <- users if user.isAuthorized) yield user
Алан

Изменяет ли это оригинальную коллекцию или создает новую? Я попытался использовать этот метод и зарегистрировал обе мои коллекции (оригинал и ту, что возвращена из метода), они одинаковы. @ Алан
Рохан

1
@Rohan, это не предназначено, чтобы изменить оригинальную коллекцию. Обратите внимание, что вышеупомянутая коллекция результатов создается заново, а метод фильтра добавляет коллекцию результатов только в том случае, если применяется предикат.
Алан

92

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


3
это нормально, но это не универсально, и изменяет коллекцию на месте (не приятно)
Кевин Вонг

2
В CollectionUtils есть другие методы фильтрации, которые не изменяют исходную коллекцию.
Скаффман

42
В частности, метод, который не изменяет коллекцию на месте, это org.apache.commons.collections.CollectionUtils # select (Collection, Predicate)
Eero,

5
В Commons Collections v4 теперь используется Generics.
Джастин Эмери

1
Этот метод следует использовать с осторожностью, так как он опирается (по крайней мере, на реализацию commons-collection-3.2.1) на метод iterator.remove (), который является необязательным для коллекций, поэтому вместо фильтрации, скажем, массива вы можете получить исключение UnsupportedOperationException.
user2417480 15.10.15

67

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

Простейший (но не самый читаемый) способ - выполнить итерацию и использовать метод 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 (), чтобы узнать, будет ли экземпляр храниться в коллекции.

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


6
Мой голос идет за это: он просто работает, без внешних библиотек. Я никогда не думал, что создание Итератора может быть полезным по сравнению с использованием синтаксиса for-each или тем, что вы можете удалять элементы из списка без исключения ConcurrentModificationException или чего-то в этом роде. :)
ZeroOne

1
Я думаю, что это лучший способ использовать стандартную библиотеку Java без копирования. Для 1.8 была бы stream()особенность, но не каждый может поиграть с новейшими игрушками: P
Populus

Это тоже изменяет оригинальную коллекцию? @ ZeroOne
Рохан

Да, конечно, @Rohan. Попробуйте, если не верите. ;)
ZeroOne

Хаха, я сделал! Но я хочу сохранить свою оригинальную коллекцию. Можете ли вы предложить способ сделать это без добавления внешней библиотеки? @ ZeroOne
Рохан

62

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

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


да, я знал о библиотеках Google. В версии, которую я использовал, не было Collections2. Я добавил новый ответ на этот вопрос, в котором перечислены конкретные методы.
Кевин Вонг

7
Кевин, Iterables.filter () и Iterators.filter () были там с самого начала, и, как правило, все, что вам нужно.
Кевин Бурриллион

28

Ждите 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());

13
Тьфу ... это так многословно. Почему они не могли просто сделать: List <Person> result = personList.filter (p -> p.age> 30);
Кевин Вонг

8
Чтобы использовать фильтр непосредственно в коллекции, вам нужно использовать команду removeIf : download.java.net/jdk8/docs/api/java/util/…
gavenkoa

6
@KevinWong "многословный" в значительной степени описывает весь язык, который я думаю. По крайней мере, они последовательны?
Изгой

5
Почему бы не использовать Collectors.toList () в последней части?
Нестор Эрнандес Лоли

3
Вот ссылка gavenkoa при условии, что не 404. personList.removeIf(p -> p.age < 30);Меньше многословно. Кроме того, я слышал разговоры о том, чтобы начать реализовывать apis, которые принимают и возвращают Streams, а не Collections, потому что Streams очень полезны и быстры, но идти к ним и из них идет медленно.
Капитан Мэн

11

Начиная с раннего выпуска 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);

11

Я добавлю 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можно найти здесь .


7

Настройка:

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();
  }
});

2
Хорошо, но я предпочитаю реализацию Alan, потому что вы получаете копию коллекции вместо ее изменения. Более того, код Алана является потокобезопасным, а ваш - нет.
Marcospereira

7

Как насчет простой и понятной 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 () статически импортируется



7

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

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);

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

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

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

Вот как вы можете фильтровать, используя анонимный внутренний класс в качестве 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 reject.

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

Метод 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.


1
Как бы вы сделали в removeIfсписке или установить для примитивов?
Вивек Рао

API для removeIf был добавлен к примитивным коллекциям в EC 9.1. eclipse.org/collections/javadoc/9.1.0/org/eclipse/collections/…
Дональд Рааб

5

С 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


Это довольно умно! Хотя много работы по реализации хорошего синтаксиса Ruby-ish! Отрицательным является то, что ваш фильтр не является первоклассной функцией и, следовательно, не может быть использован повторно.
Бросай

Хорошая точка зрения. Один из способов повторного использования тела цикла - это рефакторинг цикла в метод, который принимает запрос выбора в качестве параметра. Это, однако, далеко не так удобно и мощно, как настоящие замыкания.
akuhn


5

Поскольку java 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()));

3

Это, в сочетании с отсутствием реальных замыканий, является моей самой большой проблемой для 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");

Ссылка на сайт? Даже если ваша библиотека неэффективна или непригодна для других целей, было бы интересно посмотреть, доступен ли источник.
MatrixFrog

Сделал репо публичным ( net-machine.com/indefero/p/jdclib/source/tree/master ). Вы заинтересованы в выражении пакета. В тестовом пакете есть тестер с примером использования. Я никогда особо не работал над интерфейсом строковых запросов, на который ссылались выше (не хотелось писать настоящий парсер), так что явный интерфейс запросов в тестере - это путь.
jdc0589

2

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».

1
Вы должны отрицать, что вы являетесь автором (как я думаю, это так).
assylias

Да, я являюсь автором этой библиотеки.
Камран Али Хан

2

Я написал расширенный класс 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);
    }
}


2

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

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();
                }
            }
        }
    }
}

Просто реализуйте правильный excludeItem для каждого фильтра. В итоге у вас будут отдельные фильтры точно так же, как у вас есть сортировщики в коллекциях ...
Лоуренс

1

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

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

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


1

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);

1

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

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

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

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


1

Используя java 8, в частности lambda expression, вы можете сделать это просто, как показано ниже:

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

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


1

Мне нужно было отфильтровать список в зависимости от значений, уже присутствующих в списке. Например, удалите все значения, следующие ниже, чем текущее значение. {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;
    }
});

0

С гуавой:

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

0

В Java 8 вы можете напрямую использовать этот метод фильтра, а затем сделать это.

 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); 
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.