You can also do:
expectedPackageRepository.findById(1).ifPresent(
ep -> {
ep.setDateModified(new Date());
expectedPackageRepository.saveAndFlush(ep);
}
);
Ideally, you would also extract the part between brackets ({}) to a separate method. Then, you could write like this:
expectedPackageRepository.findById(1).ifPresent(this::doSomethingWithEp);
Where:
void doSomethingWithEp(ExpectedPackage ep) {
ep.setDateModified(new Date());
expectedPackageRepository.saveAndFlush(ep);
}
You can read the documentation of ifPresent here: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ifPresent-java.util.function.Consumer-
As it states, it will perform the specified action if the value is present and do nothing otherwise.
Answer from Poger on Stack OverflowYou can also do:
expectedPackageRepository.findById(1).ifPresent(
ep -> {
ep.setDateModified(new Date());
expectedPackageRepository.saveAndFlush(ep);
}
);
Ideally, you would also extract the part between brackets ({}) to a separate method. Then, you could write like this:
expectedPackageRepository.findById(1).ifPresent(this::doSomethingWithEp);
Where:
void doSomethingWithEp(ExpectedPackage ep) {
ep.setDateModified(new Date());
expectedPackageRepository.saveAndFlush(ep);
}
You can read the documentation of ifPresent here: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ifPresent-java.util.function.Consumer-
As it states, it will perform the specified action if the value is present and do nothing otherwise.
Yes, there are other approaches.
If you absolutely expect there always to be a value, then use Optional::orElseThrow to throw an Exception if a null appears.
If you expect a null to possibly arrive, and have an alternative instance available as a fall-back option, use Optional::orElse.
If the fall-back instance is not on hand, but you have a function to call to provide a fall-back instance, use Optional::orElseGet.
If you donβt care about receiving a null, and want to do nothing when a null arrives, use Optional::ifPresent. Pass the block of code to be run if a value arrives.
If you only care if a value arrives that meets some requirement, use Optional::filter. Pass a Predicate defining your requirement. For example, we care only if an Optional< String > contains text and that text has the word purple in it: myOptional.filter( s -> s.contains( "purple" ) ).ifPresent( this::print ) ;. If null received, our desired operation (a call to print in this example) never happens. If a value was received but failed to meet our predicate, our desired operation never happens.
Doing if( myOptional.isPresent() ) { SomeClass x = myOptional.get() ; β¦ } is valid, and safe. But this is not the original intent of Optional as it is basically the same as doing an old-fashioned null-check if ( null == x ) { β¦ }. The other methods on Optional provide a more clear and elegant way to express your intentions towards a possible null arriving.
Videos
Short Answer:
- orElse() will always call the given function whether you want it or not, regardless of
Optional.isPresent()value - orElseGet() will only call the given function when the
Optional.isPresent() == false
In real code, you might want to consider the second approach when the required resource is expensive to get.
// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource());
// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource())
For more details, consider the following example with this function:
public Optional<String> findMyPhone(int phoneId)
The difference is as below:
X : buyNewExpensivePhone() called
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| Optional.isPresent() | true | false |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| findMyPhone(int phoneId).orElse(buyNewExpensivePhone()) | X | X |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) | | X |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
When optional.isPresent() == false, there is no difference between two ways. However, when optional.isPresent() == true, orElse() always calls the subsequent function whether you want it or not.
Finally, the test case used is as below:
Result:
------------- Scenario 1 - orElse() --------------------
1.1. Optional.isPresent() == true (Redundant call)
Going to a very far store to buy a new expensive phone
Used phone: MyCheapPhone
1.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
------------- Scenario 2 - orElseGet() --------------------
2.1. Optional.isPresent() == true
Used phone: MyCheapPhone
2.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
Code:
public class TestOptional {
public Optional<String> findMyPhone(int phoneId) {
return phoneId == 10
? Optional.of("MyCheapPhone")
: Optional.empty();
}
public String buyNewExpensivePhone() {
System.out.println("\tGoing to a very far store to buy a new expensive phone");
return "NewExpensivePhone";
}
public static void main(String[] args) {
TestOptional test = new TestOptional();
String phone;
System.out.println("------------- Scenario 1 - orElse() --------------------");
System.out.println(" 1.1. Optional.isPresent() == true (Redundant call)");
phone = test.findMyPhone(10).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 1.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println("------------- Scenario 2 - orElseGet() --------------------");
System.out.println(" 2.1. Optional.isPresent() == true");
// Can be written as test::buyNewExpensivePhone
phone = test.findMyPhone(10).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 2.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
}
}
Take these two scenarios:
Optional<Foo> opt = ...
Foo x = opt.orElse( new Foo() );
Foo y = opt.orElseGet( Foo::new );
If opt doesn't contain a value, the two are indeed equivalent. But if opt does contain a value, how many Foo objects will be created?
P.s.: of course in this example the difference probably wouldn't be measurable, but if you have to obtain your default value from a remote web service for example, or from a database, it suddenly becomes very important.
This is part of JDK 9 in the form of method or, which takes a Supplier<Optional<T>>. Your example would then be:
return serviceA(args)
.or(() -> serviceB(args))
.or(() -> serviceC(args));
For details see the Javadoc, this post I wrote, or ticket JDK-8080418 where this method was introduced.
The cleanest βtry servicesβ approach given the current API would be:
Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
()->serviceA(args),
()->serviceB(args),
()->serviceC(args),
()->serviceD(args))
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
The important aspect is not the (constant) chain of operations you have to write once but how easy it is to add another service (or modify the list of services in general). Here, adding or removing a single ()->serviceX(args) is enough.
Due to the lazy evaluation of streams, no service will be invoked if a preceding service returned a non-empty Optional.
Starting with Java 9, you can simplify the code to
Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
()->serviceA(args),
()->serviceB(args),
()->serviceC(args),
()->serviceD(args))
.flatMap(s -> s.get().stream())
.findFirst();
though this answer already contains an even simpler approach for JDK 9.
JDK 16 offers the alternative
Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
()->serviceA(args),
()->serviceB(args),
()->serviceC(args),
()->serviceD(args))
.<Result>mapMulti((s,c) -> s.get().ifPresent(c))
.findFirst();
though this approach might be more convenient with service methods accepting a Consumer rather than returning a Supplier.
Your usage of nested ifPresent calls is very similar to the (nested) forEach calls on streams, seen in a lot of other questions.
They are a clear sign that you should try better on functional thinking.
What you want to do is
System.out.println(
Optional.ofNullable(userName) // will be an empty optional if userName is null
.map(Name::getName) // will turn to empty optional if getName returns null
.map("Name is: "::concat) // prepend "Name is: " (only when we have a name)
.orElse("No Name Found") // get the result string or the alternative
);
The important point to understand, is, that the mapping steps applied to an empty Optional donβt do anything but return an empty Optional again. Since you want to print in either case, the print statement is not passed as consumer, but written as stand-alone statement, printing the value returned by the orElse invocation, which will be either, the non-null result of the processing steps or the alternative String.
The orElse method allows you to return an alternative value when there isn't one in the Optional.
If you just want to print out an alternative String you can use the orElse method to return an alternative String:
Optional<String> optionalNameString = Optional.ofNullable(value.getName());
System.out.println(optionalNameString.orElse("Name is not present"));
Otherwise you can just check if the value is present using isPresent()
Optional<String> optionalNameString = Optional.ofNullable(value.getName());
if(optionalNameString.isPresent()) {
// do something
} else {
//do something else
}