Search code examples
javajava-8java-streamoption-typepredicate

How to apply a condition only if an optional is present?


I have an Optional<LocalDate> object and a Stream of other dates.

Stream<LocalDate> dates = ...;   
Optional<LocalDate> dateOptional = ...;

I would like to filter out all dates which are after the optional. If the optional is not present, the filter should not do anything.

I have written the Predicate like this:

Predicate<LocalDate> predicate = date -> !dateOptional.isPresent() || !date.isAfter(dateOptional.get());  
Stream<LocalDate> filteredStream = dates.filter(predicate);

I would like to avoid using isPresent() and get(). Is there a more functional way of writing the same logic? I am using Java 8.


Solution

  • The point is that the Predicate<T> must return an expression that always results in a boolean.

    Since the Localdate::isAfter returns boolean you can use is with the advantage of Optional inside the Predicate<LocalDate> and result in boolean:

    Optional<LocalDate> dateOptional = ...;
                                                            // Together Predicate<LocalDate>
    Predicate<LocalDate> predicate = date -> dateOptional   // .. Optional<LocalDate>
         .map(d -> !date.isAfter(d))                        // .. Optional<Boolean>
         .orElse(true);                                     // .. Boolean
    
    
    Stream<LocalDate> filteredStream = dates.filter(predicate);
    

    Don't forget, the Stream<LocalDate> remains open until the terminal operation.


    Edit: Thanks to @Holger: The whole predicate might be optimized to avoid repetitively and unnecessary calls:

    Predicate<LocalDate> predicate = dateOptional                 // Optional<LocalDate>
        .<Predicate<LocalDate>>map(d -> date -> !date.isAfter(d)) // Optional<Predicate<LocalDate>>
        .orElse(date -> true);                                    // Predicate<LocalDate>