Liste filtern

Eine Funktionalität die in fast jeder Anwendung vorkommt, ist das Filtern einer Liste. Die Java API vor Java 8 enthält noch keine elegante Möglichkeit, um eine Collection zu filtern, darum helfen wieder mal Guava und Apache Commons aus.

Inhaltsverzeichnis

Liste filtern mit Java 8

Mit der neuen Java 8 Streams API und die Verwendung von Lamda Ausdrücken können Listen oder andere Collections recht elegant gefiltert werden. Dafür wird das funktionale Interface java.util.function.Predicate verwendet. Es enthält nur die Methode test(), die entscheidet ob das Prädikat (also eine Eigenschaft) auf das übergebene Objekt zutrifft.

Im folgenden Beispiel soll eine Liste von Strings nach Elementen mit dem Anfangsbuchstaben "F" gefiltert werden:

List<String> beerList = Arrays.asList("Fürstenbräu", "Eule", "Flecks", "Bevog", "Gösser");
List<String> filteredList = beerList.stream()
        .filter(new java.util.function.Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.startsWith("F");
            }
        }).collect(Collectors.toList());
System.out.println(filteredList); // [Fürstenbräu, Flecks]

Zuerst wird die Liste in einen Stream umgewandelt. Dieser wird dann mit dem Predicate gefiltert und der Stream mit der Methode collect() wieder in eine Liste umgewandelt.

Dank der Lambda-Notation von Java 8 kann das Predicate auch als einfache Funktion übergeben werden, was den Ausdruck noch weiter verkürzt:

List<String> beerList = Arrays.asList("Fürstenbräu", "Eule", "Flecks", "Bevog", "Gösser");
List<String> filteredList = beerList.stream()
            .filter(s -> s.startsWith("F"))
            .collect(Collectors.toList());
System.out.println(filteredList); // [Fürstenbräu, Flecks]

Durch den Lambdaausdruck s -> s.startsWith("F") wird das Filtern noch übersichtlicher.

Leider sind noch lange nicht alle Projekte auf Java 8 umgestellt, weshalb es hier noch andere Lösungen für Java 6 und Java 7 vorgestellt werden.

Liste filtern mit Google Guava

Die Bibliothek Google Guava enthält auch ein Interface com.google.common.base.Predicate mit einer Methode apply(), die entscheidet ob eine Eigenschaft auf das übergebene Objekt zutrifft. Guava bietet zwei Möglichkeiten um eine Liste zu filtern: com.google.common.collect.Iterables, eine Sammlung von nützlichen Methoden und com.google.common.collect.FluentIterable, ein (wie der Name schon sagt) fluent Interface, dass ähnlich der Java 8 Streams API Methoden anbietet, die nacheinander auf eine Collection angewendet werden können.

Guava Iterables

Im ersten Beispiel soll Iterables eine Liste von Strings nach Elementen mit dem Anfangsbuchstaben "F" filtern:

List<String> beerList = Arrays.asList("Fürstenbräu", "Eule", "Flecks", "Bevog", "Gösser");
Iterable<String> filteredIterable = Iterables.filter(beerList, new com.google.common.base.Predicate<String>() {
    @Override
    public boolean apply(String s) {
        return s.startsWith("F");
    }
});
List<String> filteredList = Lists.newArrayList(filteredIterable);
System.out.println(filteredList); // [Fürstenbräu, Flecks]

Ein kleiner Nachteil dieser Lösung ist, dass Iterables.filter() keine Liste, sondern ein Iterable-Objekt zurückliefert, dass erst wieder in eine Liste umgewandelt werden muss.

Guava FluentIterable

Eine vielleicht ein wenig elegantere Lösung ist, FluentIterable zu verwenden, das wie bereits erwähnt Java 8 Streams nicht unähnlich ist:

List<String> beerList = Arrays.asList("Fürstenbräu", "Eule", "Flecks", "Bevog", "Gösser");
List<String> filteredList = FluentIterable.from(beerList)
        .filter(new com.google.common.base.Predicate<String>() {
            @Override
            public boolean apply(String s) {
                return s.startsWith("F");
            }
        }).toList();
System.out.println(filteredList); // [Fürstenbräu, Flecks]

Durch die Methode from() wird aus der Liste ein FluentIterable erstellt, das gefiltert und dann wieder in eine Liste umgewandelt wird.

Liste filtern mit Apache Commons Collections

Eine weitere Möglichkeit bietet die Klasse CollectionUtils der Apache Commons Collections. Auch diese Library enthält eine Prädikat-Klasse: org.apache.commons.collections4.Predicate mit einer Test-Methode evaluate(), die entscheidet ob eine Eigenschaft auf das übergebene Objekt zutrifft.

Um eine Liste von Strings nach Elementen mit dem Anfangsbuchstaben "F" zu filtern kann die Methode CollectionUtils.filter() verwendet werden, die die zu filternde Collection und das Predicate Objekt entgegen nimmt.

List<String> beerList = Arrays.asList("Fürstenbräu", "Eule", "Flecks", "Bevog", "Gösser");
ArrayList<String> filteredList = new ArrayList<>(beerList);
CollectionUtils.filter(filteredList, new Predicate<String>() {
    @Override
    public boolean evaluate(String s) {
        return s.startsWith("F");
    }
});
System.out.println(filteredList); // [Fürstenbräu, Flecks]

Zu beachten ist, dass die Methode die übergebene Liste verändert. Deshalb wird zuerst eine Kopie der Liste erstellt, die dann an CollectionUtils.filter() übergeben wird.

Eine reine Java-Lösung zum Filtern einer Liste

Wenn man keine Util-Bibliothek wie Apache Commons oder Google Guava zu seinem Projekt hinzufügen will, kann man natürlich auch selbst eine einfache Methode schreiben um eine Liste zu filtern. Am Besten legt man dazu ein Predicate Interface an. Dieses sollte dem von Java 8 gleichen, damit es bei der späteren Umstellung des Projekts auf Java 8 einfach ersetzt werden kann:

public interface Predicate<T> {
    boolean test(T t);
}

Dieses Interface wird nun verwendet, um eine Methode filterList() zu schreiben:

public static <T> List<T> filterList(List<T> list, Predicate<T> predicate) {
    List<T> filtered = new ArrayList<>();
    for (T element:list){
        if(predicate.test(element)){
            filtered.add(element);
        }
    }
    return filtered;
}

Diese Methode kann nun ähnlich den obigen Beispielen mit der Liste und einem Predicate aufgerufen werden:

List<String> beerList = Arrays.asList("Fürstenbräu", "Eule", "Flecks", "Bevog", "Gösser");
List<String> filteredList = filterList(beerList, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.startsWith("F");
            }
        });
System.out.println(filteredList);

Ähnliche Artikel