Filtering a list of JavaBeans with Google Guava

前端 未结 9 700
夕颜
夕颜 2020-12-01 06:59

In a Java program, I have a list of beans that I want to filter based on a specific property.

For example, say I have a list of Person, a JavaBean, where Person has

相关标签:
9条回答
  • 2020-12-01 07:00

    If you use a LinkedList(or any other collection which remove oprations is not very laborious) in single-threaded application the most efficacious solution is:

    final Iterator<User> userIterator = users.iterator();
    while (userIterator.hasNext()) {
        if (/* your condition for exclusion */) {
            userIterator.remove();
        }
    }
    
    0 讨论(0)
  • 2020-12-01 07:09

    Explaining your doubts from the sentence:

    So far, I've thought about combining Guava with Apache beanutils, but that doesn't seem elegant.

    Java, despite of being so popular, lacks first-class function support*, what is subject to change in Java 8, where you will be able to do:

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

    With lambdas and it will be elegant.

    Until then you have choose between:

    • old-school way (like @Louis wrote)
    • verbose Guava filter (@JB's answer)
    • or other functional Java libraries (@superfav's answer).

    I'd also like to add to @Lois's answer that Guava-way would be to create immutable collection, because they are better than unmodifiable, which is also described in Item 15, Minimize mutability in Effective Java by Joshua Bloch**:

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

    (It's implementation detail that ImmutableList.Builder creates temporary ArrayList under the hood).

    *: it bothers me much, I came from Python, JavaScript and Perl worlds, where functions are treated better

    **: Guava and Bloch are tightly coupled in many ways ;)

    0 讨论(0)
  • 2020-12-01 07:11
    Iterable<Person> filtered = Iterables.filter(allPersons, new Predicate<Person>() {
        @Override
        public boolean apply(Person p) {
            return acceptedNames.contains(p.getName());
        }
    });
    

    If your list of names is big, you'd better transform it into a Set (HashSet, preferrably) and call contains on this set, rather than the list, because contains is O(1) for a HashSet, and O(n) for a List.

    0 讨论(0)
  • 2020-12-01 07:11

    I can't agree enough with Louis and JB answers. I didn't know guava-reflection, maybe LambdaJ could be what you are looking for:

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

    Or maybe Scala, Clojure or Groovy are what you are looking for...

    0 讨论(0)
  • 2020-12-01 07:15

    With Java8 you can use Collection.removeIf()

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

    This will of course modify the current list.

    0 讨论(0)
  • 2020-12-01 07:19

    With Java8 style you can use stream + filter to achieve your goal.

    persons.stream()
                .filter(p -> names.contains(p.getName()))
                .collect(Collectors.toList());
    
    0 讨论(0)
提交回复
热议问题