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
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();
}
}
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:
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 ;)
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.
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...
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.
With Java8 style you can use stream + filter to achieve your goal.
persons.stream()
.filter(p -> names.contains(p.getName()))
.collect(Collectors.toList());