Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to replace null with Optional in Java8

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces "how to replace null with Optional in Java8". In daily operation, I believe that many people have doubts about how to replace null with Optional in Java8. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the doubt of "how to replace null with Optional in Java8". Next, please follow the editor to study!

How to model missing values

Suppose you need to deal with the following nested objects, which is a customer with car and car insurance.

Public class Person {private Car car; public Car getCar () {return car;}} public class Car {private Insurance insurance; public Insurance getInsurance () {return insurance;}} public class Insurance {private String name; public String getName () {return name }} public String getCarInsuranceName (Person person) {return person.getCar (). GetInsurance (). GetName ();}

This code looks pretty normal, but in real life, many people don't have a car. So what happens when you call the getCar method? In practice, it is common to return a null reference indicating that the value is missing, that is, the user does not have a car.

Next, the call to getInsurance returns the insurance referenced by null, which results in a NullPointerException at run time that terminates the program. But that's not all. What happens if the person value returned is null? What if the return value of getInsurance is also null?

Use defensive inspection to reduce NullPointerException

What can we do to avoid this unexpected NullPointerException? In general, you can add null checks where you need them (aggressive defensive checks can even add detection code where you don't need them), and often in different ways.

Deeply question public String getCarInsuranceName (Person person) {if (person! = null) {Car car = person.getCar (); if (car! = null) {Insurance insurance = car.getInsurance (); if (insurance! = null) {return insurance.getName () } return "Unknown";}

Labeled "Deep query" because it repeats a pattern: every time you're not sure whether a variable is null, you need to add a further nested if block and increase the number of layers of code indentation. Obviously, this approach is not extensible and at the same time sacrifices the readability of the code.

Too many exit statements public String getCarInsuranceName (Person person) {if (person = = null) {return "Unknown";} Car car = person.getCar (); if (car = = null) {return "Unknown";} Insurance insurance = car.getInsurance (); if (insurance = = null) {return "Unknown" } return insurance.getName ();}

You try to avoid deep recursive if blocks and adopt a different strategy: every time you encounter a null variable, a string constant "Unknown" is returned. However, this solution is far from ideal, and now this approach has four distinct exit points, making code maintenance extremely difficult. To make matters worse, the default value returned when null occurs, that is, the string "Unknown" repeats in three different places-- there is a high probability of spelling mistakes! Of course, you might say that we can avoid this problem by extracting them into a constant.

Furthermore, this process is extremely error-prone; what if you forget to check the property that might be null? You will see that it is a big mistake to use null to represent the missing value of a variable.

All kinds of problems brought by null

Using null in Java program development will bring a variety of theoretical and practical problems.

It is the source of error. NullPointerException is the most typical exception in Java program development at present.

It will inflate your code. It fills your code with deeply nested null checks, and the readability of your code is terrible.

It is meaningless in itself. Null itself does not have any semantics, in particular, it represents the modeling of missing variable values in a statically typed language in an incorrect way.

It undermines Java's philosophy. Java has been trying to avoid making programmers aware of pointers, with the only exception: null pointers.

It makes an opening in the type system of Java. Null does not belong to any type, which means that it can be assigned to variables of any reference type. This can cause problems because when this variable is passed to another part of the system, you will not know exactly what type of null variable was originally assigned.

A substitute for null in other languages

Groovy, for example, can securely access variables that may be null by introducing a secure navigation operator (Safe Navigation Operator, marked?).

Def carInsuranceName = person?.car?.insurance?.name

The first impulse of almost all Java programmers when they encounter NullPointerException is to add an if statement to check whether its value is null before calling the method to use the variable, so as to solve the problem quickly. If you solve the problem in this way, regardless of whether your algorithm or your data model should return a null in this situation, then you don't really solve the problem, but temporarily cover up the problem, making it more difficult to investigate and fix the problem next time, and you are probably the one who will face it next week or next month. The way I just did was actually covering my ears and stealing the bell, just cleaning the dust under the carpet.

And Groovy's null safe dereference operator is just a more powerful broom that allows us to make mistakes without scruples. You won't forget to do such a check, because the type system forces you to do so.

Other functional languages, such as Haskell and Scala, try to deal with this problem from another perspective. Haskell contains a Maybe type, which is essentially an encapsulation of the option value. A variable of type Maybe can be a value of a specified type or nothing.

But it doesn't have the concept of null references. Scala has a similar data structure, called option [T], which can either contain a variable of type T or not. To use this type, you must explicitly call an available operation of type Option to check whether the variable has a value, which is actually a disguised "null check".

Getting started with Optional classes

Inspired by Haskell and Scala, a new class java.util.Optional has been introduced in Java 8. This is a class that encapsulates the value of the option. For example, using a new class means that if you know that a person may or may not have a car, then the car variable inside the Person class should not be declared as Car, and the null reference should be assigned to it when someone does not have a car, but should be declared directly as an Optional type.

When a variable exists, the Optional class simply encapsulates the class. When the variable does not exist, the missing value is modeled as an "empty" Optional object, returned by the method Optional.empty (). The Optional.empty () method is a static factory method that returns a specific single instance of the Optional class.

You may also be wondering, is there any fundamental difference between a null reference and Optional.empty ()? Semantically, you can think of them as the same thing, but in practice they are very different: if you try to dereference a null, it must trigger NullPointerException, but it's fine to use Optional.empty (), which is a valid object of the Optional class and can be called in many scenarios.

A very important and practical semantic difference in using Optional instead of null is that in the first example, we use the Optional type instead of the Car type when declaring variables, which makes it very clear that missing variables are allowed here. In contrast, using a type such as Car may assign a variable to null, which means that you need to deal with this independently, and you can only rely on your understanding of the business model to determine whether a null belongs to the valid category of the variable.

ReFactor the original code using the Optional class

Public class Person {private Optional car; public Optional getCar () {return car;}} public class Car {private Optional insurance; public Optional getInsurance () {return insurance;}} public class Insurance {private String name; public String getName () {return name;}}

Using Optional consistently in your code can clearly define whether the missing value of a variable is a structural problem, a flaw in your algorithm, or a problem in your data. In addition, we would like to emphasize that the introduction of the Optional class is not intended to eliminate every null reference. On the contrary, its goal is to help you better design a universal API, so that programmers can see the method signature and know whether it accepts a value of Optional. This compulsion will make you more aggressive in unwrapping variables from Optional and confront missing variable values.

Apply several modes of Optional to create an Optional object that declares an empty OptionalOptional optCar = Optional.empty (); create OptionalOptional optCar = Optional.of (car) based on a non-null value

If car is a null, this code immediately throws a NullPointerException instead of waiting for you to try to access the property value of car before returning an error.

Accept OptionalOptional optCar = Optional.ofNullable (car) of null; use map to extract and convert values from Optional objects

Extracting information from objects is a common pattern. For example, you might want to extract the company name from the insurance company object. Before extracting the name, you need to check whether the insurance object is null

String name = null;if (insurance! = null) {name = insurance.getName ();}

To support this pattern, Optional provides a map method

Optional optInsurance = Optional.ofNullable (insurance); Optional name = optInsurance.map (Insurance::getName)

Use flatMap to link the Optional object public String getCarInsuranceName (Person person) {return person.getCar () .getInsurance () .getName ();}

Your first reaction may be that we can rewrite the previous code using map

Optional optPerson = Optional.of (person); Optional name = optPerson.map (Person::getCar) .map (Car::getInsurance) .map (Insurance::getName)

Unfortunately, this code cannot be compiled.

OptPerson is a variable of type Optional, so there should be no problem calling the map method. But getCar returns an object of type Optional, which means that the result of the map operation is an object of type Optional.

Therefore, its call to getInsurance is illegal because the outermost optional object contains the value of another optional object, and it certainly does not support the getInsurance method.

The flatMap method solves this problem.

When using a stream, the flatMap method takes a function as an argument, and the return value of this function is another stream. This method is applied to every element of the flow, resulting in a new stream. But flagMap replaces each newly generated stream with the contents of the stream.

In other words, the streams generated by the method are merged or flattened into a single stream. The result you want here is actually similar, but what you want is to merge the two layers of optional into one.

In this example, the flatMap method passed to the stream converts each square into two triangles in another stream. Then, the result of the map operation contains three new streams, each containing two triangles, but the flatMap method merges this two-layer stream into a single stream with six triangles.

Similarly, the function passed to the flatMap method of optional converts the original optional object that contains squares into optional objects that contain triangles. If you pass this method to the map method, the result is an Optional object that contains triangles, but the flatMap method converts this two-tier Optional object into a single Optional object that contains triangles.

Use Optional to obtain the insurance company name of car public String getCarInsuranceName (Optional person) {return person.flatMap (Person::getCar) .flatMap (Car::getInsurance) .map (Insurance::getName) .orElse ("Unknown");}

By comparing the previous two code listings, we can see that using Optional has a clear advantage when dealing with potentially missing values. This time, you can achieve the desired results in a very easy but universal way-no longer need to use so many conditional branches, and will not increase the complexity of the code.

Once again, you can see the advantages of this approach, which allows the knowledge hidden in your domain model to be explicitly reflected in your code through the type system, in other words, you should never forget that the primary function of the language is communication. it makes no difference even for programming languages. Declare that the method accepts an Optional parameter, or returns the result as an Optional type, so that your colleagues or future users of your method know clearly that it can accept a null value, or that it may return a null value.

Dereferencing concatenated Person/Car/Insurance objects using Optional

From the Optional object, we can use the map and flatMap methods described earlier to de-reference Car from Person, de-reference Insurance from Car, and de-reference a string containing the name of the insurance company from the Insurance object.

Use Optional in the domain model and why they cannot be serialized

The above shows how to use Optional in your domain model to mark the values of variables that are allowed to be missing or temporarily undefined in a special form. However, the original intention of Optional designers is not that, they are conceived with another use case. At this point, Brian Goetz, the architect of the Java language, has made it very clear that Optional is only designed to support syntax that returns Optional objects.

Because the Optional class is not designed to be used as a field of the class, it does not implement the Serializable interface. For this reason, if your application uses some library or framework that requires serialization, using Optional in the domain model may cause application failure.

However, from the previous introduction, you have seen that it is a good idea to declare certain types in the domain model with Optional, especially if you need to traverse objects that may be completely or partially empty or may not exist. If you must implement a serialized domain model, as an alternative, we recommend that you provide an interface that can access a variable declared as Optional and may be missing as shown in the following example. The code listing is as follows:

Public class Person {private Car car; public Optional getCarAsOptional () {return Optional.ofNullable (car);}} default behavior and dereferencing Optional object

The Optional class provides several ways to read the value of a variable in an Optional instance.

Get () is the simplest but least secure of these methods. If the variable exists, it directly returns the value of the encapsulated variable, otherwise a NoSuchElementException exception is thrown. So, unless you are quite sure that the Optional variable must contain a value, it is a pretty bad idea to use this method. In addition, this approach does not show much improvement over nested null checking.

OrElse (T other) is the method we used in listing 10-5, and as mentioned earlier, it allows you to provide a default value when the Optional object does not contain a value.

OrElseGet (Supplier

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report