Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine Java 8 Optionals with conditional AND

My Problem is I have two or more Optionals wrapping different types. I want to perform an operation which only can be performed if all optionals are not empty.

Currently Im doing it this way:

    Optional<PatientCase> caseOptional = patientCaseRepository.findOneById(caseId);
    Optional<User> userOptional = userRepository.findOneById(caseId);

    if(userOptional.isPresent() && caseOptional.isPresent()) {
        caseOptional.get().getProcess().setDesigner(userOptional.get());
    }

In my opinion the if condition does not feel right. I know it is possible to chain Optionals using orElse. But in my case I don't want a logical Else. Is there a way to create and AND Operator in order to combine two or more Optionals similar to this PSEUDO code ?

caseOptional.and.userOptional.ifPresent((theCase,user) -> //Perform Stuff);
like image 557
TardigradeX Avatar asked Sep 23 '16 08:09

TardigradeX


2 Answers

There is a logical AND operation, but there is no (simple) way to turn it into a two-value Optional, in other words, this (again) suffers from the absence of pair or tuple types. E.g.

caseOptional.flatMap(theCase -> userOptional
        .map(user -> new AbstractMap.SimpleEntry<>(theCase, user)))
    .ifPresent(e -> e.getKey().getProcess().setDesigner(e.getValue()));

which uses AbstractMap.SimpleEntry as stand-in for the absent tuple type.

An alternative would be be using a singleton map as pair:

caseOptional.flatMap(theCase -> userOptional
        .map(user -> Collections.singletonMap(theCase, user)))
    .ifPresent(m -> m.forEach((c, u) -> c.getProcess().setDesigner(u)));

But in this specific case, you may use the simpler

caseOptional.map(PatientCase::getProcess)
            .ifPresent(p -> userOptional.ifPresent(p::setDesigner));

or

caseOptional.ifPresent(c -> userOptional.ifPresent(u -> c.getProcess().setDesigner(u)));

instead.

like image 62
Holger Avatar answered Nov 09 '22 22:11

Holger


There is no direct way.

Stram allMatch will work like ifPresent for many optionals:

Stream.of(optional1, optional2, ...).allMatch(Optional::isPresent)
like image 34
Sergei Rybalkin Avatar answered Nov 09 '22 23:11

Sergei Rybalkin