Java stream ifPresent orElse /orElseGet - java

Hello What am I doing wrong here
I want to get the foundation Id , if its not present then get Insurance Type.. the code snippets are pasted below .. but I get an error at the orElse part I even tried orElseGet() ...It says "target type of Lambda must be an interface"..
String type = getFoundationId(companyInsurances).orElse(()->getInsuranceType(insurance, companyInsurances));
…
private Optional<String> getInsuranceType(Insurance insurance, List<CompanyInsurance> companyInsurances) {
return InsurancePeriodHelper.findFirstCompanyInsuranceOfType(companyInsurances, CompanyInsuranceType.POLICY_HOLDER.getValue())
.map(companyInsurance-> insurance.getProduct());
}
private Optional<String> getFoundationId(List<CompanyInsurance> companyInsurances) {
return InsurancePeriodHelper.findFirstCompanyInsuranceOfType(companyInsurances, CompanyInsuranceType.FOUNDATION.getValue())
.map(companyInsurance -> companyInsurance.getCompany().getFoundationIdentifier().toString());
}

With Java-9 and above you could simply chain such Optionals using Optional.or as:
String type = getFoundationId(companyInsurances)
.or(() -> getInsuranceType(insurance, companyInsurances))
.orElse("defaultValue");

Related

Java 8 - Optional<CustomizedObject> get first element of the list within CustomizedObject

I am not sure how to do this
class Department {
String deptName;
List<Person> employees;
}
class Person {
String personName;
}
The problem statement is to fetch the first name of the person working in a particular department.
This department can be optional. So this is how my method looks -
String getFirstPerson(Optional<Department> department, String defaultName) {
// TODO:
}
I know the traditional way of doing this but would like to see some Java 8 + lambda way to simplify this.
Still a newbie here - so please pardon if I am not using the correct format.
I also have a default name to use in case we dont find that value.
P.S. I know it is not best practice to send Optional as method parameter. This is not the actual code. I am just trying to simplify it.
You can use the map function on Optional to get the employees list and then use stream get the first name or return defaultName. Even incase if Optional is empty you will get the defaultName
String getFirstPerson(Optional<Department> department, String defaultName) {
return department.map(d->d.getEmployees().stream().map(Person::getPersonName).findFirst().orElse(defaultName)).orElse(defaultName));
}
If you have a chance of getting null on getEmployees you can use below approach
department.map(Department::getEmployees)
.filter(Objects::nonNull)
.map(emp->emp.stream().map(Person::getPersonName).findFirst().orElse(defaultName)).orElse(defaultName)
A simplified way of doing that could be using emptyList for absent department or nullable employees:
String getFirstPerson(Optional<Department> department, String defaultName) {
return department.map(Department::getEmployees)
.orElse(Collections.emptyList()) // get rid of this ensuring non null List
.stream()
.map(Person::getPersonName)
.findFirst()
.orElse(defaultName);
}
Actually in:
department.map(Department::getEmployees)
.filter(Objects::nonNull)
.map(emp->emp.stream().map(Person::getPersonName).findFirst().orElse(defaultName)).orElse(defaultName)
we don't have to check non null since .map(Department::getEmployees) will return Optional.empty() if employees are null. See Optional documentation.
Correct answer would be without redundant filter:
department.map(Department::getEmployees)
.map(emp->emp.stream().map(Person::getPersonName).findFirst().orElse(defaultName)).orElse(defaultName)
Or alternatively:
department.map(Department::getEmployees)
.map(List::stream)
.map(Stream::findFirst)
.flatMap(Functions.identity())
.map(Person::getPersonName)
.orElse(defaultName);

Java optional: map to subclass or else super class

I am trying to re-write a scala example of a POC project from Manning's "Akka in Action" in Java. The project is a small Http server for creating events and buying tickets.
I am at a point when an actor can send an Optional<Event> to my RestApi. Depending on whether the value is present I should complete the call with OK, else NOT_FOUND.
In Scala the snippet looks as follow:
get {
// GET /events/:event
onSuccess(getEvent(event)) {
_.fold(complete(NotFound))(e => complete(OK, e))
}
}
...where getEvent returns an Option[Event] (equivalent of java's Optional<Event>). This is how I rewrote it in Java:
get(() -> onSuccess(() -> getEvent(event), eventGetRoute()))
...
//and eventGetRoute() is a function:
private Function<Optional<Event>, Route> eventGetRoute() {
return maybeEvent -> maybeEvent.map(event -> complete(OK, event, Jackson.marshaller())).orElseGet(() -> complete(NOT_FOUND));
}
This doesn't compile: Bad return type in lambda expression: Route cannot be converted to RouteAdapter. The longer (and first) complete returns a RouteAdapter and the second one returns a Route. If I re-write the above function like this:
private Function<Optional<Event>, Route> eventGetRoute() {
return maybeEvent -> {
if(maybeEvent.isPresent()) {
return complete(OK, maybeEvent.get(), Jackson.marshaller());
}
return complete(NOT_FOUND);
};
}
...then the compiler doesn't complain, but then it is not right way to map an Optional.
Java doesn't have fold method for Optional (not in SE8 at least), which allows passing the fallback-to value first.
I'm curious whether it is possible to write this function in respecting functional style.
Update:
As asked in the comments, these are the signatures of the complete methods from akka-http javadsl library:
def complete(status: StatusCode): Route = RouteAdapter(
D.complete(status.asScala))
and
def complete[T](status: StatusCode, value: T, marshaller: Marshaller[T, RequestEntity]) = RouteAdapter {
D.complete(ToResponseMarshallable(value)(fromToEntityMarshaller(status.asScala)(marshaller)))
}
What is return type of complete(OK, maybeEvent.get(), Jackson.marshaller())?
I assume RouteAdapter. If so cast it to Route so chain will be binded to Route not RouteAdaper and at the end will not have troubles with casting from super class to subclass.

Java Optional return value only if present

Is it possible to return the Optional value from method only if it's present, but if it's not just continue with a normal method flow. Something like this:
public Message processMessage(Message message) {
// ErrorMessage is subclass of Message; only returned if validator found some violations, otherwise empty optional
Optional<ErrorMessage> error = validator.validate(message);
if (error.isPresent()) return error.get();
// returns different possible subclasses of Message
return service.processMessage(message);
}
Is there any prettier way to write this?
Your problem is indeed that the return types do not match. orElseGet only works when the supplier returns a subtype of the Optional type.
To work around this, you can force a cast to the parent type first:
return error.<Message>map(m -> m).orElseGet(() -> service.processMessage(message));
or equivalently:
return error.map(m -> (Message) m).orElseGet(() -> service.processMessage(message));
I simply would go with Optional.orElseGet and an explicit cast in between:
public Message processMessage(final Message message) {
return validator.validate(message)
.map(Message.class::cast)
.orElseGet(() -> service.processMessage(message));
}
I am not able to test it currently but it may give u an idea, may be you can implement something like below
return Optional.ofNullable(message)
.map(validator::validate)
.orElseGet(service::processMessage)
Looking at that snippet, it looks like the validate method on the validator doesn't quite have the proper return type. Consider using e.g. io.vavr.control.Either or io.vavr.control.Validation monad. Take a look at a possible signature for validate:
Either<SpecificError, ? extends Message> validate(Message message);
Now the map and fold combinators can be used like so:
validator
.validate(message)
.map(message -> service.processMessage(message))
.fold(error -> new ErrorMessage(error), success -> success); // the left function can be replaced by Function.identity()
to yield Message.

How to use Java 8 Optionals, performing an action if all three are present?

I have some (simplified) code that uses Java Optionals:
Optional<User> maybeTarget = userRepository.findById(id1);
Optional<String> maybeSourceName = userRepository.findById(id2).map(User::getName);
Optional<String> maybeEventName = eventRepository.findById(id3).map(Event::getName);
maybeTarget.ifPresent(target -> {
maybeSourceName.ifPresent(sourceName -> {
maybeEventName.ifPresent(eventName -> {
sendInvite(target.getEmail(), String.format("Hi %s, $s has invited you to $s", target.getName(), sourceName, meetingName));
}
}
}
Needless to say, this looks and feels bad. But I can't think of another way to do this in a less-nested and more readable way. I considered streaming the 3 Optionals, but discarded the idea as doing a .filter(Optional::isPresent) then a .map(Optional::get) feels even worse.
So is there a better, more 'Java 8' or 'Optional-literate' way of dealing with this situation (essentially multiple Optionals all needed to compute a final operation)?
I think to stream the three Optionals is an overkill, why not the simple
if (maybeTarget.isPresent() && maybeSourceName.isPresent() && maybeEventName.isPresent()) {
...
}
In my eyes, this states the conditional logic more clearly compared to the use of the stream API.
Using a helper function, things at least become un-nested a little:
#FunctionalInterface
interface TriConsumer<T, U, S> {
void accept(T t, U u, S s);
}
public static <T, U, S> void allOf(Optional<T> o1, Optional<U> o2, Optional<S> o3,
TriConsumer<T, U, S> consumer) {
o1.ifPresent(t -> o2.ifPresent(u -> o3.ifPresent(s -> consumer.accept(t, u, s))));
}
allOf(maybeTarget, maybeSourceName, maybeEventName,
(target, sourceName, eventName) -> {
/// ...
});
The obvious downside being that you'd need a separate helper function overload for every different number of Optionals
How about something like this
if(Stream.of(maybeTarget, maybeSourceName,
maybeEventName).allMatch(Optional::isPresent))
{
sendinvite(....)// do get on all optionals.
}
Having said that. If your logic to find in database is only to send mail, then if maybeTarget.ifPresent() is false, then there is no point to fetch the other two values, ain't it?. I am afraid, this kinda logic can be achieved only through traditional if else statements.
Since the original code is being executed for its side effects (sending an email), and not extracting or generating a value, the nested ifPresent calls seem appropriate. The original code doesn't seem too bad, and indeed it seems rather better than some of the answers that have been proposed. However, the statement lambdas and the local variables of type Optional do seem to add a fair amount of clutter.
First, I'll take the liberty of modifying the original code by wrapping it in a method, giving the parameters nice names, and making up some type names. I have no idea if the actual code is like this, but this shouldn't really be surprising to anyone.
// original version, slightly modified
void inviteById(UserId targetId, UserId sourceId, EventId eventId) {
Optional<User> maybeTarget = userRepository.findById(targetId);
Optional<String> maybeSourceName = userRepository.findById(sourceId).map(User::getName);
Optional<String> maybeEventName = eventRepository.findById(eventId).map(Event::getName);
maybeTarget.ifPresent(target -> {
maybeSourceName.ifPresent(sourceName -> {
maybeEventName.ifPresent(eventName -> {
sendInvite(target.getEmail(), String.format("Hi %s, %s has invited you to %s",
target.getName(), sourceName, eventName));
});
});
});
}
I played around with different refactorings, and I found that extracting the inner statement lambda into its own method makes the most sense to me. Given source and target users and an event -- no Optional stuff -- it sends mail about it. This is the computation that needs to be performed after all the optional stuff has been dealt with. I've also moved the data extraction (email, name) in here instead of mixing it with the Optional processing in the outer layer. Again, this makes sense to me: send mail from source to target about event.
void setupInvite(User target, User source, Event event) {
sendInvite(target.getEmail(), String.format("Hi %s, %s has invited you to %s",
target.getName(), source.getName(), event.getName()));
}
Now, let's deal with the optional stuff. As I said above, ifPresent is the way to go here, since we want to do something with side effects. It also provides a way to "extract" the value from an Optional and bind it to a name, but only within the context of a lambda expression. Since we want to do this for three different Optionals, nesting is called for. Nesting allows names from outer lambdas to be captured by inner lambdas. This lets us bind names to values extracted from the Optionals -- but only if they're present. This can't really be done with a linear chain, since some intermediate data structure like a tuple would be necessary to build up the partial results.
Finally, in the innermost lambda, we call the helper method defined above.
void inviteById(UserId targetId, UserId sourceID, EventId eventId) {
userRepository.findById(targetId).ifPresent(
target -> userRepository.findById(sourceID).ifPresent(
source -> eventRepository.findById(eventId).ifPresent(
event -> setupInvite(target, source, event))));
}
Note that I've inlined the Optionals instead of holding them in local variables. This reveals the nesting structure a bit better. It also provides for "short-circuiting" of the operation if one of the lookups doesn't find anything, since ifPresent simply does nothing on an empty Optional.
It's still a bit dense to my eye, though. I think the reason is that this code still depends on some external repositories on which to do the lookups. It's a bit uncomfortable to have this mixed together with the Optional processing. A possibility is simply to extract the lookups into their own methods findUser and findEvent. These are pretty obvious so I won't write them out. But if this were done, the result would be:
void inviteById(UserId targetId, UserId sourceID, EventId eventId) {
findUser(targetId).ifPresent(
target -> findUser(sourceID).ifPresent(
source -> findEvent(eventId).ifPresent(
event -> setupInvite(target, source, event))));
}
Fundamentally, this isn't that different from the original code. It's subjective, but I think I prefer this to the original code. It has the same, fairly simple structure, although nested instead of the typical linear chain of Optional processing. What's different is that the lookups are done conditionally within Optional processing, instead of being done up front, stored in local variables, and then doing only conditional extraction of Optional values. Also, I've separated out data manipulation (extraction of email and name, sending of message) into a separate method. This avoids mixing data manipulation with Optional processing, which I think tends to confuse things if we're dealing with multiple Optional instances.
I think you should consider taking another approach.
I'd start by not issuing the three calls to the DB at the beginning. Instead, I'd issue the 1st query and only if the result is present, I'd issue the 2nd one. I'd then apply the same rationale with regard to the 3rd query and finally, if the last result is also present, I'd send the invite. This would avoid unnecessary calls to the DB when either one of the first two results is not present.
In order to make the code more readable, testable and maintainable, I'd also extract each DB call to its own private method, chaining them with Optional.ifPresent:
public void sendInvite(Long targetId, Long sourceId, Long meetingId) {
userRepository.findById(targetId)
.ifPresent(target -> sendInvite(target, sourceId, meetingId));
}
private void sendInvite(User target, Long sourceId, Long meetingId) {
userRepository.findById(sourceId)
.map(User::getName)
.ifPresent(sourceName -> sendInvite(target, sourceName, meetingId));
}
private void sendInvite(User target, String sourceName, Long meetingId) {
eventRepository.findById(meetingId)
.map(Event::getName)
.ifPresent(meetingName -> sendInvite(target, sourceName, meetingName));
}
private void sendInvite(User target, String sourceName, String meetingName) {
String contents = String.format(
"Hi %s, $s has invited you to $s",
target.getName(),
sourceName,
meetingName);
sendInvite(target.getEmail(), contents);
}
You can use the following if you want to stick to Optional and not commit to consuming the value immediately. It makes use of Triple<L, M, R> from Apache Commons:
/**
* Returns an optional contained a triple if all arguments are present,
* otherwise an absent optional
*/
public static <L, M, R> Optional<Triple<L, M, R>> product(Optional<L> left,
Optional<M> middle, Optional<R> right) {
return left.flatMap(l -> middle.flatMap(m -> right.map(r -> Triple.of(l, m, r))));
}
// Used as
product(maybeTarget, maybeSourceName, maybeEventName).ifPresent(this::sendInvite);
One could imagine a similar approach for two, or multiple Optionals, although java unfortunately doesn't have a general tuple type (yet).
The first approach is not perfect (it does not support laziness - all 3 database calls will be triggered anyway):
Optional<User> target = userRepository.findById(id1);
Optional<String> sourceName = userRepository.findById(id2).map(User::getName);
Optional<String> eventName = eventRepository.findById(id3).map(Event::getName);
if (Stream.of(target, sourceName, eventName).anyMatch(obj -> !obj.isPresent())) {
return;
}
sendInvite(target.get(), sourceName.get(), eventName.get());
The following example is a little bit verbose, but it supports laziness and readability:
private void sendIfValid() {
Optional<User> target = userRepository.findById(id1);
if (!target.isPresent()) {
return;
}
Optional<String> sourceName = userRepository.findById(id2).map(User::getName);
if (!sourceName.isPresent()) {
return;
}
Optional<String> eventName = eventRepository.findById(id3).map(Event::getName);
if (!eventName.isPresent()) {
return;
}
sendInvite(target.get(), sourceName.get(), eventName.get());
}
private void sendInvite(User target, String sourceName, String eventName) {
// ...
}
Well I took the same approach of Federico to only call the DB when needed, it's quite verbose too, but lazy. I also simplified this a bit. Considering you have these 3 methods:
public static Optional<String> firstCall() {
System.out.println("first call");
return Optional.of("first");
}
public static Optional<String> secondCall() {
System.out.println("second call");
return Optional.empty();
}
public static Optional<String> thirdCall() {
System.out.println("third call");
return Optional.empty();
}
I've implemented it like this:
firstCall()
.flatMap(x -> secondCall().map(y -> Stream.of(x, y))
.flatMap(z -> thirdCall().map(n -> Stream.concat(z, Stream.of(n)))))
.ifPresent(st -> System.out.println(st.collect(Collectors.joining("|"))));
You can create an infrastructure to handle a variable amount of inputs. For this to be a good design though, your inputs should not be Optional<?>; but Supplier<Optional<?>> so you can short-circuit the unnecessary evaluation of Optionals while trying to determine whether or not all are present.
Because of this, it'd be better to create a utility wrapper around your Optionals that provides transparent access to the evaluated value using a singleton pattern, like the following:
class OptionalSupplier {
private final Supplier<Optional<?>> optionalSupplier;
private Optional<?> evaluatedOptional = null;
public OptionalSupplier(Supplier<Optional<?>> supplier) {
this.optionalSupplier = supplier;
}
public Optional<?> getEvaluatedOptional() {
if (evaluatedOptional == null)
evaluatedOptional = optionalSupplier.get();
return evaluatedOptional;
}
}
Then you can create another class that handles a List of these wrappers and provides a programmatic API to execute a Function that takes as parameters the evaluated values of the actual optionals, hiding further the users involvement in the process. You can overload the method to execute a Consumer with the same parameters. Such class would look something like this:
class OptionalSemaphores {
private List<OptionalSupplier> optionalSuppliers;
private List<Object> results = null;
private boolean allPresent;
public OptionalSemaphores(Supplier<Optional<?>>... suppliers) {
optionalSuppliers = Stream.of(suppliers)
.map(OptionalSupplier::new)
.collect(Collectors.toList());
allPresent = optionalSuppliers.stream()
.map(OptionalSupplier::getEvaluatedOptional)
.allMatch(Optional::isPresent);
if (allPresent)
results = optionalSuppliers.stream()
.map(OptionalSupplier::getEvaluatedOptional)
.map(Optional::get)
.collect(Collectors.toList());
}
public boolean isAllPresent() {
return allPresent;
}
public <T> T execute(Function<List<Object>, T> function, T defaultValue) {
return (allPresent) ? function.apply(results) : defaultValue;
}
public void execute(Consumer<List<Object>> function) {
if (allPresent)
function.accept(results);
}
}
Finally all you have left to do is to create objects of this class (OptionalSemaphores) using Suppliers of your Optionals (Supplier<Optional<?>>) and invoking any of the overloaded execute methods to run (IF all Optionals are present) with a List containing the corresponding evaluated values from your Optionals. The following is a full working demo of this:
public class OptionalsTester {
public static void main(String[] args) {
Supplier<Optional<?>> s1 = () -> Optional.of("Hello");
Supplier<Optional<?>> s2 = () -> Optional.of(1L);
Supplier<Optional<?>> s3 = () -> Optional.of(55.87);
Supplier<Optional<?>> s4 = () -> Optional.of(true);
Supplier<Optional<?>> s5 = () -> Optional.of("World");
Supplier<Optional<?>> failure = () -> Optional.ofNullable(null);
Supplier<Optional<?>> s7 = () -> Optional.of(55);
System.out.print("\nFAILING SEMAPHORES: ");
new OptionalSemaphores(s1, s2, s3, s4, s5, failure, s7).execute(System.out::println);
System.out.print("\nSUCCESSFUL SEMAPHORES: ");
new OptionalSemaphores(s1, s2, s3, s4, s5, s7).execute(System.out::println);
}
static class OptionalSemaphores {
private List<OptionalSupplier> optionalSuppliers;
private List<Object> results = null;
private boolean allPresent;
public OptionalSemaphores(Supplier<Optional<?>>... suppliers) {
optionalSuppliers = Stream.of(suppliers)
.map(OptionalSupplier::new)
.collect(Collectors.toList());
allPresent = optionalSuppliers.stream()
.map(OptionalSupplier::getEvaluatedOptional)
.allMatch(Optional::isPresent);
if (allPresent)
results = optionalSuppliers.stream()
.map(OptionalSupplier::getEvaluatedOptional)
.map(Optional::get)
.collect(Collectors.toList());
}
public boolean isAllPresent() {
return allPresent;
}
public <T> T execute(Function<List<Object>, T> function, T defaultValue) {
return (allPresent) ? function.apply(results) : defaultValue;
}
public void execute(Consumer<List<Object>> function) {
if (allPresent)
function.accept(results);
}
}
static class OptionalSupplier {
private final Supplier<Optional<?>> optionalSupplier;
private Optional<?> evaluatedOptional = null;
public OptionalSupplier(Supplier<Optional<?>> supplier) {
this.optionalSupplier = supplier;
}
public Optional<?> getEvaluatedOptional() {
if (evaluatedOptional == null)
evaluatedOptional = optionalSupplier.get();
return evaluatedOptional;
}
}
}
Complete code on GitHub
Hope this helps.
If you treat Optional just as a marker for method return values, the code becomes very simple:
User target = userRepository.findById(id1).orElse(null);
User source = userRepository.findById(id2).orElse(null);
Event event = eventRepository.findById(id3).orElse(null);
if (target != null && source != null && event != null) {
String message = String.format("Hi %s, %s has invited you to %s",
target.getName(), source.getName(), event.getName());
sendInvite(target.getEmail(), message);
}
The point of Optional is not that you must use it everywhere. Instead, it serves as a marker for method return values to inform the caller to check for absentness. In this case, the orElse(null) takes care of this, and the calling code is fully concious about the possible nullness.
return userRepository.findById(id)
.flatMap(target -> userRepository.findById(id2)
.map(User::getName)
.flatMap(sourceName -> eventRepository.findById(id3)
.map(Event::getName)
.map(eventName-> createInvite(target, sourceName, eventName))))
First of all you return an Optional as well. It's better to have a method first that creates an invite, which you can call and then send if it's not empty.
Among other things, it's easier to test. Using flatMap you also get the benefit of laziness, since if the first result is empty, nothing else will be evaluated.
When you want to use multiple optionals, you always should use a combination of map and flatMap.
I'm also not using target.getEmail() and target.getName(), those should be safely extracted in createInvite method, since I don't know if they can be nulls or not.
Keeping in mind that Exceptions should not be used in this fashion,
for conciseness you can consider as well:
try {
doSomething( optional1.get(), optional2.get(), optional3.get() );
} catch( NoSuchElementException e ) {
// report, log, do nothing
}
Remember, you can define Classes and Records inline to keep the state explicit and flattened vs. nested using callbacks/closures. It might seem a bit overkill for a small example like this, but it really helps when each nested 'chain' ends up doing work.
For example, given your 3 Optionals using lombok:
#Value #With class Temp {User target; String source; String eventName;}
maybeTarget
.map(target -> new Temp(target, null, null))
.flatMap(tmp -> maybeSourceName.map(tmp::withSource))
.flatMap(tmp -> maybeEventName.map(tmp::withEventName))
.ifPresent(tmp -> System.out.printf("Hi %s, %s has invited you to %s%n", tmp.target.getName(), tmp.source, tmp.eventName));
You can do the same w/records but you'll have to do a bit more work since you have to copy everything by hand:
record TempRecord(User target, String source, String eventName) {}
maybeTarget
.map(target -> new TempRecord(target, null, null))
.flatMap(tmp -> maybeSourceName.map(source -> new TempRecord(tmp.target, source, null)))
.flatMap(tmp -> maybeEventName.map(eventName -> new TempRecord(tmp.target, tmp.source, eventName)))
.ifPresent(tmp -> System.out.printf("Hi %s, %s has invited you to %s%n", tmp.target.getName(), tmp.source, tmp.eventName));
I've tried to keep the data immutable and functions pure.

Java 8 Optional instead of if

I have problem with Optional and I don't know how to handle it.
public void check(String name) {
if (name != null)
doSomething(name);
else
doMore();
}
How to change this if into Optional?
There is a very neat method for that, but present in jdk-9...
public void check(String name){
Optional.ofNullable(name)
.ifPresentOrElse(YourClass::doSomething, YourClass::doMore);
}
assuming doSomething and doMore are static methods... If not an instance should be used, like this::doSomething or this::doMore
While there certainly is a way to create the same code using Optionals (e.g. see Eugene's answer) you should not use Optionals here (imho).
Either you would get the Optional passed into your method which creates a overhead for the caller and does not really make sense looking at why / for what use case Optional was introduced.
Or you would create the Optional yourself inside the method. That is more "okay" but very cumbersome, obscures what is actually happening and I would request it to be changed if I came across it during a code review. Just compare the snippet using an Optional and your current code - your code is probably shorter in terms of characters, it is obvious what is happening. The only upside of using Optionals here is that it seems to become a one-liner which is firstly nothing that is more important than readability and furthermore it is something you could achieve without it anyway if you would add some braces.
Bottom line: Your code is perfectly fine as it is.
There is no reason to change your implementation. There is no way to do what you want in java 8 with an Optional without having an if, while respecting the idea of not using 'map' for side-effects.
I mean, you could have
public void check(String name) {
Optional<String> nameOpt = Optional.ofNullable(name);
nameOpt.ifPresent(n -> doSomething(n));
if (!nameOpt.isPresent()) {
doMore();
}
}
but that has no sense. here you have a good article what Optional tries to resolve (and hence for what it's meant to be used): mainly for return types. Other stuff is just overusing it.
You can avoid if statement by utilizing Java 8 Optional.map() and Optional.orElseGet() methods. Check following example:
import java.util.Optional;
import java.util.function.Consumer;
final class OptionalTestMain {
public static void main(String[] args) {
check("test", str -> {
System.out.println("Yay, string is not null!");
System.out.println("It's: " + str);
}, () -> {
System.out.println("Crap, string is a null...");
System.out.println("There is nothing for me to do.");
});
check(null, str -> {
System.out.println("Yay, string is not null!");
System.out.println("It's: " + str);
}, () -> {
System.out.println("Crap, string is a null...");
System.out.println("There is nothing for me to do.");
});
}
static void check(String str, Consumer<String> ifPresent, Runnable ifNotPresent) {
Optional.ofNullable(str)
.map(s -> { ifPresent.accept(s); return s; })
.orElseGet(() -> { ifNotPresent.run(); return null; });
}
}
It will produce following output:
Yay, string is not null!
It's: test
Crap, string is a null...
There is nothing for me to do.
Method check expects 3 parameters:
a String (it may be null)
a Consumer lambda expression that does something with this value and does not mutate input value.
a Runnable lambda with no parameters to do something when input String is null.
Of course you could easily modify following method and then utilize the whole potential of Optional class, e.g.:
static String checkAndReturn(String str, Function<String, String> ifPresent, Supplier<String> ifNotPresent) {
return Optional.ofNullable(str)
.map(ifPresent)
.orElseGet(ifNotPresent);
}
Then:
System.out.println(checkAndReturn("test", String::toUpperCase, () -> "no value"));
System.out.println(checkAndReturn(null, String::toUpperCase, () -> "no value"));
will produce following output:
TEST
no value
I hope it helps.

Categories