137

Specifically, I have TabPane, and I would like to know if there is element with specific ID in it.

So, I would like to do this with lambda expression in Java:

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

for (Tab t : tabPane.getTabs()){
    if(t.getId().equals(idToCheck)) {
        idExists = true;
    }
}
Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
Miljac
  • 2,045
  • 4
  • 19
  • 28
  • I would be writing with simple way and clean with List.contains method. Example: return tabPane.getTabs().contains(idToCheck); – soyphea Jan 04 '21 at 11:46

3 Answers3

316

Try to use anyMatch of Lambda Expression. It is much better approach.

 boolean idExists = tabPane.getTabs().stream()
            .anyMatch(t -> t.getId().equals(idToCheck));
Mark Hurd
  • 10,665
  • 10
  • 68
  • 101
Masudul
  • 21,823
  • 5
  • 43
  • 58
55

While the accepted answer is correct, I'll add a more elegant version (in my opinion):

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

Don't neglect using Stream#map() which allows to flatten the data structure before applying the Predicate.

jFrenetic
  • 5,384
  • 5
  • 42
  • 67
  • 3
    what is better here? I only see one more operation. Sorry I'm new to this lamba thing. – TecHunter Apr 26 '17 at 15:05
  • 2
    @TecHunter it is more explicit. Imagine you read this code the first time, or again after a while. There are several advantages: First, we immediately show that we are not actually interested in the tab, but some mapping of it. Second, by using method references (which is only possible because we break the initial lambda into two steps) we show that there are no surprises hidden in the code. Third, by using method references, we do not create a new Predicate, but really just re-use `equals`. Though, granted, the example here is very simple, but I hope you get what I mean. – Malte Hartwig May 17 '17 at 16:21
  • @MalteHartwig thanks! yeah I get your 3 points but I was asking about the flattening with `map`, it does another processing step no? I will try to compare the 2 methods :) – TecHunter May 18 '17 at 12:00
  • @TecHunter I do not think it will make any difference. You have to call `getId()` anyway after all. Just that now you do it separatly from the predicate. – Malte Hartwig May 18 '17 at 12:04
  • 1
    @MalteHartwig tested in a 10kk ArrayList with a simple object trying to find the last element. gives a 2ms difference 131ms against 133ms for your. on a 1kk array list yours if faster by 2ms (55ms to 53ms). So we can say that yours is better :) – TecHunter May 18 '17 at 13:40
  • 2
    @TecHunter getters are super-cheap. Always prefer code clarity over saving extra 2 milliseconds (even though, I doubt the results are accurate, it may fluctuate on every run). Besides, remember that intermediate operations on streams (such as `map`) are *lazy* by nature. That means that `getId` method is not applied to each element of the collection. It's evaluated lazily until `anyMatch` returns **true**. – jFrenetic May 25 '17 at 00:43
3

The above answers require you to malloc a new stream object.

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
  • 20,319
  • 26
  • 127
  • 154