One, foreword

If I were to make a list of all Java exceptions, I would put NullPointerException at the top of the list. This exception lurks in the code like a remote-controlled bomb, never knowing when the button will suddenly be pressed (passing in a NULL object).

I still remember when I was a programmer, I encountered the Bug caused by null pointer exception every two days. After solving one, I encountered it in another place. At that time, my senior brother taught me not to trust any “object”, especially those given to you, and to add judgment to these places. So the code would normally look like this:

if(obj! =null) {// do something
}
Copy the code

With this defense, you don’t have to worry about null-pointer exceptions anymore, but too many judgment statements make your code bloated.

Suppose we have the following object relationship

To get the name attribute in the graph, it was easy to do in a single line of code.

Staff staff=.. ; staff.getDepartment().getCompany().getName();Copy the code

Unfortunately, for the sake of code security, we have to add a null pointer to our code.

Staff staff=.. ;if(staff ! =null) {
    Department department = staff.getDepartment();
    if(department ! =null) {
        Company company = department.getCompany();
        if(company ! =null) {
            returncompany.getName(); }}}return "Unknown";
Copy the code

When the object is null, the default value can be returned, as shown above. You can also throw other exceptions to fail quickly.

While the code above has become more secure, too many nested IF statements reduce the overall readability of the code and increase its complexity.

Fortunately, Java 8 introduces a new class java.util.Optional

, which provides an API that allows you to write code that is both safe and readable.

Still using JDK 6? Well, don’t be so quick to shut this article down. Consider Guava Optional. The Guava Optional API differs from the JDK. The following uses JDK8 Optional as an example.

Second, the Optional apis

2.1、Optional#of 与 Optional#ofNullable

Optional is essentially a container into which we pass an object instance. The Optional constructor is private, so you cannot build objects directly using new. You can only create objects using static methods provided by Optional.

Optional three creation methods are as follows:

  • Optional.of(obj)If the object is null, an NPE will be thrown.
  • Optional.ofNullable(obj)If the object is null, an object with no value will be createdempty OptionalObject instance.
  • Optional.empty()Is equivalent toOptional.ofNullable(null)

Use option #of only if you are certain that the object will not be null, otherwise the option #ofNullable method is recommended.

2.2, Option #get and option #isPresent

Once the object instance is stored in the Optional container, we finally need to pull it out of it. The Optional#get method is used to fetch an internal object instance, but note that if it is an Empty Optional instance, since there are no object instances in the container, using the GET method will throw a NoSuchElementException.

To prevent exceptions from being thrown, use option #isPresent. This method will determine if there is an internal instance of the object and return true if there is.

Example code is as follows:

Optional<Company> optCompany = Optional.ofNullable(company);
// It is no different from using null Pointers directly
if (optCompany.isPresent()) {
    System.out.println(optCompany.get().getName());
}
Copy the code

Careful comparison shows that the above usage is no different from the null pointer check. When I first came across Optional, I read a lot of articles about its use, and I was wondering if this solution was more troublesome.

It wasn’t until I looked at the Optional apis that I realized the real value of this class was the following ones. If you have used the Java8 Stream API, the following Optional API will be familiar to you.

2.3, Optional# ifPresent

Normally, after the null pointer is checked, if the object is not null, the next step, such as printing the object, is taken.

Company company = ... ;if(company! =null){
    System.out.println(company);
}
Copy the code

We can replace the above code with option #ifPresent as follows:

Optional<Company> optCompany = ... ; optCompany.ifPresent(System.out::println);Copy the code

With the ifPresent method, we do not need to check the display. If Optional is empty, the above example will not be printed.

2.4, Optional# filter

Sometimes we need certain attributes to meet certain conditions before we can proceed to the next step. Suppose we print OK when the Company name property is Apple.

if(company ! =null && "Apple".equals(company.getName())) {
    System.out.println("ok");
}
Copy the code

Let’s rewrite the above code using option #filter in conjunction with Option #ifPresent as follows:

Optional<Company> companyOpt=... ; companyOpt .filter(company ->"Apple".equals(company.getName()))
        .ifPresent(company -> System.out.println("ok"));
Copy the code

The filter method determines whether the object meets the criteria. If not, an empty Optional is returned.

Option #orElse and Option #orElseThrow

When an object is null, it is often possible to set a default value for the business to continue the process.

String name = company ! =null ? company.getName() : "Unknown";
Copy the code

Or throw an internal exception, record the cause of the failure, and fail quickly.

if (company.getName() == null) {
    throw new RuntimeException();
}
Copy the code

The Optional class provides two methods, orElse and orElseThrow, to facilitate the above transformation.

// Set the default value
String name=companyOpt.orElse(new Company("Unknown")).getName();

// Throw an exception
String name=companyOpt.orElseThrow(RuntimeException::new).getName();
Copy the code

If Optional is empty, provide a default value or throw an exception.

Option #map and Option #flatMap

Those familiar with Java8 Stream should know that the Stream#map method can convert the current object to another object, and the Option # Map method is similar.

Optional<Company> optCompany = ... ; Optional<String> nameopt = optCompany.map(Company::getName);Copy the code

The map method converts the original Optional

to Optional

, in which case the Optional internal object becomes a String. If the Optional object is empty before the conversion, nothing happens.

Optional also has a flatMap method, as shown in the figure below.

Department#getCompany returns the object as Optional

Third, code refactoring

Now that you’ve seen the main API of the Optional class, let’s use Optional to refactor the code we started this article with. The above code has been copied for comparison purposes.

Before code refactoring:

if(staff ! =null) {
    Department department = staff.getDepartment();
    if(department ! =null) {
        Company company = department.getCompany();
        if(company ! =null) {
            returncompany.getName(); }}}return "Unknown";
Copy the code

So the first thing we need to do is change the Staff Department to change the getter to Optional.

public class Staff {
    private Department department;
    public Optional<Department> getDepartment(a) {
        returnOptional.ofNullable(department); }... }public class Department {

    private Company company;
    public Optional<Company> getCompany(a) {
        returnOptional.ofNullable(company); }... }public class Company {
    private String name;
    public String getName(a) {
        returnname; }... }Copy the code

Then use the Optional API to refactor the code as follows:

Optional<Staff> staffOpt =... ; staffOpt .flatMap(Staff::getDepartment) .flatMap(Department::getCompany) .map(Company::getName) .orElse("Unknown");
Copy the code

As you can see, the Optional Fluent Interface and lambda expressions are used to make the code more Fluent and coherent, and improve the overall readability of the code.

Help article

1、Tired of Null Pointer Exceptions? Consider Using Java SE 8’s Optional!

3、Optionals: Patterns and Good Practices

3、Java8 in Action

Welcome to pay attention to my public account: procedures to get daily dry goods push. If you are interested in my topics, you can also follow my blog: studyidea.cn