How to use Java Optional to elegantly replace Ternary operators - java

A super simple question:
Here's my plain Java code using traditional ternary operator ?
public DateTime getCreatedAt() {
return !recordA.isPresent() ? recordB.get().getCreatedAt() : recordA.get().getCreatedAt();
}
My best bet is following:
public DateTime getCreatedAt() {
return recordA.map(
record -> record.getCreatedAt())
.orElse(recordB.get().getCreatedAt());
}
This could compile, but looks like it's not behaving correctly.
It always executes both branches, for e.g. when recordA isPresent(), it still executes recordB.get().getCreatedAt() which throws me
java.util.NoSuchElementException: No value present
Any help is appreciated!
Basically, I'd like to replace the traditional ternary operator with more advanced Optional/lamda features.

To avoid eagerly evaluating else-branches, use orElseGet, which takes an instance of the functional interface Supplier:
return recordA.map(
record -> record.getCreatedAt())
.orElseGet(() -> recordB.get().getCreatedAt());

You're looking for .orElseGet(() -> recordB.get().getCreatedAt()); and the reason to that can be found on this post --> Difference between Optional.orElse() and Optional.orElseGet()
Some people may find it a bit subjective but personally, I'd say by default, it makes more sense to use orElseGet() as opposed to orElse every time except in the case where the default object is already constructed as this will prevent many unexpected problems (given you didn't read the differences between orElse and orElseGet doc) as such of the one you're facing now.
read more from Java Optional – orElse() vs orElseGet()

My question about recordB being Optional got unanswered but if it is Optional then you cannot just safely call its get method, you need to check if it is empty or not. Here safe call to get record or null if both recordA and recordB are empty Otionals.
recordA
.map(Record::getCreatedAt)
.orElseGet( () -> recordB.map(Record::getCreatedAt).orElse(null) );

If you are using Java 9+, you may be able to use ifPresentOrElse() method as more completely explained in this Stackoverflow answer.
recordA.ifPresentOrElse(
value -> recordA.get().getCreatedAt(),
() -> recordB.get().getCreatedAt()
);

Related

Is there any Java Functional approach to avoid cascaded NonNull Checks

I have gone through several null check related questions in Java and the best practices around it.
After long search , I can see Objects.nonNull () serves the purpose though it looks Orange instead of Apple.
Now i have a following check using Objects.nonNull() and short-circuiting logical AND.
if (Objects.nonNull (obj1) &&
Objects.nonNull (obj1.getObj2()) &&
Objects.nonNull (obj1.getObj2().getObj3 ())
{
obj1.getObj2().getObj3().doSomething();
}
I find it is more redundant and less readable when i clearly know my intention.
Is there any other approach to handle it in functional way to assert the non null state of the deeper object without facing Null pointer exception.
Using !=null is the normal way to do null-checks, but here's an alternative way that allows you to chain them using Optional.
Optional.ofNullable(obj1).map(class1::getObj2)
.map(class2::getObj3)
.ifPresent(class3::doSomething);
and you can use a lambda expression in place of any of the method references if the code you want to execute is not a simple function call.
Optional.ofNullable(obj1).map(x -> x.getObj2())
.map(x -> x.getObj3())
.ifPresent(x -> {
System.out.println("Now I can use my obj3 "+x);
});

Optional isPresent vs orElse(null)

I was updating the dependencies to Spring 5 in my project and was bombarded with compilation errors where the method definition of findOne() has been replaced by findById() which now returns an Optional (correct me if I am wrong).
While refactoring, I came across multiple approaches that I can choose to adopt, and I would therefore like some input on which one is to be preferred.
1st approach:
ExpectedPackage ep = expectedPackageRepository.findById(1).orElse(null);
if(ep != null){
ep.setDateModified(new Date());
expectedPackageRepository.saveAndFlush(ep);
}
2nd approach:
Optional<ExpectedPackage> ep = expectedPackageRepository.findById(1);
if(ep.isPresent()){
ep.get().setDateModified(new Date());
expectedPackageRepository.saveAndFlush(ep.get());
}
Or is there a third and better approach that I have missed? I went through several questions and a couple of articles, but I did not find a clear answer.
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.
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.
The other answer is basically some refactoring of your second approach, which has nothing wrong per-se, it's just a matter of style. Of course chaining and extraction to a separate method will make this a lot more readable and clear, no doubt (+1 from me), especially since the correct usage of ifPresent.
I'd just add here that get, well, was seen as somehow a design error ( or may be a bad method name, probably that came from guava mindset ). Using get even if it documented to throw an Exception when that value is missing is somehow weird ( if you think getters here, you would not expect a getter to throw an Exception). And you would not expect that get needs to be called after isPresent, at least not on the very first interactions with Optional. Thus get was proposed to be deprecated ( and hopefully removed ), thus java-10 adds a better addition orElseThrow() - this makes sense right after you read it, cause the throwing part is in the name of the method, so no surprises.
Also, someone should tell you about that usage of new Date() that when used with Optional from java-8 just looks weird, there are much better time/date related classes already.
I am also not very sure why you are updating a modified date manually, when there are spring annotations for that like PreUpdate/PrePersist.
you can also do:
Optional<ExpectedPackage> updatedPackage = expectedPackageRepository.findById(1).map(ep -> {
ep.setDateModified(new Date());
return expectedPackageRepository.saveAndFlush(ep);
});

Java8 way to handle if..else check in Collections

Below one is my code and I would like to write a better equivalent code in Java8
List<String> fruits = Arrays.asList("Apple","Orange","Banana");
List<String> animals = Arrays.asList("Tiger","Lion","Monkey");
#SuppressWarnings("all")
Map<String,List<String>> allLists = new HashMap() {{
put("fruits",fruits);
put("animals",animals);
}};
Legacy prior Java8 way of checking
if(allLists.get("fruits")!=null) {
List<String> fruits1 = allLists.get("fruits");
if(fruits1.contains("Apple")) {
System.out.println("Apple is there");
}
}
Java8 Way of doing..
Consumer<List<String>> consumer1 = arg ->{
Optional.of(arg.contains("Apple")).filter(value -> value.equals(true)).ifPresent(value1 -> System.out.println("Apple is available"));
};
Optional.of(allLists.get("fruits")).ifPresent(consumer1);
Currently the Java8 way is returning the output "Apple is available"..
Question is, How do I handle if Apple is not in the ArrayList...
Ex: If Apple is not in the list , I want to print "Apple is not Available"
Please suggest me better approaches to handle both cases.
I'd go for getOrDefault on the map, like this:
if(allLists.getOrDefault("fruits", Collections.emptyList()).contains("Apple"))
System.out.println("Having apples");
Basically, this eliminates the key-not-present check you normally do. In situations, where you want to continue to work with the list (grouping in maps), you may also check out computeIfAbsent.
First, Optional.of will throw a NullPointerException if you pass null to it. You need to use ofNullable here as
Optional.ofNullable(allLists.get("fruits"))
Optional in Java 8 does not have a method that can be executed if a value is not found.
But Java-9 has ifPresentOrElse that takes a Runnable where you can print that Apple is not there
FWIW, Optional is not replacement for null. Cleverly use of Optional in place of null and simple if...else checks is bad idea.
Why Optional: Optional's are created to handle value/no values(empty) cases on Streams. Optional's are created to avoid breaking stream methods for null check during fluent chaining.
Until you have a valid reason to create Optional, do not create it.
ex: The below is not a good Idea,
String process(String s) {
return Optional.ofNullable(s).orElseGet(this::getDefault);
}
//Better way is
String process(String s) {
return s!=null ? s : getDefault();
}
PITFALLS: Optional.get is a really attractive method to use but beware that Optional.get throws "NoSuchElementException". Not similar to get method in java Collections ( they wont throw exception if the value does not present).
So use get method along with isPresent() method.
Places you should not use Optional:
Do not create Optional type Fields
Do not use Optional Parameters (forcing someone to create empty
optional instead of passing null is really bad)
Do not combine Java collections with Optional.

Calling contains on a list for an optional value in Java?

In Java 8,
I currently have a lambda that looks like this:
.createSomething((acceptableStates, someProxy) -> (userId) ->
acceptableStates.contains(someProxy.getSomeAttributeId(userId)))
However, we have changed someProxy.getSomeAttributeId to return an Optional<String> instead of a string.
What's the cleanest / most accepted way to essentially check for if acceptableStates contains the value of someProxy.getSomeAttributeId(userId) if the attribute returned isn't empty?
(Note: acceptableStates is still a list of strings, not of Optional<String>)
.... userId -> someProxy.getSomeAttributeId(userId)
.map(acceptableStates::contains)
.orElse(Boolean.FALSE);
Unfortunately, I see no very clean solution here. Refer to this question: Functional style of Java 8's Optional.ifPresent and if-not-Present?
Additionally, you even have to save the optional in a variable if the call to getSomeAttributeId does cost resources.
.createSomething((acceptableIds, someProxy) -> (userId) ->
{
Optional<String> attrId = someProxy.getSomeAttributeId(userId);
return attrId.isPresent() ? acceptableStates.contains(attrId.get()) : false;
})
I strongly recommend writing understandable and clear code like this snippet:
Optional<SomeAttributeId> optional = someProxy.getSomeAttributeId(userId);
return optional.isPresent() && acceptableStates.contains(optional.get‌​());
If there should not be thrown an exception (1) when someProxy.getSomeAttributeId(userId) is an empty optional:
acceptableStates.contains(someProxy.getSomeAttributeId(userId).orElseThrow(() -> new Exception()))
Or unless you have the default value (2) to fill up the result with:
acceptableStates.contains(someProxy.getSomeAttributeId(userId).orElse(DEFAUT_VALUE))
My point:
Do not pursue Java 8 features which will mess everything up, especially in cases where a simple boolean expression could be used. I had experience refactoring some code toward plain Java statements because new people (1.1) came in a project could not get what the code does. With the time, even I (as a writer) barely can do so (1.2).
Also, with that "lambda chain" style, one slight change could cause rewriting a snippet/method entirely (2).
It is always fun to poke around n-nested lambdas, where n > 2 (3).
Anyway, if you don't share my point, #Eugene proposed a good way to go with.
return value.isPresent() && value.get().contains("some-text");

using Java8's Optional<T> in a functional way for updating source with default value

This is probably more a question about functional programming than about Java 8 specifically, but it's what I'm using right now.
I have a source object (could represent a repository, or a session..., doesn't matter here) that has a method retrieveSomething() that returns an Optional<SomethingA>.
I have a method somewhere that returns a Something, by calling retrieveSomething() and providing a default value in case the optional was empty, as follows:
return source.retrieveSomething()
.orElseGet(() -> provideDefaultValue());
Now I want to modify this code so that in case the source didn't contain any value yet (so the optional was empty), the source is updated with the provided default value.
Of course, I could easily do that inside a lambda expression code block:
return source.retrieveSomething()
.orElseGet(() -> {
Something sth = provideDefaultValue()
source.putSomething(sth);
return sth;
});
But if I understand correctly, I'm not supposed to use functions that cause side effects. So what's the "correct" (functional) way to do this, keeping the benefit of using Optional (in real code I'm actually also performing a map operation on it, but that's irrelevant here) ?
You could follow the way Java does this with Map.computeIfAbsent()
which takes a second parameter which is a function on how to compute and insert the record:
So your code would become:
Something something = source.computeIfAbsent(sth, (k)->provideDefaultValue());
An advantage of using a lambda to compute the default instead of just passing it in, is the lambda will only be evaluated if it needs to be so if computing the default is expensive, you only have to pay it when you need it.
From a conceptual standpoint, you use the optional pattern to deal with the absence of a return value. This means, if your source instance doesn't contain a value for you to use, you have the choice of providing a default value to use in its place.
It is not advised to modify the Optional directly to provide its value; that instance may be temporal and will differ on subsequent calls to retrieve it.
Since a function call truly governs what's returned by that Optional, the only approach you have if you truly want to go down this route is to modify how that value is computed. This really should be done from within the function providing the Optional, but it could be done outside of it if necessary.
Since there's not enough code structure here to truly write up some example, I will describe the steps:
Outside of the method providing the Optional, you write the same closure as you did before, with the side effect of adjusting the value used to compute the original Optional. This is likely a field of some sort.
Inside of the method providing the Optional, you ensure that you don't expose provideDefaultValue anywhere else (since they won't need it), and use a boolean conditional before you package the Optional.
return value == null ? Optional.of(provideDefaultValue()) : Optional.of(value);
...but that really defeats the purpose of the Optional, as you're still doing a null check.
A slightly better approach to the above would be to compute value in such a way that it was either itself or the default value, and return the Optional of that...
value = computeValue();
if(null == value) {
value = provideDefaultValue();
}
return Optional.of(value);
...but again, seriously defeating the purpose of Optional, as you're doing null checks.
An answer I came up with myself, which I'm not entirely satisfied with, but may serve as an example of what I'm looking for:
I could implement something similar to a Pair<V1,V2> class and then map the Optional<Something> to a Pair<Something, Boolean> where the Boolean value would indicate whether or not the value was a generated default:
Pair<Something, Boolean> somethingMaybeDefault =
source.retrieveSomething()
.map(sth -> new Pair<Something, Boolean>(sth, false))
.orElseGet(() -> new Pair<Something, Boolean>(provideDefaultValue(), true));
Then I'd update in case the boolean is false:
if (somethingMaybeDefault.value2()) {
source.putSomething(somethingMaybeDefault.value1());
}
And finally return the new value:
return somethingMaybeDefault.value1();
Of course, this uses imperative style for the update, but at least the functions remain pure.
I'm not sure this is the best possible answer though.

Categories

Resources