web-dev-qa-db-fra.com

Filtrer une liste de JavaBeans avec Google Guava

Dans A Java Programme, j'ai une liste de haricots que je veux filtrer en fonction d'une propriété spécifique.

Par exemple, disons que j'ai une liste de personnes, une JavaBean, où la personne a de nombreuses propriétés, parmi elles "nom".

J'ai aussi une liste de noms.

Maintenant, je veux trouver toutes les personnes dont le nom figure dans la liste Nom.

Quelle est la meilleure façon d'exécuter ce filtre à l'aide de Google Guava?

Jusqu'à présent, j'ai pensé à combiner de Guava avec Apache Beansutils, mais cela ne semble pas élégant.

J'ai également trouvé une bibliothèque d'extension de réflexion ici: http://code.google.com/p/guava-réflection/ , mais je ne sais pas comment l'utiliser (il y a peu de documentation) .

Des pensées?

p.s. Pouvez-vous dire que je manque vraiment Python compréhension de la liste?

24
Or Peles

Faites-le la voie à l'ancienne, sans guava. (Parlant comme développeur de goyave.)

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

Vous pouvez le faire avec de GUAVA, mais Java n'est pas python et essaye de le faire entrer Python va simplement perpétuer le code maladroit et illisible. Guava's Les utilitaires fonctionnels doivent être utilisés avec parcimonie, et uniquement lorsqu'ils fournissent un avantage concret et mesurable aux lignes de code ou de performance.

42
Louis Wasserman
Iterable<Person> filtered = Iterables.filter(allPersons, new Predicate<Person>() {
    @Override
    public boolean apply(Person p) {
        return acceptedNames.contains(p.getName());
    }
});

Si votre liste de noms est grosse, vous feriez mieux de le transformer en un ensemble (HASHSET, de préférence) et l'appel contient sur cet ensemble, plutôt que la liste, car contient IS O(1) Pour un hashset, et O(n) pour une liste.

23
JB Nizet

Expliquer vos doutes de la phrase:

Jusqu'à présent, j'ai pensé à combiner de Guava avec Apache Beansutils, mais cela ne semble pas élégant.

Java, malgré d'être si populaire, manque fonction de première classe Support*, Qu'est-ce qui est sujet de changement de Java 8 , où vous pourrez faire:

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

Avec Lambdas et il sera élégant.

Jusque-là, vous avez choisi entre:

  • vue ancienne (comme @Louis a écrit)
  • filtre Verbose Guava (réponse de @ JB)
  • ou d'autres fonctionnels Java bibliothèques (réponse de @ Superfav).

J'aimerais également ajouter à la réponse de @ Lois que Guava-Way serait de créer une collection immuable , car - ils sont meilleurs que non modifiables , qui est également décrit dans Rubrique 15, minimisez la mutabilité dans Efficace Java par Joshua BlochAmateur:

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

(Son mise en œuvre détaille que ImmutableList.Builder crée temporaire ArrayList sous le capot).

*: Cela me dérange beaucoup, je venais de Python, JavaScript et Perl Worlds, où les fonctions sont mieux traitées

**: Guava et Bloch sont étroitement couplés de nombreuses manières;)

5
Xaerxess

Je ne peux pas accepter assez avec les réponses Louis et JB. Je ne savais pas que Guava-réflexion, peut-être Lambdaj pourrait être ce que vous recherchez:

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

Ou peut-être que Scala, Clojure ou Groovy sont ce que vous recherchez ...

4
superfav

Parlant en tant que développeur de Guava-réflexion, je suis désolé d'avoir abandonné ce projet à un tel stade précoce (j'ai un travail de jour et une femme et des enfants :-)). Ma vision était quelque chose comme:

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

Le code existant est d'environ 60% là-bas, donc si vous êtes intéressé, contactez-moi et pouvons-nous peut-être que cela puisse obtenir cela ensemble.

2
Sean Patrick Floyd

Avec le style Java8, vous pouvez utiliser Stream + Filtre pour atteindre votre objectif.

persons.stream()
            .filter(p -> names.contains(p.getName()))
            .collect(Collectors.toList());
0
enterbios

Avec Java8, vous pouvez utiliser Collection.RemoveIF ()

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

Cela modifiera bien sûr la liste actuelle.

0
user2051552

Voici un exemple d'utilisation de génériques à l'aide de GUAVA, des beansutils pour filtrer toute liste à l'aide d'une correspondance demandée

/**
 * 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
Anand

Si vous utilisez un LinkedList (ou une autre collection qui Supprimer Oprations n'est pas très laborieuse) dans l'application à une seule fois la solution la plus efficace est la suivante:

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