As it almost but not really matches Optional, maybe you might reconsider the logic:

Java 8 has a limited expressiveness:

Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
System.out.println(element.orElse(DEFAULT_ELEM));

Here the map might restrict the view on the element:

element.map(el -> el.mySpecialView()).ifPresent(System.out::println);

Java 9:

element.ifPresentOrElse(el -> System.out.println("Present " + el,
                        () -> System.out.println("Not present"));

In general the two branches are asymmetric.

Answer from Joop Eggen on Stack Overflow
🌐
Javatpoint
javatpoint.com › if-condition-in-lambda-expression-java
if Condition in Lambda Expression Java - Javatpoint
if Condition in Lambda Expression Java with java tutorial, features, history, variables, programs, operators, oops concept, array, string, map, math, methods, examples etc.
🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › using ‘if-else’ conditions with java streams
Using 'if-else' Conditions with Java Streams - HowToDoInJava
March 3, 2022 - Learn to use the if-else conditions logic using Java Stream API to filter the items from a collection based on certain conditions. The 'if-else' condition can be applied as a lambda expression in forEach() function in form of a Consumer action.
🌐
TutorialsPoint
tutorialspoint.com › how-to-write-a-conditional-expression-in-lambda-expression-in-java
How to write a conditional expression in lambda expression in Java?
The conditional operator is used to make conditional expressions in Java. It is also called a Ternary operator because it has three operands such as boolean condition, first expression, and second expression. We can also write a conditional expression in lambda expression in the below program.
🌐
Stack Overflow
stackoverflow.com › questions › 45006435 › how-to-make-lambda-expression-as-a-condition-in-if-then-statement
java - How to make lambda expression as a condition in if-then statement - Stack Overflow
Is it either of these you mean? public static void main(String[] args) { boolean ifResult = lambdaIf( (pInt) -> { //Call lambdaIf with a function if(pInt == 0) { //Our lambda has an if-case for its input return true; } else { return false; } ...
Top answer
1 of 3
6

As a stream call chain is complex make two streams - avoiding the conditional branches.

String ncourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() != null)
   .map(EquivalentCourse::getNcourse)
   .map(x -> String.valueOf(x.getId()))
   .collect(Collectors.joining(", "));

String pastCourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() == null
          && equivalentCourse.getPastCourse() != null)
   .map(EquivalentCourse::getPastCourse)
   .map(x -> String.valueOf(x.getId()))
   .collect(Collectors.joining(", "));

This also is code focusing on the resulting two strings, with an efficient joining.

By the way, if this is for an SQL string, you may use a PreparedStatement with an Array.


Embellishment as commented by @Holger:

String ncourseIds = equivalentCourses.stream()
   .map(EquivalentCourse::getNcourse)
   .filter(Objects::nonNull)
   .map(NCourse::getId)
   .map(String::valueOf)
   .collect(Collectors.joining(", "));

String pastCourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() == null)
   .map(EquivalentCourse::getPastCourse)
   .filter(Objects::nonNull)
   .map(EquivalentCourse::getPastCourse)
   .map(PastCourse::getId)
   .map(String::valueOf)
   .collect(Collectors.joining(", "));
2 of 3
1

You could group by condition and then remap:

public void booleanGrouping() throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("ala");
    strings.add("ela");
    strings.add("jan");

    strings.stream()
            .collect(
                    Collectors.groupingBy(s -> s.endsWith("a")) // using function Obj -> Bool not predicate
            ).entrySet()
            .stream()
            .collect(
                    Collectors.toMap(
                            e -> e.getKey() ? "Present" : "Past",
                            e -> e.getValue().stream().collect(Collectors.joining(""))
                    )
            );
}

First stream group by condition, you should use equivalentCourse.getNcourse() != null second remap collections from value to string. You could introduce:

enum PresentPast{
    Present, Past
    PresentPast is(boolean v){
         return v ? Present : Past
    }
}

and change e -> e.getKey() ? "Present" : "Past" to enum based solution.

Edit:

Solution for else if:

public Map<Classifier, String> booleanGrouping() throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("ala");
    strings.add("ela");
    strings.add("jan");
    // our ifs:
    /*
        if(!string.endsWith("n")){
        }else if(string.startsWith("e")){}

        final map should contains two elements
        endsWithN -> ["jan"]
        startsWithE -> ["ela"]
        NOT_MATCH -> ["ala"]

     */
    return strings.stream()
            .collect(
                    Collectors.groupingBy(Classifier::apply) // using function Obj -> Bool not predicate
            ).entrySet()
            .stream()
            .collect(
                    Collectors.toMap(
                            e -> e.getKey(),
                            e -> e.getValue().stream().collect(Collectors.joining(""))
                    )
            );
}

enum Classifier implements Predicate<String> {
    ENDS_WITH_N {
        @Override
        public boolean test(String s) {
            return s.endsWith("n");
        }
    },
    STARTS_WITH_E {
        @Override
        public boolean test(String s) {
            return s.startsWith("e");
        }
    }, NOT_MATCH {
        @Override
        public boolean test(String s) {
            return false;
        }
    };

    public static Classifier apply(String s) {
        return Arrays.stream(Classifier.values())
                .filter(c -> c.test(s))
                .findFirst().orElse(NOT_MATCH);
    }
}
Top answer
1 of 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...
}
2 of 2
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.

Find elsewhere
🌐
Code with Mosh
forum.codewithmosh.com › t › using-lambda-expressions-for-if-statements › 13119
Using lambda expressions for if statements - Code with Mosh Forum
June 17, 2022 - Hello all! First post here haha, I’ll get right to it :slight_smile: I was recently asked as a challenge to represent a validation method as a lambda expression and the implication was that this was somehow more effic…
🌐
Baeldung
baeldung.com › home › java › java streams › how to use if/else logic in java streams
How to Use if/else Logic in Java Streams | Baeldung
May 28, 2024 - Our forEach method contains if/else logic that verifies whether the Integer is an odd or even number using the Java modulus operator.
🌐
Java Code Geeks
javacodegeeks.com › home › core java
Lambda of Lambda, if/else from an Optional - Java Code Geeks
March 10, 2016 - So I got frustrated with two limitations of the Optional interface in JDK 8. The first problem is that there is no obvious way to perform an else operation in a block as there is only a isPresent method unless you are using an old school if statement. The second problem is of course the old chestnut that even if you could do that the methods would not be able to throw a checked exception. (Yes you can wrap with a RuntimeException but it is not the prettiest.) The workaround I found was to use the map function as the success case and the orElseGet to return the failure case. In both branches the code returns an instance of ThrowingRunnable by having a lambda return a lambda.
🌐
Stack Overflow
stackoverflow.com › questions › 33249601 › java-if-else-in-a-lambda-expression
if statement - Java if else in a lambda expression - Stack Overflow
October 21, 2015 - Note that this would not compile if permissions is a Map, because the signature of Map.put is not compliant. Another simplification (beyond those already mentioned by others): public void addPermission(String permission, String resource){ permissions.put(new Permission(permission, ()-> permission.charAt(permissions.size() - 1) == '*')); } The type of the given lambda should be a FunctionalInterface with no argument and result Boolean, e.g.
🌐
Tech with Maddy
techwithmaddy.com › java-8-lambda-expression
Lambda Expression in Java
August 16, 2021 - For example, if we want to avoid printing “apple”, we will have to add an if statement and, therefore, more code. So, what can you do instead? This is where a lambda expression can be of great help. You get the same output if you use a lambda expression instead of the for-each loop. import java.util.ArrayList; public class LambdaExpression { public static void main(String[] args) { ArrayList<String> fruits = new ArrayList<>(); fruits.add("Apple"); fruits.add("Mango"); fruits.add("Pear"); fruits.add("Grapes"); fruits.forEach((n) -> System.out.println(n)); } }
🌐
Stack Overflow
stackoverflow.com › questions › 37147457 › lambda-expression-if-else-statement
java - Lambda expression if-else statement - Stack Overflow
May 10, 2016 - Tunaki, I can't figure out how to do an Lamda Expression when its if-else statement, so I just want the example in Lamda Expression. YES ... Comparator<String> c = (String first, String second) -> { if (first.length() < second.length()) return -1; else if (first.length() > second.length()) return 1; else return 0; }; I believe this answers your question. For more info, read Java8 for really impatient.
🌐
Delft Stack
delftstack.com › home › howto › java › one line if statement java
Java One Line if Statement | Delft Stack
October 12, 2023 - The lambda expression checks if the string is equal to 1. If this condition is true, the string is allowed to pass through the filter; otherwise, it is discarded. Finally, the forEach method is used to iterate over the filtered stream and print ...
🌐
W3Schools
w3schools.com › java › java_conditions.asp
Java If ... Else
To avoid mistakes, always use curly braces { }. This makes it clear which lines belong to the if statement:
Top answer
1 of 2
2

If/else or even switch are not the "good OO design" answer. Neither are lambdas. Retrieving the status from somewhere, to make then a decision based on that - that is procedural programming; not OO.

You see, what you actually have in front of you - is a state machine. You have different states; and the point is: if your "thing" is in state A; then you want to do something ( invoke handleA() ). If your are in state B; you want to do something too ( like invoke handleB() ).

So, what you actually have is:

abstract class State {
  abstract void doIt();
...

StateA extends State {
  @Override
  void doIt() { handleA(); }

So, from the client side, you just call doIt() on same object of class State.

Thus: if you are really interested in improving your code base, learn how to use polymorphism to get rid of your if/else/switch statements.

You can watch this video to get an idea what I am talking about.

2 of 2
0

Maybe I hadn't fully explained my problem, but my colleague proposed another solution that I really like. He suggested I make the if-else block a java.util.Supplier, and invoke it in the Entity class where I need it.

So my code went from this block of logic sprinkled everywhere:

public class ServiceImpl {
  ...
  if (entity.getStatus) == 'A' then
    finalStatus = handleA();
  else if (entity.getStatus() == 'B') then
    finalStatus = handleB();
  else
    finalStatus = handleEverythingElse();
  ...
}

To this nicely compacted form:

public class ServiceImpl {
  finalStatus = entity.getFinalStatus(this::handleStatus);

  public int handleStatus() {
    return dao.getStatus();
  }
}

With the implementation in my Entity class:

public class Entity {
  public int handleStatus(Supplier<Integer> s) {
    int finalStatus;
    if (status) == 'A' then
      finalStatus = handleA();
    else if (status() == 'B') then
      finalStatus = handleB();
    else
      finalStatus = supplier.get();
    return status;
  }
}

I hope this make sense...