Optional use of torture to get rid of NPE

architectural-architectural-design-architecture

In the present work, I have to use a lot of Java in the Stream and Lambda expressions, before also wrote two articles summarize the corresponding knowledge.

Optional but for this feature has not been well used up, so recently started reading "Java 8 real" book, this is where the Chapter 10 for a study summary.

background

In Java, if you attempt to make null function call, it will trigger NullPointerException (NPE), NPE is the most typical abnormal Java program development for Java developers, whether you are inexperienced newcomers and also worked for many years old driver, NPE often let them roll. To avoid NPE, they will add a lot if the judge sentences, making the code readability becomes poor.

From a software design point of view, null itself is meaningless semantics, this is the wrong kind of modeling missing variable values.

From the perspective of the Java type system perspective, null can be assigned to any type of variable, and continues to be passed, and finally know who do not know where it was introduced.

Optional introduction of

Java designers get inspiration from Haskell and Scala, the introduction of a new class in Java 8 in java.util.Optional<T>. If an interface return Optional, can represent a person may or may not have a car the car, the Car than a simple return to be more clear, people do not need to read the code of business knowledge to prepare in advance.

Optional objective lies in this: by type of system allows your domain model hidden knowledge explicitly reflected in your code.

Optional use of

method description
empty Optional return an empty instance
filter If the value exists and filtered to provide the condition is satisfied, the return value is an object containing Optional; otherwise returns an empty Optional objects
map If the value exists, mapping function to perform on the value of the calls provided
flatMap If the value exists, it is executed to provide the mapping function value of the call, the return value of a type Optional, otherwise it returns an empty Optional objects
ifPresent If the value exists, the implementation method of using the value of the call, otherwise do nothing
of After the specified value Optional package returned, if the value is null, throw an NPE
ofNullable After the specified value Optional package returned, if the value is null, an object is returned empty Optional
orelse If there is value is returned, otherwise a default value
orElseGet If value is returned, otherwise a Supplier generated by the designated interface value (default value if the cost of generating relatively high, then suitable methods orElseGet)
orElseThrow If the value is returned, otherwise a return by the specified exceptions thrown Supplier Interface
get If the value exists, the value is returned, otherwise an exception is thrown a NoSuchElementException
isPresent If the value is returned there is true, false otherwise

This table lists the basic API Optional above, I Here are a few tips to use:

  • You can use ofNullable may be a null object encapsulation for Optional object, and then get the time value of using orElse method to provide default values; you can create an object using empty empty Optional method; of methods generally do not, but if you know a impossible to null value, this value can be used Optional package, so that once it is null will throw an exception.
//empty方法的使用
Optional<Car> optCar = Optional.empty();

//of方法的使用
Optional<Car> optCar = Optional.of(car);

//ofNullable方法的使用
Optional<Car> optCar = Optional.ofNullable(car);
复制代码
  • Value of a field value you can use the map method Optional object from its package in;
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName); 
复制代码
  • If continuous, progressive layers to obtain the value of an object field from the end of the chain, you can not use all the map method, need to use a flatMap, and finally use the map method;
//转换之前
public String getCarInsuranceName(Person person) {
  return person.getCar().getInsurance().getName();
}

//转换后
public String getCarInsuranceName(Optional<Person> person) {
  return person.flatMap(Person::getCar)
               .flatMap(Car::Insurance)
               .map(Insurance::getName)
               .orElse("Unknown");
}
复制代码
  • Optional in the map, flatMap filter method, the concept of the method is very similar to the corresponding Stream, Optional difference is at most one of the elements, considered a special case of Stream - a special set.
  • Do not use ifPresent and get methods, and they are essentially not applicable Optional objects before the same pattern, are bloated determines if-then-else statements;
  • Since Optional can not be serialized, so in the domain model, could not be defined as a field Optional, because: Optional is designed to support only able to return Optional object syntax, if we want to introduce Optional in the domain model, this alternative may be by the following method:
public class Person {
  private Car car;
  public Optional<Car> getCarAsOptional() {
    return Optional.ofNullable(car);
  }
}
复制代码
  • Do not use the underlying type Optional object because: Optional base type of object does not support the map, flatMap and filter methods, and these methods are Optional very powerful way.

Real case

Case 1: Using the tools improved method might throw an exception API

There are two ways to handle exceptions Java method results: Returns null (or error code); throws an exception, for example: Integer.parseInt (String) This method - if not resolved to the corresponding integer, which throws a NumberFormationException, in which case we will generally use try / catch statement to handle exceptions.

We generally recommend the try / catch block to a single extraction method, this method is used here Optional design, as follows. In a development, you may attempt to build a OptionalUtility tools, these complex try / catch logic encapsulated.

public static Optional<Integer> stringToInt(String a) {
  try{
    return Optional.of(Integer.parseInt(s));
  } catch  (NumberFormationException e) {
    return Optional.empty();
  }
}
复制代码

Case 2: Integrated Case

Now there is a method, it is to try to obtain a value corresponding to a keyword from an attribute mapping, the following sample code:

   public static int readDuration(Properties properties, String name) {
        String value = properties.getProperty(name);
        if (value != null) {
            try {
                int i = Integer.parseInt(value);
                if (i > 0) {
                    return i;
                }
            } catch (NumberFormatException e) {

            }
        }
        return 0;
    }
复制代码

Optional wording after use, the code is as follows:

    public static int readDurationWithOptional(Properties properties, String name) {
        return Optional.ofNullable(properties.getProperty(name))
            .flatMap(OptionalUtility::stringToInt)
            .filter(integer -> integer > 0)
            .orElse(0);
    }
复制代码

If the attribute values ​​require access does not exist, the return value Properites.getProperty (String) method is a null, the method can be used noNullable plant to convert the value Optional objects; Next, flatMap can be converted to a Optional Optional objects ; finally filtered using filter negative, then you can use orElse getting a property value, a default value is returned if the get 0.

to sum up

Optional use the same ideas and Stream, is a chain of ideas, with database queries like, express very strong, but also eliminates the need for complex which try / catch and if-then-else approach. Later developed may be used Optional design API, allowing to design a more secure interfaces and methods.


This focus on the number of back-end technology, JVM troubleshooting and optimization, Java interview questions, personal growth and self-management, and other topics, providing front-line developers work and growth experience for the reader, you can expect to gain something here.

Jwadu

Guess you like

Origin juejin.im/post/5d33bdeb51882557d67fe513