4

Consider the case where an if condition needs to evaluate an array or a List. A simple example: check if all elements are true. But I'm looking for generic way to do it

Normally I'd do it like that:

boolean allTrue = true;
for (Boolean bool : bools){
    if (!bool) {
        allTrue = false;
        break;
     }
}
if (allTrue){
     // do Something
}

But now I'd like to hide it into my if condition. I tried using Lambda Expressions for this, but it's not working:

if (() -> {
    for (Boolean bool : bools)
        if (!bool)
            return false;
    return true;
}){
      // do something
}

If this were working I could do something more complicated like

if (() -> {
   int number = 0;
   for (MyObject myobject : myobjects)
       if (myObject.getNumber() != 0)
           numbers++;
   if (numbers > 2) 
       return false;
   return true;
 }{
     //do something
 }

Is there a better way to do it is it just a syntax error?

UPDATE I'm not talking about the boolean array, rather looking for a generic way to achieve that.

8
  • 2
    Uh, use .anyMatch()? Commented Apr 14, 2014 at 11:33
  • 1
    @fge .allMatch () maybe? He wanta to return true if all are true Commented Apr 14, 2014 at 11:34
  • Could conceivably use anyMatch instead - just ! the inputs and ! the whole expression. Commented Apr 14, 2014 at 11:36
  • Thx, not aware of those functions. I'm actually looking for a generic way to do it, probably unclear here. Commented Apr 14, 2014 at 11:37
  • 4
    Well, a @FunctionalInterface is not a boolean even if some of them return booleans; you'd have to invoke that "interface" to have a boolean result anyway Commented Apr 14, 2014 at 13:54

2 Answers 2

13

You can write, given for instance a List<Boolean>:

if (!list.stream().allMatch(x -> x)) {
    // not every member is true
}

Or:

if (list.stream().anyMatch(x -> !x)) {
    // at least one member is false
}

If you have an array of booleans, then use Arrays.stream() to obtain a stream out of it instead.


More generally, for a Stream providing elements of (generic) type X, you have to provide a Predicate<? super X> to .{all,any}Match() (either a "full" predicate, or a lambda, or a method reference -- many things go). The return value of these methods are self explanatory -- I think.


Now, to count elements which obey a certain predicate, you have .count(), which you can combine with .filter() -- which also takes (whatever is) a Predicate as an argument. For instance checking if you have more than 2 elements in a List<String> whose length is greater than 5 you'd do:

if (list.stream().filter(s -> s.length() > 5).count() > 2L) {
    // Yup...
}
Sign up to request clarification or add additional context in comments.

Comments

4

Your problem

Your current problem is that you use directly a lambda expression. Lambdas are instances of functional interfaces. Your lambda does not have the boolean type, that's why your if does not accept it.

This special case's solution

You can use a stream from your collections of booleans here.

if (bools.stream().allMatch((Boolean b)->b)) {
    // do something
}

It is actually much more powerful than this, but this does the trick I believe.

General hint

Basically, since you want an if condition, you want a boolean result. Since your result depends on a collection, you can use Java 8 streams on collections.

Java 8 streams allow you to do many operations on a collection, and finish with a terminal operation. You can do whatever complicated stuff you want with Stream's non-terminal operations. In the end you need one of 2 things:

  • use a terminal operation that returns a boolean (such as allMatch, anyMatch...), and you're done
  • use any terminal operation, but use it in a boolean expression, such as myStream.filter(...).limit(...).count() > 2

You should have a look at your possibilities in this Stream documentation or this one.

1 Comment

This gives a syntax error for me: Incompatible types: cannot infer functional interface descriptor for Predicate<? super boolean[]>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.