5

I am refactoring the code to Java 8 and I want to replace null checks with Optional.

public Employee findEmployeeById(String id) {
    List<Employee> empList = .. //some db query
    return (empList.isEmpty() ? null : empList.get(0));
}

Optional.ofNullable(empList.get(0)) won't work as when it will throw IndexOutofBoundException

Or should I ideally replace null with Optional.empty()?

5
  • Why doesn't your query only return a single result in the first place? Commented May 13, 2017 at 9:57
  • That is a complex logic ....of left joins and all....I understand you point but cant really change that Commented May 13, 2017 at 9:58
  • 6
    return empList.isEmpty() ? Optional.empty() : Optional.of(empList.get(0)); Commented May 13, 2017 at 9:58
  • When I replace this code and inspect Optiona.empty() ,it shows null then what is the use to use Optional Commented May 13, 2017 at 10:23
  • 1
    Optional wraps a reference to an object, or nothing. Of course, inside the Optional, it it wraps nothing, the reference to the object is null. What else could it be? What matters is that what your method returns is an Optional, which is never null, and which forced the caller to think about and deal with an empty value. Commented May 13, 2017 at 11:17

4 Answers 4

10

As @Jesper already mentioned in the comments, you have to check whether the list is empty and then return an empty Optional.

public Optional<Employee> findEmployeeById(String id) {
    List<Employee> empList = .. //some db query
    return empList.isEmpty() ? Optional.empty() : Optional.of(empList.get(0));
}

An Optional is a wrapper around a potentially null value that allows you to avoid explicitly checking for null when you use it.

Have a look at the Optional documentation to see what functionality it provides.

For example you can get an employee's name or "unknown" if it's absent, without checking for null:

Optional<Employee> emp = findEmployeeById(id);
String name = emp.map(Employee::getName).orElse("unknown");

You may read this post about Uses for Optional to see if it makes sense for you to use Optional.

Sign up to request clarification or add additional context in comments.

2 Comments

Isn't it bad to return Optional.of instead of Optional.ofNullable as a practice?
@BilboBaggins if the value can be null, then yes, you have to use Optional.ofNullable().
6

To me the natural solution would be to keep your ? : construct as in Floern’s answer. If, however, you want to get rid of that, there is also an elegant solution without it:

public Optional<Employee> findEmployeeById(String id) {
    List<Employee> empList = .. //some db query
    return empList.stream().findFirst();
}

This gives you what you want because findFirst() returns an Optional. If you don’t care which element you get — or you know there’s never more than one — you may alternatively use findAny(), it too returns an Optional.

2 Comments

Good one, didn't think about that
Nice! You don't even need the empList local, so this can be reduced to return someDbQuery().stream().findFirst().
3

Why don't you simply replace your method with:

public Optional<Employee> findEmployeeById(String id) {
    List<Employee> empList = .. //some db query
    return (empList.isEmpty() ? Optional.empty() : 
              Optional.ofNullable(empList.get(0)));
}

I suggest you wrap the empList.get(0) in a Optional.ofNullable in case it might still be null.

As far as why that is better: think about the caller of the method. Whomever is now calling your method has to think what to actually do when the result is empty.

Besides you are now forced into writing code like:

Optional<Employee> emp = findEmployeeById("12");

if (emp.isPresent()) {

} else {
    ....
}

You can also chain this to become more fluent like:

emp.orElseThrow(RuntimeException::new)

Or other Optional methods.

That is simply not the case when you return an Employee. You are not even thinking (usually) to check if the reference is null.

That makes your code less error-prone and easier to understand.

Comments

2

Another possibility would be to do it as follows:

return Optional.of(empList).filter(list -> !list.isEmpty()).map(list -> list.get(0));

This will automatically return an empty Optional in case the list is empty or empList.get(0) returns null.

If empList can be null, consider using Optional.ofNullable(empList) instead of Optional(empList).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.