Filtern und Transformieren von Sammlungen in Guave

Filtern und Transformieren von Sammlungen in Guave

1. Überblick

In diesem Tutorial zeigen wir Ihnen, wie manfilter and transform collections with Guava macht.

Wir werden mit Prädikaten filtern, mit den von der Bibliothek bereitgestellten Funktionen transformieren und schließlich sehen, wie Filterung und Transformation kombiniert werden.

Weitere Lektüre:

Neuer Stream, Komparator und Sammler in Guave 21

Schnelle und praktische Anleitung zu Werkzeugen im common.collect-Paket in Guava 21.

Read more

Leitfaden für Guava Multimap

Eine kurze Anleitung zu Guava Multimap im Vergleich zu Standard java.util.Map

Read more

Leitfaden für Guava RangeSet

Erfahren Sie anhand von praktischen Beispielen, wie Sie das Google Guava RangeSet und seine Implementierungen verwenden.

Read more

2. Eine Sammlung filtern

Beginnen wir mit einem einfachen Beispiel fürfiltering a collection. Wir verwenden ein sofort einsatzbereites Prädikat, das von der Bibliothek bereitgestellt und über die DienstprogrammklassePredicateserstellt wurde:

@Test
public void whenFilterWithIterables_thenFiltered() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Iterable result
      = Iterables.filter(names, Predicates.containsPattern("a"));

    assertThat(result, containsInAnyOrder("Jane", "Adam"));
}

Wie Sie sehen können, filtern wir dieList von Namen, um nur die Namen zu erhalten, die das Zeichen "a" enthalten - und verwenden dazuIterables.filter().

Alternativ können wir auch die API vonCollections2.filter()gut nutzen:

@Test
public void whenFilterWithCollections2_thenFiltered() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result
      = Collections2.filter(names, Predicates.containsPattern("a"));

    assertEquals(2, result.size());
    assertThat(result, containsInAnyOrder("Jane", "Adam"));

    result.add("anna");
    assertEquals(5, names.size());
}

Ein paar Dinge, die hier zu beachten sind - erstens ist die Ausgabe vonCollections.filter()a live view of the original collection - Änderungen an einer werden sich in der anderen widerspiegeln.

Es ist auch wichtig zu verstehen, dass jetztthe result is constrained by the predicate - wenn wir ein Element hinzufügen, das diesePredicate nicht erfüllt, wird einIllegalArgumentException ausgelöst:

@Test(expected = IllegalArgumentException.class)
public void givenFilteredCollection_whenAddingInvalidElement_thenException() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result
      = Collections2.filter(names, Predicates.containsPattern("a"));

    result.add("elvis");
}

3. Schreiben Sie den benutzerdefinierten FilterPredicate

Als nächstes schreiben wir unsere eigenenPredicate, anstatt eine von der Bibliothek bereitgestellte zu verwenden. Im folgenden Beispiel definieren wir ein Prädikat, das nur die Namen erhält, die mit "A" oder "J" beginnen:

@Test
public void whenFilterCollectionWithCustomPredicate_thenFiltered() {
    Predicate predicate = new Predicate() {
        @Override
        public boolean apply(String input) {
            return input.startsWith("A") || input.startsWith("J");
        }
    };

    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result = Collections2.filter(names, predicate);

    assertEquals(3, result.size());
    assertThat(result, containsInAnyOrder("John", "Jane", "Adam"));
}

4. Kombinieren Sie mehrere Prädikate

Wir können mehrere Prädikate mitPredicates.or() undPredicates.and() kombinieren. Im folgenden Beispiel filtern wirList von Namen, um die Namen zu erhalten, die mit "J" beginnen oder kein "a" enthalten:

@Test
public void whenFilterUsingMultiplePredicates_thenFiltered() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result = Collections2.filter(names,
      Predicates.or(Predicates.containsPattern("J"),
      Predicates.not(Predicates.containsPattern("a"))));

    assertEquals(3, result.size());
    assertThat(result, containsInAnyOrder("John", "Jane", "Tom"));
}

5. Entfernen Sie Nullwerte beim Filtern einer Sammlung

Wir können dienull-Werte aus einer Sammlung bereinigen, indem wir sie wie im folgenden Beispiel mitPredicates.notNull() filtern:

@Test
public void whenRemoveNullFromCollection_thenRemoved() {
    List names =
      Lists.newArrayList("John", null, "Jane", null, "Adam", "Tom");
    Collection result =
      Collections2.filter(names, Predicates.notNull());

    assertEquals(4, result.size());
    assertThat(result, containsInAnyOrder("John", "Jane", "Adam", "Tom"));
}

6. Überprüfen Sie, ob alle Elemente in einer Sammlung einer Bedingung entsprechen

Als nächstes überprüfen wir, ob alle Elemente in einer Sammlung einer bestimmten Bedingung entsprechen. Wir werdenIterables.all() verwenden, um zu überprüfen, ob alle Namen "n" oder "m" enthalten, und dann prüfen, ob alle Elemente "a" enthalten:

@Test
public void whenCheckingIfAllElementsMatchACondition_thenCorrect() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");

    boolean result = Iterables.all(names, Predicates.containsPattern("n|m"));
    assertTrue(result);

    result = Iterables.all(names, Predicates.containsPattern("a"));
    assertFalse(result);
}

7. Verwandle eine Sammlung

Nun - mal sehen, wie mantransform a collection using a Guava Function macht. Im folgenden Beispiel transformieren wirList von Namen inList vonIntegers (Länge des Namens) mitIterables.transform():

@Test
public void whenTransformWithIterables_thenTransformed() {
    Function function = new Function() {
        @Override
        public Integer apply(String input) {
            return input.length();
        }
    };

    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Iterable result = Iterables.transform(names, function);

    assertThat(result, contains(4, 4, 4, 3));
}

Wir können auch dieCollections2.transform()-API wie im folgenden Beispiel verwenden:

@Test
public void whenTransformWithCollections2_thenTransformed() {
    Function func = new Function(){
        @Override
        public Integer apply(String input) {
            return input.length();
        }
    };

    List names =
      Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result = Collections2.transform(names, func);

    assertEquals(4, result.size());
    assertThat(result, contains(4, 4, 4, 3));

    result.remove(3);
    assertEquals(3, names.size());
}

Beachten Sie, dass die Ausgabe vonCollections.transform()a live view of the original Collection ist - Änderungen an einem wirken sich auf den anderen aus.

Und - wie zuvor - wenn wir versuchen, der AusgabeCollection ein Element hinzuzufügen, wird einUnsupportedOperationException ausgelöst.

8. Erstellen SieFunction ausPredicate

Wir können auchFunction ausPredicate mitFunctions.fromPredicate() erstellen. Dies wird natürlich eine Funktion sein, die die Eingaben gemäß der Bedingung des Prädikats inBoolean umwandelt.

Im folgenden Beispiel transformieren wirList von Namen in eine Liste von Booleschen Werten, wobei jedes Element darstellt, wenn der Name "m" enthält:

@Test
public void whenCreatingAFunctionFromAPredicate_thenCorrect() {
    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result =
      Collections2.transform(names,
      Functions.forPredicate(Predicates.containsPattern("m")));

    assertEquals(4, result.size());
    assertThat(result, contains(false, false, true, true));
}

9. Zusammensetzung zweier Funktionen

Weiter - Schauen wir uns an, wie Sie eine Sammlung mit einem zusammengesetztenFunction transformieren.

Functions.compose() gibt die Zusammensetzung zweier Funktionen zurück, da die zweitenFunction auf die Ausgabe der erstenFunction angewendet werden.

Im folgenden Beispiel - die erstenFunction transformieren den Namen in seine Länge, dann transformieren die zweitenFunction die Länge in einenboolean-Wert, der angibt, ob die Länge des Namens gerade ist:

@Test
public void whenTransformingUsingComposedFunction_thenTransformed() {
    Function f1 = new Function(){
        @Override
        public Integer apply(String input) {
            return input.length();
        }
    };

    Function f2 = new Function(){
        @Override
        public Boolean apply(Integer input) {
            return input % 2 == 0;
        }
    };

    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result =
      Collections2.transform(names, Functions.compose(f2, f1));

    assertEquals(4, result.size());
    assertThat(result, contains(true, true, true, false));
}

10. Kombinieren Sie Filtern und Transformieren

Und jetzt - sehen wir uns eine andere coole API an, die Guava hat - eine, die es uns tatsächlich ermöglicht, Filterung und Transformation miteinander zu verketten - dieFluentIterable.

Im folgenden Beispiel filtern wir dieList von Namen und transformieren sie dann mitFluentIterable:

@Test
public void whenFilteringAndTransformingCollection_thenCorrect() {
    Predicate predicate = new Predicate() {
        @Override
        public boolean apply(String input) {
            return input.startsWith("A") || input.startsWith("T");
        }
    };

    Function func = new Function(){
        @Override
        public Integer apply(String input) {
            return input.length();
        }
    };

    List names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    Collection result = FluentIterable.from(names)
                                               .filter(predicate)
                                               .transform(func)
                                               .toList();

    assertEquals(2, result.size());
    assertThat(result, containsInAnyOrder(4, 3));
}

Erwähnenswert ist, dass die imperative Version in einigen Fällen besser lesbar ist und dem funktionalen Ansatz vorgezogen werden sollte.

11. Fazit

Schließlich haben wir gelernt, wie man Sammlungen mit Guava filtert und transformiert. Wir haben die APIsCollections2.filter() undIterables.filter() zum Filtern sowieCollections2.transform() undIterables.transform() zum Transformieren von Sammlungen verwendet.

Schließlich haben wir uns kurz die sehr interessante fließende API vonFluentIterableangesehen, um sowohl Filterung als auch Transformation zu kombinieren.

Die Implementierung all dieser Beispiele und Codefragmentecan be found in the GitHub project - dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.