Jak sprawdzić, czy element istnieje, używając wyrażenia lambda?

118

W szczególności mam TabPane i chciałbym wiedzieć, czy jest w nim element o określonym identyfikatorze.

Tak więc chciałbym to zrobić z wyrażeniem lambda w Javie:

boolean idExists = false;
String idToCheck = "someId";

for (Tab t : tabPane.getTabs()){
    if(t.getId().equals(idToCheck)) {
        idExists = true;
    }
}
Miljac
źródło

Odpowiedzi:

273

Spróbuj użyć anyMatchwyrażenia Lambda. To znacznie lepsze podejście.

 boolean idExists = tabPane.getTabs().stream()
            .anyMatch(t -> t.getId().equals(idToCheck));
Masudul
źródło
11
Warto również zauważyć: jeśli chcesz zanegować czek, użyj noneMatchzamiast anyMatch.
Blacklight
Wywołanie wymaga poziomu API 24
FabioLux
50

O ile przyjęta odpowiedź jest prawidłowa, dodam bardziej elegancką wersję (moim zdaniem):

boolean idExists = tabPane.getTabs().stream()
    .map(Tab::getId)
    .anyMatch(idToCheck::equals);

Nie zaniedbuj używania Stream # map (), które pozwala spłaszczyć strukturę danych przed zastosowaniem Predicate.

jFrenetic
źródło
3
co tu jest lepsze? Widzę jeszcze tylko jedną operację. Przepraszam, że jestem nowy w tej sprawie z lambą.
TecHunter
2
@TecHunter jest bardziej wyraźny. Wyobraź sobie, że czytasz ten kod po raz pierwszy lub ponownie po chwili. Zalet jest kilka: Po pierwsze, od razu pokazujemy, że tak naprawdę nie interesuje nas karta, ale jej mapowanie. Po drugie, używając referencji do metod (co jest możliwe tylko dlatego, że dzielimy początkową lambdę na dwa kroki) pokazujemy, że w kodzie nie ma żadnych niespodzianek. Po trzecie, używając odniesień do metod, nie tworzymy nowego predykatu, ale tak naprawdę używamy go ponownie equals. Chociaż, przyznaję, przykład tutaj jest bardzo prosty, ale mam nadzieję, że rozumiesz, o co mi chodzi.
Malte Hartwig
@MalteHartwig thanks! tak, mam twoje 3 punkty, ale pytałem o spłaszczenie map, czy to kolejny krok przetwarzania, nie? Spróbuję porównać dwie metody :)
TecHunter
1
@MalteHartwig przetestowano w 10kk ArrayList z prostym obiektem próbującym znaleźć ostatni element. daje 2 ms różnicy 131 ms wobec 133 ms dla twojego. na tablicy 1kk lista twoja, jeśli jest szybsza o 2 ms (55 ms do 53 ms). Możemy więc powiedzieć, że twoje jest lepsze :)
TecHunter
2
Gettery @TecHunter są super tanie. Zawsze wolę przejrzystość kodu niż oszczędność dodatkowych 2 milisekund (chociaż wątpię, czy wyniki są dokładne, mogą się zmieniać przy każdym uruchomieniu). Poza tym pamiętaj, że pośrednie operacje na strumieniach (takich jak map) są z natury leniwe . Oznacza to, że getIdmetoda nie jest stosowana do każdego elementu kolekcji. Jest oceniany leniwie, dopóki nie anyMatchzwróci true .
jFrenetic
3

Powyższe odpowiedzi wymagają pobrania nowego obiektu strumienia.

public <T>
boolean containsByLambda(Collection<? extends T> c, Predicate<? super T> p) {

    for (final T z : c) {
        if (p.test(z)) {
            return true;
        }
    }
    return false;
}

public boolean containsTabById(TabPane tabPane, String id) {
    return containsByLambda(tabPane.getTabs(), z -> z.getId().equals(id));
}
...
if (containsTabById(tabPane, idToCheck))) {
   ...
}
kevinarpe
źródło