Can someone explain how Optional helps us avoid NullPointerException?
Optional<String> op = someFunc()
if(op.isPresent()) {
op.get();
}
String possibleNull = op.get();
Isn't this code prone to NullPointerException too? If so, then why is this code preferred over
String op = someFunc()
if(op != null) {
op.get();
}
String possibleNull = op;
What possible benefit does Optional provide other than the fact that it helps us in knowing whether a function actually had a return value or not
Let's say you want to get a string returned by a function, convert it to upper case, and then print it out. If you have:
String someFunc() { ... }
You might be tempted to write:
System.out.println(someFunc().toUpperCase());
Of course, this throws NullPointerException if someFunc returns null. Instead, suppose we have this:
Optional<String> someFunc() { ... }
Then
System.out.println(someFunc().toUpperCase());
won't work, since Optional doesn't have a toUpperCase method. At this point -- hopefully -- you'll be confronted with an Optional, which should make you think about the case of the Optional being empty. This helps avoid NPEs, but probably only somewhat.
Now you might be focusing on how to get the value out of the Optional, and you might forget about the empty case. Ah, there's a get method:
System.out.println(someFunc().get().toUpperCase());
This brings back the same problem as NPE, except that the exception is NoSuchElementException instead. So if you blindly call get on an Optional, it really is pretty much the same thing as calling a method on a reference without checking whether it's null.
(For this reason, Brian Goetz considers Optional.get to be the biggest mistake in Java 8. See his interview with Angelika Langer JAX 2015 Fragen und Antworten zu Java 8 at about 16 minutes in. I'm not sure it's the biggest, but it is a mistake. People just don't expect get to throw an exception.)
If you're diligent about checking for null references or empty optionals, then
Optional<String> os = someFunc();
if (os.isPresent()) {
System.out.println(os.get().toUpperCase());
}
is hardly any better than the old
String s = someFunc();
if (s != null) {
System.out.println(s.toUpperCase());
}
The real advantage of Optional is that it's a library class that has a fairly rich API for dealing with the empty case in a safe way. It's often possible to process the value that might be contained within an Optional by chaining a couple method calls to the method that returned the Optional in the first place. For example, we could rewrite the sample above as follows:
someFunc().map(String::toUpperCase)
.ifPresent(System.out::println);
String op = someFunc()
if(op != null) {
op.trim();
}
When the interface someFunc() is invoked above, it doesn't explicitly say that a null value could be returned, so the caller is left to his/her own assumption.
By explicitly returning an Optional, the caller of someFunc() is made aware that the interface could potentially return null. From an interface creator's perspective, it lets him/her be specific about the return value rather than having to document it separately.
Optional<String> op = someFunc()
if(op.isPresent()) {
op.get().trim();
}
One scenario where Optional is helpful in avoiding NullPointerException is method chaining.
class A {
private B b;
}
class B {
private C c;
}
class C {
private D d;
}
Let's say I have the above classes, and I want to make sure that an instance of class A has a non-null instance of D, but without causing a null pointer exception.
If I were to directly call a.getB().getC().getD() != null, then it might throw NullPointerException - say if a.getB() was null.
Of course, I can do
try {
a.getB().getC().getD();
// do something
}
catch(NullPointerException e) {
// handle exception
};
But that doesn't look nice. An elegant solution would be to wrap our objects in optional.
Optional.ofNullable(a).map(A::getB).map(B::getC).map(C::getD).isPresent()
Check this for more.
Related
This question already has answers here:
Using Java 8 Optional for List of String as output
(3 answers)
Closed 1 year ago.
I keep seeing some users saying that using a collection with an optional is not recommended / is bad practice. I couldn't find much information on why it would be bad practice, so here I am.
In case it matters, in my particular case I have a JpaRepository with 2 methods. One Optional<List> getValues() and a second List getDefaultValues(), as such:
public interface someRepository extends JpaRepository<x, y> {
Optional<List> getValues();
List getDefaultValues();
}
The idea is that the values might not be present so I want to force the method caller to do .orElse(getDefaultValues()) so there is no chance getting returned an empty List. I also figured it would be tidier than just doing something like this:
List list = getValues();
if (list.isEmpty()) {
list = getDefaultValues();
}
Any feedback is appreciated.
Edit: I realise my example is not the most well suited to the question, as pointed out in the answers below. However, I would still like to understand why Optional<List> is considered bad practice by some.
This question does not really answer my question.
I think the point is moot. There are two possible cases:
1. The caller needs to be aware that default values have been returned
In this case, the caller will not be able to use the orElse()/orElseGet() construct, and will have to check with isPresent(). This is no better than checking whether the list is empty.
2. The caller does not need to be aware that default values have been returned
In which case you might as well hide the implementation details behind a single List getValues() method that returns the default values in case no values were found.
As to the general applicability of using Optional<List>, I think the Brian Goetz quote from this answer says it best:
Our intention was to provide a limited mechanism for library method
return types where there needed to be a clear way to represent "no
result", and using null for such was overwhelmingly likely to cause
errors.
When it comes to lists (and collections in general), there is already a clear way to represent "no result", and that is an empty collection.
Lets first consider this example:
public class <X> Example {
public List<X> getValues() {
if (...) {
return null;
} else {
return /* a non-empty list */
}
}
public List<X> getValuesAgain() {
if (...) {
return Collections.emptyList();
} else {
return /* a non-empty list */
}
}
}
Which of those ways of returning no values is better?
I would argue that the better way is (nearly always) the way that getValuesAgain does it; i.e. by returning an empty list. Consider the following.
With the first version, I need to test for a null before using the result:
List<String> l = example.getValues();
if (l != null) {
for (s String: l) {
/* do something */
}
}
With the second version, I can use the result directly:
List<String> l = example.getValuesAgain();
for (s String: l) {
/* do something */
}
In short, returning null makes life more complicated for the caller compared with returning an empty list. In theory, you may have saved the creation of an empty list object ... except that the javadoc for emptyList() states that it doesn't need to return a distinct list object each time. (And it typically won't!)
Now consider what Optional<List<String>> means: either a List<String> or no value. But as we have already seen, returning an empty list is simpler for the caller that returning a null. And the same logic applies here too.
So if getValues returns an Optional<List<X>>, we would need to use it like this:
Optional<List<String>> l = example.getValues();
if (l.isPresent()) {
for (s String: l.get()) {
/* do something */
}
}
Compare with the original getValuesAgain:
List<String> l = example.getValuesAgain();
for (s String: l) {
/* do something */
}
In short, using Optional to return a list or null is not an improvement.
The only scenario where I think you should contemplate using Optional<List<?>> as a return type is if the API needs to make a semantic distinction between an empty list versus no list.
The same applies for other collection types, and also for arrays, strings and other examples.
Another way of thinking about this is that the designers' intention for Optional is to provide a way to indicate there is "no result"; see Brian Goetz's answer to this question. But we don't need to indicate there is "no result" here since we can return an empty collection.
This is a code segment from another StackOverflow question:
#Override
public String convertToDatabaseColumn(final UUID entityValue) {
return ofNullable(entityValue).map(entityUuid -> entityUuid.toString()).orElse(null);
}
I am really struggling to understand the use of the Optional class. Is the return code saying "return the value of the map (a String) or NULL if that fails?
How can return be acting on a method rather than a Class - that is Optional.ofNullable()?
This is a really bad use of Optional. In fact the java developers themself say that optional should not be used in such cases, but only as a return argument from a method. More can be read in this great answer: Is it good practice to use optional as an attribute in a class
The code can be rewritten to this:
#Override
public String convertToDatabaseColumn(final UUID entityValue) {
return entityValue == null ? null : entityValue.toString();
}
Is the return code saying "return the value of the map (a String) or NULL if that fails?
Yes. You can check the documentation of Optional here. It tells you exactly what map and orElse do.
How can return be acting on a method rather than a Class - that is Optional.ofNullable()?
You are not returning the method. You are returning the return value of a method. Look at this simple example:
int myMethod() {
return foo();
}
int foo() { return 10; }
See? I am not returning foo the method, I am returning 10, the return value of foo.
Note that it is possible to return methods, with functional interfaces.
In this case, you are returning the return value of the last method in the method chain, orElse. ofNullable creates an Optional<T>, then map is called on this object and returns a new Optional<T>, then orElse is called and its return value is returned.
Lets go step by step:
ofNullable(entityValue)
creates an Optional of the incoming parameter (which is allowed to be null, using of() a NPE gets thrown for null input)
.map(entityUuid -> entityUuid.toString())
Then you pick the actual value, and invoke toString() on that value ... which only happens if entityValue isn't null. If it is null, the result comes from orElse(null).
In the end, the result of that operation on the Optional is returned as result of the method.
The above code is nothing but a glorified version of
if (entityValue == null) return null;
return entityValue.toString();
Optionals have their place in Java, but your example isn't a good one.
It doesn't help readability a bit, and you are not alone with wondering "what is going on here".
The code can be turn like this :
public String convertToDatabaseColumn(final UUID entityValue) {
if(entityValue==null){
return null;
}else{
return entityValue.toString();
}
}
Your initial code have two statements:
Optional.ofNullable(entityValue): create an Optional Object to say the value can be present or not.
.map(entityUuid -> entityUuid.toString()).orElse(null); you apply some operation to your Optional object, return a string of it or null.
This will avoid a null pointer exception in a more elegant way.
Optional.ofNullable(T value):
Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.
Optional.orElse(null)
Return the value if present, otherwise return null.
Follow this link
I was trying the following code:
Optional.ofNullable(listEvidence).ifPresent(
eviList -> {
List<String> repoKeysList = new ArrayList<String>();
for (Evidence evidence : eviList) {
repoKeysList.add(evidence.getRepositoryKey());
}
log.debug("UserContentBean: processRepoSyncCleanup repoKeysList - "+repoKeysList);
evidenceDetailDAO.updateIsSelectedFlag(repoKeysList, 0,configurationService.getNodeName());
}
).orElseThrow();
but I am getting the following error:
Cannot invoke orElseThrow() on the primitive type void
It seems to me that orElseThrow() is misplaced in the code. but updateIsSelectedFlag() throws an exception which needs to be handled.
Also, this piece of code is a part of, say, method1(). I tried adding throws Exception to method1(), but it yet asks me to handle the exception raised by updateIsSelectedFlag(). I couldn't understand the reason for the same.
This seems like a poor approach to the situation. In general, speaking on the use of Optional, you're expecting that usually as a return value, not a value that you do operations on. In effect, you're still doing a null check; it's just unnecessarily obfuscated.
Instead, perform the operations you intend to do with the if statement.
if (null != listEvidence) {
List<String> repoKeysList = new ArrayList<String>();
for (Evidence evidence : listEvidence) {
repoKeysList.add(evidence.getRepositoryKey());
}
log.debug("UserContentBean: processRepoSyncCleanup repoKeysList - " + repoKeysList);
evidenceDetailDAO.updateIsSelectedFlag(repoKeysList, 0, configurationService.getNodeName());
}
For more context into the conversation around Optional, this Stack Overflow question goes into some detail as to what use cases Optional is meant for.
Optional.ifPresent returns a void type, and not the Optional itself.
What you're trying to do should be done with a if {listEvidence != null} else {} block.
You are misusing the Optional class.
First problem is that inside ifPresent() you are using a lambda expression that contains code that throws a checked exception. Lambdas cannot throw checked excpetions (i.e those that do not extend RuntimeException).
Second problem is that you are misusing the orElseThrow() method of Optional. It is supposed to be used to either get a maybe nullable object or throw an exception if it is actually null like so:
MyObject notNull = Optional.ofNullable(maybeNull).orElseThrow(new MyException());
For your use case you can either go with the old school if-else or if you want to play with Optional for some reason the way to go about it would be:
Optional.ofNullable(listEvidence).ifPresent((eviList -> {
// your logic
try {
evidenceDetailDAO.updateIsSelectedFlag(repoKeysList, 0,configurationService.getNodeName());
} catch (Exception e) {
throw new RuntimeException(e);
}
});
This way you convert the checked exception into an unchecked one inside the lambda and you can handle it outside the Optional by adding another try-catch for RuntimeException.
As pointed out by Jeremy, Optional.ifPresent returns void. In addition, you miss an argument to public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
Note that orElseThrow will never handle the exception thrown by updateIsSelectedFlag(). The purpose of orElseThrow is to "get the value inside the optional if it present and if its is not present throw an exception".
updateIsSelectedFlag() must throw unchecked exceptions if you want to use it in the Consumer<T> that is the argument of ifPresent. Have a look at the Consumer interface, it does not support checked exceptions. If updateIsSelectedFlag() cannot throw unchecked exceptions, you have to catch the exceptions and throw a new unchecked exception (such as a RuntimeException) in the Consumer.
You could achieve something similar to what you wrote by using Optional.map instead of Optional.ifPResent and by fixing the rest of the code (managing your exception, adding the argument to orElseThrow). But as suggested by many, you should better rewrite the code. For now, you are not writing what you intend to do.
Tip : since you have the good idea of using Optional, avoid to test for a null value. Prefer
listEvidence = Optional.ofNullable(something);
if (listEvidence.isPresent())
to
if (null != listEvidence)
If you avoid null values, your code will never throw NullPointerException.
Like everybody else has said, in your case it's better just to use if (listEvidence != null).
However, if you do need to use an optional like this in another case, you can store it in a variable instead of chaining everything together.
Say listEvidence is of type MyClass.
Optional<MyClass> myOptional = Optional.ofNullable(listEvidence);
myOptional.ifPresent(
eviList -> {
List<String> repoKeysList = new ArrayList<String>();
for (Evidence evidence : eviList) {
repoKeysList.add(evidence.getRepositoryKey());
}
log.debug("UserContentBean: processRepoSyncCleanup repoKeysList - "+repoKeysList);
evidenceDetailDAO.updateIsSelectedFlag(repoKeysList, 0,configurationService.getNodeName());
});
myOptional.orElseThrow(() -> new RuntimeException());
If there is a structure, an array for example, which might be null, is it valid to use a for/in loop for this structure? For example,
String[] a = someFunction(); //some function which might return null
for (String s : a) {
//do something
}
I wonder if this code will crash or not.
No. You'll get a NullPointerException
In such circumstances I always try to return empty collections, rather than null collections. That way I don't have to worry about iterating without a prior null check (you could argue this is a NullObject pattern)
Make someFunction() return an empty array if possible.
Otherwise, yeah. You'll get a NullPointerException
I wonder if this code will crash or not.
Yes. It might crash.
Note that if you return an empty collection, this might ruin your logic. You have to be sure that you don't do unexpected things when you didn't return a non-null value.
I would simply put an if that checks if the value returned from someFunction() is null:
if(a != null) {
for (String s : a) {
//...
}
}
I have a big problem with this code and I have no idea how to cause it:
while(tree.find(indexreg)!=null){
//do stuff
}
For some reason, comparing tree.find(indexreg) with null causes a NullPointerException. Since this is a college project I have to use my own binary tree implementation instead of the one provided by Java. tree is a BinarySearchTree and indexreg is a Comparable object, that was already initialized. This is the code for find in the BinarySearchTree class:
public Comparable find(Comparable x) {
return elementAt(find(x, root));
}
It looks for the object in the tree and it returns null if it doesn't find it (I don't think you can return an empty Comparable object). I tried Googling but I didn't find an useful answer. Does anyone know how to make this code work?
I don't think the problem has anything to do with your Comparable.
If the line while(tree.find(indexreg) != null) { throws a NullPointerException, it must be because tree is null. No other possibilities are credible.
Comparison of an object reference with null using == or != will NOT throw an NPE. So even if tree.find(...) returned a null, that can't be the cause of this exception.
Passing a null value as a method argument will NOT throw an NPE. So if indexreg was null, that wouldn't cause this exception. (An NPE could be thrown by the find method or something it calls, but the stacktrace will not show a different line in a different method as the origin of the exception.)
(I could be misinterpreting the question. I'm assuming that the OP means "throws" when he says that the line "causes" the exception.
Unfortunately, the OP is only posting snippets of code and hasn't shown us the stacktrace ... which is the critical piece of evidence.)
public Comparable find(Comparable x) {
return x == null ? null : elementAt(find(x, root));
}
fyi this is equivalent to:
public Comparable find(Comparable x) {
if (x == null) return null;
return elementAt(find(x, root));
}
You nay also consider improving the clarity of your code: You have a method call and a test combined. While this is not "bad" per se, IMHO it would be cleaner to separate the two, AND get a hold of the value returned in case you want to do something with it, like this:
for (Comparable<?> result = tree.find(indexreg); result != null; result = tree.find(indexreg)) {
//do stuff with variable "result"
}
It just makes it more obvious what is controlling the loop.
There is another way to get the result, but it's considered "bad coding style" by some; that is to assign and test in one:
Comparable<?> result;
while ((result = tree.find(indexreg)) != null) {
//do stuff with variable "result"
}
Some believe that you should avoid this style of coding. I tend to agree with them.
Possibly indexreg is null, not initialized at all. You should certainly code find() more defensively as suggested by #Bohemian but this may be the underlying problem. Or see next comment below.