Java8 introduced a very interesting Optional class it is to solve the infamous null pointer exception (NullPointerException). When we checked object's properties to determine whether its value to the desired format, only to find not a target we are looking at, but a null pointer, it will immediately throw an annoying NullPointerException exception.
Throwing bricks
Let's look at a simple example:
String address = world.getCountry.getCity.getName;
复制代码
Prior to get the address needs to be checked for each category to prevent null pointer exception:
public String getAddress(World world){
if (world != null){
Country country = world.getCountry();
if (country!=null){
City city = country.getCity();
if (city != null){
return city.getName();
}
}
}
return "unknown";
}
复制代码
You can see how complicated the above checks, the code filled with empty check readability abysmal.
Optional class entry
Variable exists, Optional simply package the class class. When the variable does not exist, the missing value is modeled as a "empty" Optional objects () method returned by Optional.empty. Then you might wonder difference, null and Optional.empty () in which it? Semantically, one thing you can think of them as children, but the real difference between them is very large: if you try to dereference a null, will trigger NullPointerException, but use Optional.empty () is completely all right it is a valid object Optional classes, a variety of scenarios can be called, is very useful.
Optional application of several models
Optional object instance is created
You can create an empty object instance Optional
@Test(expected = NoSuchElementException.class)
public void createOptionalObject(){
Optional<String> country = Optional.empty();
country.get();
}
复制代码
There is no doubt that when we call the get () method will be reported abnormal NoSuchElementException
Can also create Optioanal Examples include the use of values () and ofNullable () method, except that if the pass in as a parameter of null () will be reported null pointer exception, the presence or absence of an object may be, should be used ofNullable ()
@Test
public void createOptionalObject(){
Optional<String> country = Optional.of("中国");
Optional<String> city = Optional.ofNullable("上海");
Optional<String> world = Optional.ofNullable(null);
//下面会报空指针异常
Optional<String> province = Optional.of(null);
}
复制代码
How to get the value Optional variables? Optional offers a get () method. But get method when empty Optional encountered objects will throw an exception, so do not use it in the agreed manner, but let us once again into the code caused by a null maintenance nightmare.
Value Optional object access
One way to retrieve the actual value of the object instance is to use the Optional get () method:
@Test
public void getOptionalObject(){
String country = "China"
Optional<String> countryName = Optional.ofNullable(country);
Assert.assertEquals("China",countryName.get());
}
复制代码
Of course, this method throws an exception if the value is null, to avoid abnormal, we must first check
@Test
public void getOptionalObject(){
City city = new City("ShangHai");
Optional<City> sample = Optional.ofNullable(city);
Assert.assertTrue(sample.isPresent());
Assert.assertEquals(city.getName(),sample.get().getName());
}
复制代码
Check whether there is value there is another method ifPresent (), which will be passed in addition to checking a Consumer (consumer) parameter, if the object is not empty, it will execute the incoming Lambda expressions
@Test
public void getOptionalObject(){
City city = new City("ShangHai");
Optional<City> sample = Optional.ofNullable(city);
sample.ifPresent(c -> Assert.assertEquals(city.getName(),sample.get().getName()));
}
复制代码
If the object is not empty assertion was executed
Return to the default value
Optional provides an API to return the value of the object, or the object returns to the default value is empty
@Test
public void getOptionalObject(){
City city = null;
City city1 = new City("ShangHai");
City sample = Optional.ofNullable(city).orElse(city1);
Assert.assertEquals(city1.getName(),sample.getName());
}
复制代码
The second is the same type of API orElseGet () - behaves slightly differently. This method will return a value when there is the value, if no value, it performs as a parameter a Supplier (provider) interface function, and returns the execution result:
City sample = Optional.ofNullable(city).orElseGet(() -> city1);
复制代码
Abnormal return
Optional also defines orElseThrow () API it will throw an exception when the subject is empty
@Test(expected = IllegalArgumentException.class)
public void throwOptionalException(){
City city = null;
City sample = Optional.ofNullable(city).orElseThrow(() -> new IllegalArgumentException());
}
复制代码
city is empty it will throw an IllegalArgumentException
This approach gives us a richer semantics, what kind of abnormality may decide to throw, but not always throw NullPointerException.
Examples of actual use Optional
Optional objects extracted from the map using the converted value and
Information extracted from the object is a relatively common pattern, in order to support this model, Optional provides a map method. It works as follows:
@Test
public void getCityName(){
City city = new City("ShangHai");
Optional<City> sample = Optional.ofNullable(city);
Optional<String> name = sample.map(City::getName);
}
复制代码
map of the value of the application (call) as a function of the parameter, and then return the value of the package in the Optional in, which makes the return value chain retried operation is made possible, it is not possible to reconstruct the code for it before ?
public Optional<String> getCityName(World world){
Optional<World> real = Optional.ofNullable(world);
Optional<String> name =
real.map(World::getCountry)
.map(Country::getCity)
.map(City::getName);
return name;
}
复制代码
However, this code will not compile, real.map (World :: getCountry) returns an instance Optional this is no problem, but the object is to continue to call back Optional <Optional> type map generated. That you suffered a nested Optional institutions.
Optional two-layer structure of the object
Optional use flatMap link objects
So, how do we solve this problem? Let us recall that you just used in streaming mode: flatMap method. When using a stream, flatMap accepts a function as an argument, a return value of this function is another stream. This method will be applied to each element of flow, eventually forming a new stream flow. But flagMap each stream will be replaced with the newly generated content stream. In other words, each stream generated by the process will be merged into a single flattened or streams. Here you desired result is actually similar, but what you want is two layers of optional combined into one.
public Optional<String> getCityName(World world){
Optional<World> real = Optional.ofNullable(world);
Optional<String> name =
real.flagMap(World::getCountry)
.flagMap(Country::getCity)
.map(City::getName);
return name;
}
复制代码
Use filter excluding certain value
Do you often need to call an object method, then you should first check the object is NULL
public void filterCity(City city){
Optional<City> real = Optional.ofNullable(city);
real.filter(c -> c!=null && "ShangHai"
.equals(c.getName()))
.ifPresent(x -> System.out.println("ok"));
}
复制代码
summary
- null references are introduced to the programming language in history, the purpose is to represent the missing variable values.
- Java 8 introduces a new class java.util.Optional, the presence or absence of variable values modeling.
- Optional you can create objects using a static factory method Optional.empty, Optional.of and Optional.ofNullable.
- Optional class supports a variety of methods, such as map, flatMap, filter, and their corresponding methods Stream class is very similar in concept.
- Optional will force you to use more actively Optional dereference objects, in order to deal with the issue of the missing variable values, eventually, you can more effectively prevent the unexpected emergence of the code and to the null pointer exception.
- Optional use can help you design a better API, users only need to read the method signature, you will be able to know whether the method accepts a value of type Optional.