Behavior of Optional Class in Java8 - java

What is the Optional class in java 8? What its significance? Can the object of optional class hold null value?

It is container to avoid null pointer exception.
It is an implementation of NULL object pattern. Here is an article on it
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

It's simply to handle null better.
for example -:
if(book.getAuthor()==null)
//do something
else
System.out.println(book.getAuthor().getName())
can be better handled through optional as -:
System.out.println(Optional.ofNullable(book.getAuthor()).orElse(/**return something else instead**/).getName())
from the doc ->
Optional.ofNullable(T value)
Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.
and orElse(T other)
Return the value if present, otherwise return other.

Related

Why Optional.isEmpty() which checks for NULL is not called isNull()

This might be a silly question.
When I am using Optional.isEmpty() like below in the code
Optional<List<String>> optional = Optional.of(new ArrayList<>());
optional.isEmpty(); // only checks if the value is NULL or not.
isEmpty() method is only checking whether the value null or not.
public boolean isEmpty() {
return value == null;
}
This method name seems not clear for me.
I'm wondering why this method is named isEmpty() and not isNull() since it performs null-check under the hood?
It’s the because the null check is an implementation detail, not what the method logically does. Logically, the method checks whether the optional value is empty or engaged.
Technically, this can be implemented in a number of ways, depending on how the Optional stores its value. JDK 8’s implementation happens to use a reference object with a null check, but other implementations could conceivably do this differently. It’s a mistake to confuse a high-level interface description with its implementation. The entire point of encapsulation is to abstract away implementation details from the user.
You're missing the main point.
Optional is designed to be a container of data which can never be null by itself and which is safe to interact with.
Optional is not intended to be a substitution for null-checks. It's mean to represent a nullable return value and should not be creating in order to hide null-checks or chain methods on it (more on that, see here and here).
If you need to validate that something is not null you can use method Objects#requireNonNull() and it's flavors or explicit null-check.
The idea behind the optional, is that serves as a box for a value, and you can do whole lot of staff with it without caring if the box empty or not. Optional offers you methods to filter to the value inside the box filter(), to replace an empty box with another box or(), to transform the value inside the box map(), etc. And all these actions can be done by chaining the methods fluently without opening the box.
Methods isNull()/isNotNull() are not suitable for the Optional API because they contradict its design goal, which to provide a limited mechanism for representing a nullable return value and a mean of interaction with the target value (around which optional is wrapped) in a simple and fluent way regardless whether its value is null or not.
Note, that checks isPresent() (JDK 8) and isEmpty() (JDK 11) exist as a last resort. Be attentive when you're using them, because most likely you're not leveraging Optional to its full power.
Also, note that wrapping Optional around a Collection or an array doesn't make sense because they are container of data as well (like optional) and might be empty as well, which represents the absents of data.
Doing something like this is redundant and inconvenient.
Optional<List<String>> optional = Optional.of(new ArrayList<>());
When a collection is not null, which should be the case because keeping nullable collections is an antipattern, Collection.isEmpty() is sufficient to check if the data is present. Meanwhile, when you have optional wrapped around collection, the presence of collection inside the optional doesn't means that the actual data is exists.
This is the definition of Optional:
A container object which may or may not contain a non-null value.
Since the object itself is a container, which may or may not hold a value, isEmpty (or isPresent) refers to the status of the container, whether it holds something or not.
isNull as a name would suggest that the Optional would be null, which would be a false impression, because the Optional itself is a properly existing instance.
Is the Optional null if it does not hold a not-null value? No, you can check for
myOptional == null
and you will see it's false (you couldn't even call isEmpty otherwise). Is the object inside the container null? If isEmpty is null, then it's a sure thing. Hence, the Optional is either empty, or something is present inside of it.
Here's a different way of implementing Optional which checks emptiness by using different concrete classes for full and empty instances.
public interface MyOptional<T> {
boolean isEmpty();
T getOrDefault(T aDefault);
static <T> MyOptional<T> empty() {
return new MyOptional<T>() {
#Override
public boolean isEmpty() {
return true;
}
#Override
public T getOrDefault(T aDefault) {
return aDefault;
}
};
}
static <T> MyOptional<T> of(T t) {
return new MyOptional<T>() {
#Override
public boolean isEmpty() {
return false;
}
#Override
public T getOrDefault(T aDefault) {
return t;
}
};
}
public static void main(String[] args) {
MyOptional<String> optString = MyOptional.empty();
System.out.println(optString.isEmpty());
}
}
This has a semantic difference from Java's Optional: this can contain a null value in a full instance, while Java's cannot.

Use Optional instead of null check

I have to check if an attribute of an object is null or not. Depending on the above check I have to update another attribute in the same object. Is it possible to use Optional class and its methods to replace null checks?
if(userData.getSubscription()==null){
userData.setFees(Enum.ZERO);
} else {
userData.setFees(Enum.HUNDRED);
}
Let me know if this can be replaced with a single line using Java 8 Optional class or other features.
Maybe you want:
userData.setFees(Objects.isNull(userData.getSubscription()) ? Enum.ZERO : Enum.HUNDRED)
You could do something like
Optional::ofNullable(userData.getSubscription()).map(any -> Enum.HUNDRED).orElse(Enum.ZERO);
However I don't see much benefit to that over #T.J. Crowder's suggestion from the comments
userData.getSubscription() == null ? Enum.ZERO : Enum.HUNDRED
The main use of Optional is to prevent you from forgetting to check for null. Thus, it would only be useful if the Optional type was returned from getSubscription(). Then you could do:
userData.setFees(userData.getSubscription().map(x -> Enum.HUNDRED).orElse(Enum.ZERO));
But if you can't or don't want to change getSubscription() to return Optional, then there is no point in using Optional here. Just do this:
userData.setFees(userData.getSubscription() == NULL ? Enum.ZERO : Enum.HUNDRED);
By the way, if Enum.ZERO and Enum.HUNDRED are just names representing 0 and 100, then that's not a good idea. The words "ZERO" and "HUNDRED" are just as much a "magic number" as the numbers 0 and 100 themselves. You should name your enums something descriptive like "FREE_OF_CHARGE" and "FULL_PRICE".

How to handle a null returned from a method?

I have a graph related method which returns the neighboring nodes of a certain node.
If the one node has no neighbors it returns null, the method is the following
public Iterable<Node> getNeighbors(Node v) {
if (!this.adjacencyList.get(v).isEmpty())
return this.adjacencyList.get(v);
return null;
}
I try to avoid the exception using the following :
if (graph.getNeighbors(nodeIterator.name) == null)
nodeIterator = all_graph_nodes.iterator().next();
Iterable<Node> adjNodes = graph.getNeighbors(nodeIterator.name);
The NullPointerException is raised even using the previous code.
How to solve this ?
If you're still getting an NPE, then the problem is in getNeighbours and not the second snippet.
this.adjacencyList is null, -OR-
this.adjacencyList.get(v) returns null.
Given that you're passing a name to a method that will then do a lookup by node, and that you can't call .get(someNodeRef) on a list, adjacencyList is probably some sort of hashmap, so your names are off and you should rename some things. Map's .get(x) method returns null if an entry is not found, so most likely the culprit is that v isn't in the map at all, and thus .get(v).isEmpty() throws NPE.
The fixes are as follows:
You should NEVER return null when a valid sentinel value that carries the intended semantic meaning is available. A mouthful, but it means here: Why are you returning null when you intend to treat that the exact same way as 'zero nodes'? There is an instance of Iterable<Node> that properly represents the concept of zero nodes, and it isn't null. It's List.of() or equivalent: An empty list has no nodes. Great. That's what you intended. So return that.
.get(v).isEmpty() is bad code here, as it would mean an NPE occurs if you ask for a non-existent node. Unless, of course, you want it to work that way. An easy way out is the defaulting mechanism: Call .getOrDefault instead:
if (!this.adjacencyList.getOrDefault(v, List.of()).isEmpty()) ....
except, of course, you should never be returning null when you can return an empty list instead, so your getNeighbours method becomes simply:
return adjacencyMap.getOrDefault(v, List.of());
that one-liner will fix all things.
In general, if you are writing code where null is dealt with in some way, and some sentinel value (such as a blank string or an empty list) is dealt with in the same way, your code is badly styled; however you got that null should have gotten you that empty value instead. e.g. if you ever write this:
if (x == null || x.isEmpty()) ...
you messed up. Figure out where you got x from. Update it there, make x the blank sentinel ("" for strings, List.of for lists, etcetera).
That, and use .getOrDefault and other such methods more: Methods that let you provide what should happen when e.g. a key is not found.
You should probably avoid returning null from your getNeighbors method. It's not good practice to return null for Iterables, Iterators and Collections, since an empty iterable would represent the same concept (there is nothing in that adjacency list) without all the dangers of null. And your code would be simpler. You can check if the iterable contains anything and if not then default to the full iterator.
You should avoid returning null at all cost. This is of high danger as it may cause Null Pointer Exceptions to be thrown during runtime. Such exceptions are horrific to debug as they usually hide implementation errors due to the place where the exception was thrown is most likely far away from the original implementation error.
Your case is actually a good example of such behavior as it is not directly understandable where the NPE is coming from.
In situations in which the appearance of a null value is inevitable (e.g. as #rzwitserloot pointed out, Java's Map get method) and there is the possibility of exposing it to client objects (e.g. your getNeighbors method may expose such null value) I like to use Java's Optional which (as stated in the docs) is:
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
This object will act as wrapper to objects which may be assigned as null thus preventing it to be used directly and possibly preventing NPEs to be thrown.
In your case this would apply as follows (note that this is assuming that adjancencyList is a non-null object and that its get method is the one actually throwing the NPE):
public Optional<Iterable<Node>> getNeighbors(Node v) {
return Optional.ofNullable(this.adjacencyList.get(v));
}
if (!graph.getNeighbors(nodeIterator.name).isPresent()) {
nodeIterator = all_graph_nodes.iterator().next();
}
Iterable<Node> adjNodes = graph.getNeighbors(nodeIterator.name).get();
Note that by wrapping the original get method in an Optional object there is no longer the propagation of a raw null value hence preventing it to be used by the client. You are moving the responsibility of dealing with null to your side only and protecting clients to handle them instead.
Another great advantage of using Optional as a method's return type is that it implicitly declares that the return object of the method may or may not be present. This forces clients to understand that its return value may be empty (null) and thus force it to act accordingly.

How to performe a null-check for an empty Optional

I'm currently working with some repository functions, like .findById(). Now I want to check, if there was an entry returned for the requested id. I'm currently doing this by performing a null-check.
Optional<Entry> entryOptional = entryRepository.findById(id);
if (entryOptional != null) {
// do sth. ...
}
The .findById() documentation says, that the function will...
return the entity with the given id or Optional#empty() if
none found
So is my current implementation with the null-check working as expected? Or do I have to check something like:
if (!entryOptional.isEmpty()) {
// do sth. ...
}
Checking whether an optional is null or not is intrinsically wrong.
Optionals where created in order to negate the need for null checks, by introducing the notion of emptiness.
Essentially an optional is a wrapper for a value, for which it can have two states. Either having a value or being empty. This is done via using Optional#isPresent. You can check more on this on the related documentation here.
What this does essentially is the following:
public boolean isPresent() {
return value != null;
}
A nicely implemented method (as the one you mention above) will either return an optional with a value or an empty Optional (as it is mentioned in the documentation).
Optionals offer a good amount of methods that you can operate of them without the need for emptiness checks.
For example, in your code you could:
entryRepository.findById(id).ifPresent(() -> {
//some operation
});
Which basically accepts an consumer and executes it in case the value of the optional is not null.
Alternative you could use mapping functions etc etc.
I suggest you have a good look at the documentation for more.
So is my current implementation with the null-check working as expected?
No. Like the method says, it returns the entity, or Optional.empty; it does not return null.
Your second version is correct.
Optionals are created to remove null checks on that field and to do operations on that field without the care of it being null.
You can check with Optional.isPresent() at the end if it contains any value or not.
So yes, your second approach is correct.

How to use Guava Optional in this scenario

I have a scenario which I want to use Guava Optional, but there is problem:
The method is like this:
private static void method(Optional<Object> myOptional) {
if(myOptional.isPresent()) {
....
}
}
The myOptional can contain non-null value, null value, or absent(). A null is a valid input in this scenario.
In the method, I want to process non-null value and null value using differnt ways, but ignore absent value.
However, if I use isPresent here, the null value will be ignored as well. But if I use "get" method, the absent value will throw exception. If I use orNull, the absent value also returns as null.
I am not sure what I shall do here. But I think the reason to create Optional is to differentiate null and absent so that null becomes a valid meaningful value. But it looks like there is no method in Optional that allows me to achieve my usecase.
Can anyone help? Thanks.
You can't do that.
The javadoc says it explicitly: an Optional may contain a non null reference. Never a null one.
What you can do is create an Optional.fromNullable(whatever).orNull(). But an Optional will never differentiate a null value from absent, since it is not what it is meant to do!

Categories

Resources