How to use Guava Optional in this scenario - java

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!

Related

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.

Behavior of Optional Class in Java8

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.

What to do if nothing to return. Java

There is long get(int key) method in my container class.
What to do if i have no matches for key value?
Throw an exception? Something else?
I will suggest to throw an exception, which clearly describe your method from its signature. I will not suggest to returning null or returning -1 if no match found, because the behavior of the method will not be reflected from its signature. Who ever is going to use that method need to remember or somewhere you need to document that if no matching found then it will return null or -1 and in the client code they need to handle it with condition. But by throwing exception you are documenting the behavior in the method signature itself. And in the client code they have to handle as the method throws exception.
You should do whatever suits the use cases of your container:
If calling your container with an absent index is probably an error
in the calling client code, then you should throw an exception.
If calling this method with an absent key is quite usual and does not
signify the error, then probably client code expects some default
value in absence of an explicitly set value. So you should return
this value.
If you want to explicitly state that there is no value
for this key, and expect the client code to handle this correctly,
then change the return type to Long and return null.
In any case, write good documentation for your container class and method that clearly defines its contract.
You don't even have to handle that in your container class. Handle it in the controller class or the class that calls that method. If you really want to, if nothing comes back, just return -1. EDIT: If -1 is a valid value, then pick a value that is not a valid value to be a return value. My preference is to avoid NULL.
Example.
if ( get(tempKey) == -1 )
//you know it isn't a match, do something with it, throw exception...etc.
This will depend on what it can return. If it can never return -1 then you can return -1 (this is often used for this sort of thing).
If it can return -1 then you can throw an exception.
You can also use the Long class to return null, but throwing an exception should be better.
Depends upon the application - is what I would say. I will try to ensure both of your queries in the posting above.
I would return Long.MIN_VALUE for your first query and null for your second query.
Returning null is not all that bad - read below for an explanation for my choices.
As a rule of thumb whenever you are developing your classes and methods that invoke other classes and methods; you should define the expected contracts (parameters and return values) based upon the way your logic would process them after having invoked the method.
In you case, if the method must return a long and you do not have anything to return then return Long.MIN_VALUE. This way you insulate the application from cases where negative numbers would be valid return values - it is rare to have a program that processes Long.MIN_VALUE.
Coming to the second question - what should be returned when a key is not present within a map. Well the Java SDK shows the way : Returning null would be your best bet. This would force you to check for valid return values from the get() method before processing your code. Assuming that you do not catch NullPointerException this would also result in your application definitely crashing in case you miss such checks - a good fail-fast implementation that would help you identify the missing links.

Categories

Resources