Как проверить, существует ли элемент с помощью лямбда-выражения?

118

В частности, у меня есть TabPane, и я хотел бы знать, есть ли в нем элемент с определенным идентификатором.

Итак, я хотел бы сделать это с помощью лямбда-выражения в Java:

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

for (Tab t : tabPane.getTabs()){
    if(t.getId().equals(idToCheck)) {
        idExists = true;
    }
}
Miljac
источник

Ответы:

273

Попробуйте использовать anyMatchлямбда-выражение. Это намного лучший подход.

 boolean idExists = tabPane.getTabs().stream()
            .anyMatch(t -> t.getId().equals(idToCheck));
Masudul
источник
11
Также стоит отметить: если вы хотите отказаться от проверки, используйте noneMatchвместо anyMatch.
Blacklight
Для вызова требуется уровень API 24
FabioLux
50

Хотя принятый ответ верен, я добавлю более элегантную версию (на мой взгляд):

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

Не пренебрегайте использованием Stream # map (), который позволяет сгладить структуру данных перед применением Predicate.

jFrenetic
источник
3
что здесь лучше? Я вижу только еще одну операцию. Извините, я новичок в этой ламбе.
TecHunter
2
@TecHunter точнее. Представьте, что вы читаете этот код в первый раз или снова через некоторое время. Есть несколько преимуществ. Во-первых, мы сразу показываем, что нас интересует не вкладка, а ее отображение. Во-вторых, используя ссылки на методы (что возможно только потому, что мы разбиваем исходную лямбду на два шага), мы показываем, что в коде нет никаких неожиданностей. В-третьих, используя ссылки на методы, мы не создаем новый предикат, а просто повторно используем его equals. Хотя, конечно, пример здесь очень простой, но я надеюсь, вы понимаете, о чем я.
Мальте Хартвиг
@MalteHartwig, спасибо! да, я получил ваши 3 балла, но я спрашивал о сглаживании map, это еще один шаг обработки, нет? Попробую сравнить 2 метода :)
TecHunter
1
@MalteHartwig протестирован в 10kk ArrayList с простым объектом, пытающимся найти последний элемент. дает разницу в 2 мс 131 мс против 133 мс для вашего. в массиве 1kk укажите ваш, если быстрее на 2 мс (от 55 до 53 мс). Так что можно сказать, что ваш лучше :)
TecHunter
2
Геттеры @TecHunter супер-дешевые. Всегда предпочитайте ясность кода экономии дополнительных 2 миллисекунд (хотя я сомневаюсь, что результаты точны, они могут колебаться при каждом запуске). Кроме того, помните, что промежуточные операции над потоками (например, map) по своей природе ленивы . Это означает, что getIdметод не применяется к каждому элементу коллекции. Он вычисляется лениво, пока не anyMatchвернет true .
jFrenetic
3

Приведенные выше ответы требуют, чтобы вы присвоили новый объект потока.

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
источник