[New Features of Java 8] 05 Use Optional instead of null

Java8 was released by Oracle in 2014 and is the most revolutionary version after Java5.

Java 8 absorbs the essence of other languages ​​and brings a series of new features such as functional programming, lambda expressions, and streams. After learning these new features, you can achieve efficient coding and elegant coding.

1. Unwanted null pointer exception

There is a short story: the null citation was first proposed by British scientist Tony Hoare. Many years later, Hoare regretted his idea and thought it was "a major mistake worth a million." It can be seen how unpopular the null pointer is.

NullPointerException is the most frequently encountered exception in Java development. When encountering this exception, our usual solution is to add an if to null at the call.

The more if there are more blanks, it will cause too many code branches, and subsequent code maintenance will become more and more complicated.

2. Bad code

For example, look at the following example, using too many ifs to determine nulls.

The House object is defined in the Person object, and the Address object is defined in the House object:

public class Person {
    
    
    private String name;
    private int age;
    private House house;

    public House getHouse() {
    
    
        return house;
    }
}

class House {
    
    
    private long price;
    private Address address;

    public Address getAddress() {
    
    
        return address;
    }
}

class Address {
    
    
    private String country;
    private String city;

    public String getCity() {
    
    
        return city;
    }
}

Now get the city where the person bought the house, then usually write like this:

public String getCity() {
    
    
    String city = new Person().getHouse().getAddress().getCity();
    return city;
}

But writing this way is prone to the problem of null pointers. For example, this person has no room and the House object is null. Then you will modify this code and add a lot of judgment conditions:

public String getCity2(Person person) {
    
    
    if (person != null) {
    
    
        House house = person.getHouse();
        if (house != null) {
    
    
            Address address = house.getAddress();
            if (address != null) {
    
    
                String city = address.getCity();
                return city;
            }
        }
    }
    return "unknown";
}

In order to avoid null pointer exceptions, judgments are added to each layer, but this will cause the code to be nested too deep and difficult to maintain.

You may think of how to modify the above code, for example, add an empty exit in advance:

public String getCity3(Person person) {
    
    
    String city = "unknown";
    if (person == null) {
    
    
      return city; 
    }

    House house = person.getHouse();
    if (house == null) {
    
    
        return city;
    }

    Address address = house.getAddress();
    if (address == null) {
    
    
        return city;
    }

    return address.getCity();
}

But such a simple code has added three exit conditions, which is not conducive to the maintenance of the code behind. So how can we write the code more elegantly, let's introduce today's protagonist "Optional".

3. Solve the "silver bullet" of null pointers

A new class java.util.Optional has been introduced since Java8, which is a container of objects, which means that it may or may not contain a non-empty value. Let's focus on the common methods of Optional:

public final class Optional<T> {
    
    
    // 通过指定非空值创建Optional对象
    // 如果指定的值为null,会抛空指针异常
    public static <T> Optional<T> of(T value) {
    
    
        return new Optional<>(value);
    }
    
    // 通过指定可能为空的值创建Optional对象
    public static <T> Optional<T> ofNullable(T value) {
    
    
        return value == null ? empty() : of(value);
    }

    // 返回值,不存在抛异常
    public T get() {
    
    
        if (value == null) {
    
    
            throw new NoSuchElementException("No value present");
        }
        return value;
    }
    
    // 如果值存在,根据consumer实现类消费该值
    public void ifPresent(Consumer<? super T> consumer) {
    
    
        if (value != null)
            consumer.accept(value);
    }
    
    // 如果值存在则返回,如果值为空则返回指定的默认值
    public T orElse(T other) {
    
    
        return value != null ? value : other;
    }

    // map flatmap等方法与Stream使用方法类似,这里不再赘述,读者可以参考之前的Stream系列。
}

The above is the commonly used method of the Optional class, it is very simple to use.

4. Getting started with Optional

(1) Create an Optional instance

  • Create an empty Optional object. You can create an empty object through the static factory method Optional.Empty(), for example:
Optional<Person> optionalPerson = Optional.Empty();
  • Specify a non-empty value to create an Optional object.
Person person = new Person();
Optional<Person> optionalPerson = Optional.of(person);
  • Specify a value that may be empty to create an Optional object.
Person person = null; // 可能为空
Optional<Person> optionalPerson = Optional.of(person);

(2) Common methods

ifPresent

If the value exists, the consumer instance is called to consume the value, otherwise nothing is executed. Give a chestnut:

String str = "hello java8";
// output: hello java8
Optional.ofNullable(str).ifPresent(System.out::println);

String str2 = null;
// output: nothing
Optional.ofNullable(str2).ifPresent(System.out::println);

filter, map, flatMap

The three methods have been explained in detail when we talked about Stream. Readers can read the articles written before, so I won't repeat them here.


If the value is empty, orElse returns the default value, for example:

public void test(String city) {
    
    
    String defaultCity = Optional.ofNullable(city).orElse("unknown");
}

orElseGet

If the value is empty, the Supplier instance is called to return a default value. for example:

public void test2(String city) {
    
    
    // 如果city为空,则调用generateDefaultCity方法
    String defaultCity = Optional.of(city).orElseGet(this::generateDefaultCity);
}

private String generateDefaultCity() {
    
    
    return "beijing";
}

orElseThrow

If the value is empty, a custom exception is thrown. Give a chestnut:

public void test3(String city) {
    
    
    // 如果city为空,则抛出空指针异常。
    String defaultCity = Optional.of(city).orElseThrow(NullPointerException::new);
}

5. Refactor the code with Optional

Look at the code before refactoring again, using three ifs to make the code nesting level deep.

// before refactor
public String getCity2(Person person) {
    
    
    if (person != null) {
    
    
        House house = person.getHouse();
        if (house != null) {
    
    
            Address address = house.getAddress();
            if (address != null) {
    
    
                String city = address.getCity();
                return city;
            }
        }
    }
    return "unknown";
}

Refactor with Optional

public String getCityUsingOptional(Person person) {
    
    
    String city = Optional.ofNullable(person)
            .map(Person::getHouse)
            .map(House::getAddress)
            .map(Address::getCity).orElse("Unknown city");
    return city;
}

Only one line of code is used to get the city value, and there is no need to constantly judge whether it is empty. Isn't it elegant to write code like this? Hurry up and refactor your project with Optional~

— end —

Laughter architects are not too bad in technology. Search "Laughing Architects" on WeChat, and more technical dry goods will be posted as soon as possible!

Finally, I will give you a bonus. The laughable architect has collected a lot of technical genuine e-books and technical videos. After paying attention to the official account, reply to the number 666 to get it for free.

Guess you like

Origin blog.csdn.net/guoguo527/article/details/108805479