NullPointerException, everyone should have seen it. This is the idea of a null reference proposed by Tony Hoare in designing the Algol W language, and is designed to ensure that all references are absolutely secure by using a compiler's automatic detection mechanism. Many years later, he regretted the decision he had made, calling it "My big mistake of millions." The consequence of this is---we want to judge a field in an object to check, and we see that we are not looking at an object, but rather a null pointer, and he throws the NullPointerException exception immediately.
Look at the following example:
Public classPerson {Privatecar Car; PublicCar Getcar () {returncar; }} Public classCar {PrivateInsurance Insurance; PublicInsurance getinsurance () {returninsurance; }} Public classInsurance {PrivateString name; PublicString GetName () {returnname; }}
What's wrong with this method?
Public String getcarinsurancename (person p) { return p.getcar (). Getinsurance (). GetName ();
This is a way to get the name of the insurer, but in the library many people may not have a car, so a null reference is returned. There is no car insurance, so return directly to a nullpointerexception.
To avoid this, we typically add null checks where needed, often in a different way.
Avoid nullpointerexception for the first time:
PublicString getcarinsurancename (person p) { if(p! = null ) { car car=P.getcar (); if(car! = null ) { Insurance Insurance=car.getinsurance (); if(insurance! = NULL) { returnInsurance.getname (); } } } return"Unknown"; }
This method does a null check every time a variable is referenced, and returns unknown if any one of the returned values is null. Knowing that the company must have a name, the name of the last insurer was not judged. This approach is not extensible, and it also sacrifices the readability of the code. Each time you have to nest an if to check.
Avoid NullPointerException second attempt:
Public String getcarinsurancename (person p) { if (p = = null) return "Unknown"; Car Car=P.getcar (); if (car = = null) return "Unknown"; Insurance Insurance=car.getinsurance (); if (insurance = = null) return "Unknown"; returnInsurance.getname (); }
The second way, the deep if statement block is avoided, and the method of returning the unknown string directly with NULL is encountered each time. And then the solution is not ideal, and now this method has four distinct exit points, making the code more difficult to maintain. The default value when null occurs, occurs in three different places, and does not know exactly which one returns NULL.
Optional class
A new class java.util.optional<t> is introduced in Java 8. This is a class that encapsulates the optional value. When a variable is present, the optional class is simply encapsulated in the class, and when the variable does not exist, the missing value is modeled as an empty optional object, returned by the method Optional.empty (). This method is a static factory method that returns a specific single instance of the optional class.
Null and Optional.empty () semantically, can be regarded as one thing. In fact, the difference between them is very large: if you try to access a null, a null reference will be triggered. and Optional.empty () can be accessed from anywhere.
public class person { private Optional <car> Car; public Optional <Car> Getcar () { return car; }} public class Car { private Optional <insurance> insurance; public Optional <Insurance> Getinsurance () { return insurance; }}
The name of the company we did not use optional<string> but kept the original type String, then it had to set a value.
Create a optional object
1. Declare an empty optional
Optional<car> Car = Optional. Empty ();
2. Create a optional based on a non-null value
New Car (); Optional<Car> optcar = Optional. of (car);
If car is null, it will directly error the null reference instead of waiting for you to visit.
3. Optional, which can accept NULL, is different from the in, and the compiler will run without error.
NULL ; Optional<Car> optcar = Optional. ofnullable (car);
Extracting and converting values from a optional object using map
Reading information from an object is a more common pattern. For example, you can extract the name of a company from a insurance company object. Before extracting the name you need to check if the insurance object is null, such as:
NULL ; if NULL ) { = insurance.getname (); }
To support this pattern, optional provides a map method.
optional<insurance> optionalinsurance = optional.ofnullable (Insurance); Optional<String> name = Optionalinsurance. Map (Insurance::getname);
The map here is similar to the map in the stream. The map operation applies the provided function to each element of the stream. You can think of a optional object as a special set of data.
This is useful, but how to use it to refactor the previous code?
P.getcar (). Getinsurance (). GetName ();
Optional objects with flatmap links
Using the map you just learned, the first reaction is to rewrite the previous code, such as this:
optional<person> person = optional.of (p); Optional<String> name = person . Map (Person::getcar) . Map (car::getinsurance) . Map ( Insurance::getname);
But this code cannot be compiled, the person is a variable of type optional<person>, there is no problem in calling the map method, but Getcar returns an object of type optional<car>, This means that the result of the map operation is an object of type optional<optinoal<car>>. Therefore it is illegal to call getinsurance.
Using Flatmap in a stream can flatten the merge stream, where you want to merge the two-tier optional into one.
Public String getcarinsurancename (person p) { Optional<Person> person = optional.of (p); return person . FlatMap (Person::getcar). FlatMap (car::getinsurance). map (insurance::getname) . OrElse ("Unknown"); }
The use of optional has obvious advantages when dealing with potentially missing values through code comparisons. You can achieve the desired effect very easily, without having to write so many conditional branches, and without adding complexity to the code.
First, Optional.of (p) generates the Optional<person> object and then calls Person.flatmap (Person::getcar) to return a Optional<car> object. The person in the optional is also converted to this object, and the result is a two-layer optional object, which will eventually be merged by Flatmap operations. If one of the merges is empty, then an empty optional object is formed. If an empty optional object is called, the Flatmap returned is also an empty optional object.
FlatMap (Car::getinsurance) is then converted to optional<insurance> merge. The third step is to call the map method here, because the return type is a string and does not need to be flatmap. Returns null if any one of the results on the connection is empty, otherwise the value returned is the expected value. So finally, a OrElse method is used, and a default value is returned when the optional is empty.
Gets the value of the optional object:
1. Get () is the simplest and least secure method of these methods. If the variable exists, it returns the encapsulated variable value directly. Otherwise throws a nosuchelementexception exception.
2. OrElse (T Other) default value, return value exists, otherwise this default value is returned.
3. Orelseget (supplier< extends t> other) is a deferred call version of the OrElse method, and the Supplier method executes the call only if the optional object does not contain a value.
4. Orelsethrow (supplier< extends x> exceptionsupplier) is similar to the Get method in that it throws an exception when the optional object is empty. You can use Orelsethrow to customize the exception type.
5. Ifpresent (CONSUMER< super t>) executes when a variable value is present, otherwise nothing is done.
Determine if optional has a value isPresent ()
Suppose there is a way to accept two parameters of person and car to inquire about cheap insurers:
Public Insurance getinsurance (person person, car car) { // business logic returnNew Insurance (); }
This is the previous version, using the knowledge we learned today can make a secure version, it accepts two optional object as the parameter return value is also a optional<insurance> method:
Public Static Optional<insurance> getinsuranceopt (optional<person> person,optional<car> Car) { if (person. isPresent () && car. IsPresent()) { return optional.of (Getinsurance (Person.get (), Car.get ())); } return optional.empty (); }
This looks a lot better and more elegant in the way:
Public Static Optional<insurance> getInsuranceOpt1 (optional<person> person, optional<car> Car) { return Person.flatmap (P--Car.map (C-- getinsurance (P, c)); }
If P is empty, the returned empty optional object is not executed. If the car is empty, it will not perform a return empty optional object. Call this method if all have values.
Filter to reject specific values
In addition to the operations in the map and Flatmap methods like streams, there is a filter method. Use filter to quickly determine whether the optional object contains the specified rules, such as:
New Insurance (); if null && insurance.getname (). Equals ("abc")) { System.out.println ("is abc");}
You can use the filter rewrite to:
optional<insurance> insuranceopt = optional.of (Insurance); insuranceopt. Filter(c->c.getname (). Equals ("abc")). Ifpresent (X->system.out.println (x));
Use optional to improve your code
While it's hard to make changes to the old Java API, we can add tools to our own code to fix or circumvent these problems, and to accommodate your code with the power of optional.
Use optional to encapsulate a possible null value
Almost all existing Java APIs represent the absence of a required value by returning a null, or the value cannot be computed for some reason. For example, if the map does not contain a value corresponding to the specified key, its get will return a null. It is very easy for us to return the optional object in this case.
New // NULL
There are two ways to convert to optional objects, the first of which is the if else approach, which is obviously cumbersome. The second is the use of the Ofnullable method.
optional<object> value = optional.ofnullable (new hashmap<string,object> (). Get ("key"));
Each time you want to safely convert a potentially null object, you can convert it to a optional object first.
Anomalies and optional
For some reason, a function cannot return a value, and an exception is thrown in addition to returning null. A typical example is Integer.parseint (string), which converts a string to int. If the string cannot be resolved to an integral type, a NumberFormatException exception is thrown. Generally do this, we will add Try/catch to avoid the program hangs, rather than use if to judge.
Use the optional object to model A string that encounters an inability to convert to return an illegal value, and you expect the return value of parseint to be a optional. Although we cannot change the previous method, we can create a tool method:
Public Static Optional<integer> Stringtoint (String s) { try{ return Optional.of (Integer.parseint (s)); } Catch (Exception ex) { return optional.empty (); } }
We can build a Optionalutils tool class and then create a method for all similar conversion operations. Then Optionalutils.stringtoint (stirng) where needed;
Optional objects of the underlying type
Like the stream object, the optional object also provides a similar underlying type: Optionalint, optionaldouble, Optionallong. However, the three base types do not support the map, FlatMap, and filter methods.
Summary:
1.null references have historically been introduced into programming languages, in order to represent the absence of variable values.
A new class java.util.optional<t> is added to 2.Java 8 to model existing or missing variables.
3. You can use the static factory method Optional.empty, Optional.of, optional.ofnullable to create Optional objects.
4.Optional supports a variety of methods, such as map, FlatMap, and filter, which are conceptually similar to stream.
5. Using optional will force you to refer to the optional object more actively, and to deal with the problem of missing variables, and ultimately you will be more effective in preventing null pointer anomalies in your code.
6. Using optional can help you better design the API, users only need to see the signature wine to know if the method accepts a optional.
Java 8 (9) optional replace null