Фильтрация списка JavaBeans с помощью Google Guava - PullRequest
23 голосов
/ 26 декабря 2011

В программе на Java у меня есть список bean-компонентов, которые я хочу отфильтровать на основе определенного свойства.

Например, скажем, у меня есть список Person, JavaBean, где Person имеет много свойств, среди которых 'name'.

У меня также есть список имен.

Теперь я хочу найти всех людей, чье имя есть в списке имен.

Как лучше всего выполнить этот фильтр с помощью Google Guava?

До сих пор я думал о комбинировании Guava с beanutils Apache, но это не выглядит элегантно.

Я также нашел здесь библиотеку расширений отражения: http://code.google.com/p/guava-reflection/, но я не уверен, как его использовать (есть небольшая документация).

Есть мысли?

ps Можете ли вы сказать, что я действительно скучаю по пониманию списка Python?

Ответы [ 9 ]

42 голосов
/ 26 декабря 2011

Делай это по старинке, без гуавы.(Выступая в качестве разработчика на Guava.)

List<Person> filtered = Lists.newArrayList();
for(Person p : allPersons) {
   if(acceptedNames.contains(p.getName())) {
       filtered.add(p);
   }
}

Вы можете сделать это с Guava, но Java не является Python, и попытка превратить его в Python просто увековечит неуклюжий и нечитаемый код.Функциональные утилиты Guava следует использовать с осторожностью, и только в том случае, если они обеспечивают конкретное и измеримое преимущество для строк кода или производительности.

23 голосов
/ 26 декабря 2011
Iterable<Person> filtered = Iterables.filter(allPersons, new Predicate<Person>() {
    @Override
    public boolean apply(Person p) {
        return acceptedNames.contains(p.getName());
    }
});

Если ваш список имен большой, вам лучше преобразовать его в набор (предпочтительно, HashSet), и вызов содержит в этом наборе, а не в списке, потому что содержит O (1) для HashSet и O (n) для Списка.

5 голосов
/ 27 декабря 2011

Объясняя свои сомнения из предложения:

До сих пор я думал о комбинировании гуавы с beanutils Apache, но это не кажется элегантным.

Java, несмотря на свою популярность, не обладает первоклассной функцией поддержкой *, что может быть изменено в Java 8 , где вы будете находиться в состоянии сделать:

Iterable <Person> filtered = filter(allPersons, (Person p) -> acceptedNames.contains(p.getName()));

С лямбдами и будет элегантно.

До этого у вас есть выбор между:

  • олдскульный путь (как писал @Louis)
  • подробный фильтр гуавы (ответ @ JB)
  • или другие функциональные библиотеки Java (ответ @ superfav).

Я также хотел бы добавить к ответу @ Lois, что Guava-way будет создавать неизменную коллекцию , потому что они лучше, чем неизменяемые , что также описано в 1032 * Элемент 15, Минимизировать изменчивость в Эффективная Java Джошуа Блоха **:

ImmutableList.Builder<Person> builder = ImmutableList.builder();
for (final Person p : allPersons) {
    if (acceptedNames.contains(p.getName())) {
        builder.add(p);
    }
}
ImmutableList<Person> filtered = builder.build();

(это детали реализации, которые ImmutableList.Builder создает временные ArrayList под капотом).

*: меня это очень беспокоит, я пришел из миров Python, JavaScript и Perl, , где функции обрабатываются лучше

**: Гуава и Блох тесно связаны во многих отношениях;)

4 голосов
/ 27 декабря 2011

Я не могу достаточно согласиться с ответами Луи и Джей Би. Я не знал гуавы-отражения, может быть LambdaJ может быть тем, что вы ищете:

// set up
Person me = new Person("Favio");
Person luca = new Person("Luca");
Person biagio = new Person("Biagio");
Person celestino = new Person("Celestino");
Collection<Person> meAndMyFriends = asList(me, luca, biagio, celestino);

// magic
Collection<Person> filtered = filter(having(on(Person.class).getName(),
                                            isOneOf("Favio", "Luca")),
                                     meAndMyFriends);

// test
assertThat(filtered, hasItems(me, luca));
assertEquals(2, filtered.size());

Или, может быть, Scala, Clojure или Groovy - это то, что вы ищете ...

2 голосов
/ 27 декабря 2011

Говоря как разработчик guava-рефлексии, я сожалею, что отказался от этого проекта на столь ранней стадии (у меня есть дневная работа, жена и дети :-)). Мое видение было что-то вроде:

Iterable<Object> thingsWithNames = 
    Iterables.filter(someData,
                     // this is a Predicate, obviously
                     BeanProperties.hasBeanProperty("name", String.class));

Существующий код составляет около 60%, поэтому, если вам интересно, свяжитесь со мной, и, возможно, мы сможем закончить это вместе.

0 голосов
/ 24 ноября 2015

Вот пример использования обобщений с использованием guava, beanutils для фильтрации любого списка с использованием запрошенного соответствия

/**
 * Filter List
 * 
 * @param inputList
 * @param requestMatch
 * @param invokeMethod
 * @return
 */
public static <T> Iterable<T> predicateFilterList(List<T> inputList, final String requestMatch,
        final String invokeMethod) {
    Predicate<T> filtered = new Predicate<T>() {
        @Override
        public boolean apply(T input) {
            boolean ok = false;
            try {
                ok = BeanUtils.getProperty(input, invokeMethod).equalsIgnoreCase(requestMatch);
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            return ok;
        }
    };
    return Iterables.filter(inputList, filtered);
}
0 голосов
/ 30 августа 2014

С Java8 вы можете использовать Collection.removeIf ()

List<Person> theList = ...;
theList.removeIf(
    (Person p)->"paul".equals(p.getName())
);

Это, конечно, изменит текущий список.

0 голосов
/ 06 апреля 2014

В стиле Java8 вы можете использовать стрим + фильтр для достижения своей цели.

persons.stream()
            .filter(p -> names.contains(p.getName()))
            .collect(Collectors.toList());
0 голосов
/ 13 июля 2013

Если вы используете LinkedList (или любую другую коллекцию, которая удаляет операции не очень трудоемка) в однопоточном приложении, наиболее эффективным решением является:

final Iterator<User> userIterator = users.iterator();
while (userIterator.hasNext()) {
    if (/* your condition for exclusion */) {
        userIterator.remove();
    }
}
...