Home Page
Column
Online Course
Developer Tools
Home Page
Column
Online Course
Developer Tools
更多
Follow the community
User Center
Developer Center
>
Column
>
Details
Go deep into the Optional in the JDK
Self-justification Tech
2021-05-26
IP归属:未知
88567 browse
Computer Programming
**Overview**: Optional is a concept originally provided by Google’s Guava and represents an optional value. The Optional class has been added to the deluxe package since Java8 to address NPE problem in applications, resulting in less explicit null evaluation, less code contamination and, on the other hand, explicit representation of knowledge hidden in the domain model. The Optional class is located under the java.util package and has certain support for the chain programming style. In fact, Optional is more like a container, in which the member variable stored is a value of type T, which can be valued or Null. It is in Wrapper mode and the value operation is packaged and designed. This article begins with the problems solved by Optional, dissects the Optional layer by layer progressively, and provides the comparison, practices, misuse case analysis, advantages and disadvantages of Optional methods. Let’s have an insight into this new feature in Java8. ## 1. Existing Problems The notorious null point exception (NPE) is a common exception that might be encountered by every programmer.Any calls to methods or attributes that access an object may result in a null point exception. In general, we should evaluation whether the object is null so as not to trigger the NPE. For example, a shopper may go into a supermarket and shop in a Trolley or otherwise. There may or may not be a bag of chestnuts in the trolley. The code defined for these three is as follows: ```java public class Shopper { private Trolley trolley; public Trolley getTrolley(){ return trolley; } } public class Trolley { private Chestnut chestnut; public Chestnut getChestnut(){ return chestnut; } } public class Chestnut { private String name; public String getName(){ return name; } } ``` If you want to get the name of the chestnut in your trolley, and write as follows, you may encounter NPE. ```java public String result(Shopper shopper) the usual writing method, as follows ```java public String result(Shopper shopper) { if (shopper != null) { Trolley trolley = shopper.getTrolley(); if (trolley != null) { Chestnut chestnut = trolley.getChestnut(); if (chestnut != null) { return chestnut.getName(); } } } return “Failed to get”; } ``` Multi-layer nesting will be dazzling for deeper object cascade relations, especially with the layer of brackets. In addition, the reason for the error is also blurred by the lack of corresponding information (for example, when trolley is null, only “Failed to get” is returned finally. Of course, you can also add returns to each layer, and the corresponding code will become very verbose). So then, we can also rewrite it with guard clauses that returns when null. ```java public String result(Shopper shopper) { if (shopper == null) { return ‘Shopper does not exist‘; } Trolley trolley = shopper.getTrolley(); if (trolley == null) { return ‘Trolley does not exist‘; } Chestnut chestnut = trolley.getChestnut(); if (chestnut == null) { return ‘Chestnuts do not exist‘; } return chestnut.getName(); } ``` There is no problem with the code that does three explicit null evaluations to get a name. But good engineers always prefer the code that is more elegant and concise. Optional offers a few ways to do just that. ```java public String result(Shopper shopper){ return Optional.ofNullable(shopper) .map(Shopper::getTrolley) .map(Trolley::getChestnut) .map(Chestnut::getName) .orElse(‘Failed to get‘); } ``` ## 2. Common Methods #### 1) Get Optional object There are two constructors in the Optional class: Parameterized and non-parameterized constructors. For parameterized constructor, the Optional object will be constructed by assigning value to the passed parameter;for non-parameterized constructor, the Optional object will be constructed by initializing value with null. ```java private Optional() {} private Optional(T value) {} ``` But both are private methods, the Optional objects are actually built in static factory mode, with the following three main functions ```java public static <T> Optional<T> of(T value) {} public static <T> Optional<T> ofNullable(T value) {} public static <T> Optional<T> empty() {} ``` Create an Optional object that must not be null, as an NPE will be thrown if the parameter passed is null ```java Chestnut chestnut = new Chestnut(); Optional<Chestnut> opChest = Optional.of(chestnut); ``` Create a null Optional object ```java Optional<Chestnut> opChest = Optional.empty(); ``` Create a nullable Optional object ```java Chestnut chestnut = null; Optional<Chestnut> opChest = Optional.ofNullable(chestnut); ``` #### 2) Normal use The methods used normally can be roughly divided into three types, judgment, operation and value ```java //Judgment public boolean isPresent() {} //Operation public void ifPresent(Consumer<? super T> consumer) {} //Value public T get() {} public T orElse(T other) {} public T orElseGet(Supplier<? extends T> other) {} public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {} ``` The isPresent() method acts as a safety valve, controlling whether the value in the container is null or has a value. Its usage is similar to original null != obj. It returns true when obj has a value, false when obj is null (that is, it is true if value exists). However, it is more common to use other methods of Optional to determine the null or not null logic. The following code will print the sad fact that there are no chestnuts. ```java Optional<Chestnut> opChest = null; if(opChest.isPresent){ System.out.println(‘There are no chestnuts in the container‘); } ``` The ifPresent() method is an operation class method. Its parameter is a function whose target type is Consumer. When the value is not null, the accept() method in the consumer will be automatically executed (implemented when it is passed in), and if it is null, no action will be performed. For example, in the following code, we pass in a lamda expression that outputs value, printing out “Qianxi Chestnut”. ```java Optional<Chestnut> opChest = Optional.ofNullable(new Chestnut(‘Qianxi Chestnut‘)); opChest.ifPresent(c -> System.out.println(c.getName())); ``` The source code of the get() method is as follows. As you can see, get returns the value directly from the container. However, for such simple method, if no null evaluation is performed before use, and the value is null, an exception will be thrown. ```java public T get() { if (value == null) { throw new NoSuchElementException(‘No value present‘); } return value; } ``` The three orElse methods are similar to get in that they are all value operations. The orElse method differs from get in that it does not require additional null evaluation statement, which is more pleasant in writing logic. The three orelses have in common that they all return value when value is not null. When null, they will have different operations: the orElse() method will return the passed other instance (or a function of Supplier type); the orElseGet() method will automatically execute the get() method of the Supplier instance; while the orElseThrow() method will throw a custom exception. More specific differences will be described later in the method comparison. For example, the following code shows how to spit out “Xinyang Chestnut”, “Zhen’an Chestnut” and throw a warning of “Oiled Chestnut” when there are no chestnuts. ```java Optional<Chestnut> opChest = Optional.empty(); System.out.println(opChest.orElse(new Chestnut(‘Xinyang Chestnut’))); System.out.println(opChest.orElseGet(() - > new Chestnut(‘Zhen’an Chestnut‘))); try { opChest.orElseThrow(() -> new RuntimeException(‘Oiled Chestnut‘)); }catch (RuntimeException e){ System.out.println(e.getMessage()); } ``` #### 3) Advanced use ```java public Optional<T> filter(Predicate<? super T> predicate) {} public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {} public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {} ``` The filter() method accepts a function whose predicate is a Predicate type as a parameter. If the value is not null, the test() method of the predicate (implemented when passed in) will be automatically executed to determine whether the criteria are satisfied. If satisfied, it will return its own Optional. If not, it will return a null Optional; if the value is null, it will return its own Optional (which is similar to a null Optional). For example, in the following code, the filter criteria “Shaodian Chestnut” in the second sentence does not match the chestnut name in opChest, so it does not pass the filtering. And the filter criteria of the third sentence is the same as opChest, so the final print is “Kuancheng Chestnut”. ```java Optional<Chestnut> opChest = Optional.ofNullable(new Chestnut(‘Kuancheng Chestnut‘)); opChest.filter(c -> ‘Shaodian Chestnut‘.equals(c.getName())).ifPresent(System.out::println); opChest.filter(c -> ‘Kuancheng Chestnut‘.equals(c.getName())).ifPresent(System.out::println); ``` Both the map() and flatmap() methods pass in a Function-type function. map is translated as 'map' here. For the map method, when the value is not null, some processing will be performed, and the value returned is an Optional value processed by mapper’s Apply () method. The results of the two methods are consistent, and there will be differences in processing. In the following code, after obtaining the chestnut name from opChest, a new chestnut named “Xingtai Chestnut” is created and printed out. The two have consistent output, but differ in the processing, which will be mentioned in method comparison below. ```java Optional<Chestnut> opChest = Optional.ofNullable(new Chestnut(‘Xingtai Chestnut‘)); System.out.println(opChest.map(c - > new Chestnut(c.getName()))); System.out.println(opChest.flatMap(c -> Optional.ofNullable(new Chestnut(c.getName())))); ``` #### 4) New features in 1.9 ```java public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {} public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {} public Stream<T> stream() {} ``` Three methods have been added in JDK1.9: the ifPresentOrElse(), or(), and stream(). In 1.8, ifPresent() only provides if(obj! = null) method, does not provide if(obj! = null)else{} operation, so an ifPresentElse() method was added in 1.9 to provide this support. This method accepts functions of types Consumer and Runnable. When the value is not null, the accept() method of the action will be called, which is the same as ifPresent(). When value is null, the run() method of the emptyAction will be called, which performs the else semantic logic. As shown in the following code, the prompt “No Chestnut” will be printed out. ```java Optional<Chestnut> opChest = Optional.empty(); opChest.ifPresentElse(c -> System.out.println(c.getName()),c -> System.out.println(‘No Chestnut’)); ``` The or() method is an improvement on the orElse() and orElseGet() methods. They are used in the same way, but the latter two methods do not return a wrapper value after execution. The or() method can be used if you need to perform some logic and return Optional. This method passes to an instance of the Supplier API and returns its Optional when value is not null. When null, the supplier’s get() method will be automatically executed, wrapped and returned as Optional. The following statements are wrapped in the source code: ```java Optional<T> r = (Optional<T>) supplier.get(); return Objects.requireNonNull(r); ``` The stream() method, which will not be mentioned here, is a method for streaming programming that functions as an adapter to convert Optional to stream: If the value is null, it will return a null stream or a stream containing an Optional. Its source code is as follows: ```java if (!isPresent()) { return Stream.empty(); } else { return Stream.of(value); } ``` ## 3. Method Comparison and Summary There are many methods of Optional encapsulation. To choose a suitable method, one must understand the applicable scenarios and similarities and differences in advance. #### 1) Comparison of creation methods Since the constructor is a private method, it can only create objects through static factories. Whereas the of(), ofNullable(), and empty() methods are three static methods. Let’s look at the source code first ```java //Factory method public static <T> Optional<T> of(T value) { return new Optional<>(value); } public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); } public static<T> Optional<T> empty() { @SuppressWarnings(‘unchecked‘) Optional<T> t = (Optional<T>) EMPTY; return t; } //Constructor private Optional() { this.value = null; } private Optional(T value) { this.value = Objects.requireNonNull(value); } //Static constant private static final Optional<?> EMPTY = new Optional<>(); ``` The of() method creates an Optional object by calling the parameterized constructor. There is no problem with normal parameters with values, but when the parameters are null, an exception will be thrown during the non-null check of the Objects.requireNonNull() before the value is set. The code is as follows: ```java public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; } ``` The requireNonNull() method is a method of the Objects class in the java.util package that checks whether a parameter passed in is null. If yes, an NPE will be thrown. It has many other uses in the Optional class. Therefore, the of() method can be used only when it is determined that the parameter passed in for constructing Optional is not null. The ofNullable() method, as opposed to the ofNullable() method, allows to construct Optional when the value is null. The empty () method is called when the parameter is null, and returns a compile-time constant Empty. The value of EMPTY is the object created by the constructor without parameters, and the final result is an Optional object with a null value. #### 2) Comparison of methods used As mentioned in 2.2), the normally used value methods include orElse(), orElseGet() and orElseThrow(). These three methods all return value when they are not null, but differ in processing when they are null. Let’s look at the source code first: ```java public T orElse(T other) { return value != null ? value : other; } public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); } public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } } ``` The most obvious difference between the orElse() and orElseGet() methods lies in the difference in parameters. As shown in the following code: ```java // test statement Optional<Chestnut> opChest = Optional.ofNullable(new Chestnut(‘Tongbai Chestnut‘)); //Optional<Chestnut> opChest = Optional.empty(); opChest.orElse(print(‘orELse‘)); opChest.orElseGet(()->print(‘orElseGet‘)); // Call the method private static Chestnut print(String method){ System.out.println(‘Yanshan Chestnut is the best----‘+method); return new Chestnut(‘Yanshan Chestnut‘); } ``` For the first time, an Optional of “Tongbai Chestnut” was obtained with new, and orElse() and orElseGet() were called respectively. As a result, two lines of “Yanshan Chestnut is the best” were output. This is because that both methods will execute the method in the parameter if the value is not null; For the second time, an Optional null chestnut was obtained with empty() method, and then the orElse() and orElseGet() methods were called. As a result, a line of “Yanshan Chestnut is the best” was output. ```java The first output: Yanshan Chestnut is the best----orELse Yanshan Chestnut is the best----orElseGet The second output: Yanshan Chestnut is the best----orELse ``` This is because that the parameter of orElseGet() is a function of the Supplier target type. To put it simply, the Supplier API is similar to lazy loading of Spring in that it does not consume memory after the declaration and only calls the constructor to create the object after the get() method is executed, whereas orElse() features rapid loading and can run actually even if it is not called. This feature doesn’t make a big difference for simple methods, but when methods are performing intensive calls, such as remote calls, calculating classes, or querying class methods, the performance may be compromised. The parameters of both orElseThrow() and orElseGet() methods are Supplier parameters, which are function types. This means that both methods features lazy loading, but orElseThrow() is more appropriate for scenarios where the exception control flow must be used, as you can control the exception type, enabling the richer semantics than NPE. #### 3) Comparison of other methods **a. map and filterMap** Let’s look at the source code first: ```java public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } } public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } } ``` The map() and filterMap() are similar in that they both accept a Function-type function and return Optional data. But we can also see from the source code: First, map() wraps the return value with the ofNullable() function. This function, as described in 2.1, is an Optional factory function that wraps data as Optional. Whereas filterMap () returns a non-null check and is already an Optional object when mapper.apply is applied. Second, as can be seen from the signature, the output of map() Function is ”? extends U‘, which means that when mapper.apply() is done, it simply spits out a U or a subclass of U; if the Functional output value of filterMap() is 'Optional<U>', mapper.apply() must return an Optional data when it is done. **b. ifPresent and ifPresentOrElse** The ifPresentOrElse() method is an improvement on ifPresent(). Let’s look at the source code first: ```java public void ifPresent(Consumer<? super T> action) { if (value != null) { action.accept(value); } } public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) { if (value != null) { action.accept(value); } else { emptyAction.run(); } } ``` As can be seen from the source code, the ifPresentOrElse() parameter adds a Runnable-type function emptyAction. When value != null, the action.accept() method is activated. However, the ifPresentOrElse() method will also call the emptyAction.run() method when value == null. So in general, the introduction of ifPresentOrElse() method into jdk1.9 serves as a supplement to ifPreset in the realm of if-else. **c. or and orElse** The or() method, as an another improvement, is also designed to address the weaknesses of the orElse series methods. Let’s look at the source code first: ```java public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) { Objects.requireNonNull(supplier); if (isPresent()) { return this; } else { @SuppressWarnings(‘unchecked‘) Optional<T> r = (Optional<T>) supplier.get(); return Objects.requireNonNull(r); } } public T orElse(T other) { return value != null ? value : other; } public T orElseGet(Supplier<? extends T> supplier) { return value != null ? value : supplier.get(); } ``` The or() method is more like orElseGet() in signature form, in that its parameters are functions of Supplier type. In contrast, the or() method specifies that the Supplier must return Optional type and the value type must be T or a subclass of T. The orElse method, which is more of a consumption method, “take out” the value from an Optional instance to the next operation, whereas the or() method is like the constructor mode, in which after a certain operation on the value, the data of the Optional type is re-spit out, so it can be used in tandem, with the latter or processing the Optional spit out by the former or. #### 4) Comparison of “dangerous” methods The “dangerous” here means that an exception will be thrown. After all, the Optional class is introduced to remove the determination of the NPE. If another NPE or other exception is thrown at this point, it will introduce a lot of trouble to the program if it is not handled properly. So here’s a summary of the methods in which Optional can throw an exception. First, the most intuitive method that may throw an exception is the of() method, as it creates an instance by calling a parameterized constructor, which checks whether the value is not null and will throw an NPE if it is null. Second, the get() method is also “dangerous” because NoSuchElementException in get will be triggered when the get value is used without null evaluation. Third, the orElseThrow() method will also throw an exception, but this exception is artificially specified to enrich the semantics of the exception case, and this artificially set exception is controllable. Finally, the parameter nonnull check (objects.requirenonNULL ()) is set in some methods, which will throw an NPE. In addition to the parameterized constructor mentioned above, there are four methods: filter, map, flatMap and or, which will trigger the NPE at any time if the passed API instance is Null. ## 4. Misused Forms and Best Practice ### 1) Misused form **a. Initialized to null** The first form of misuse is initializing the variables of Optional type. Optional variables are not null by default, so they can be easily “clicked” when the method is executed. If they occur during initialization: ```java Optional<Chestnut> chest = null; ``` And if chest is not assigned in time, NPE is still likely to occur. The correct initialization should be: ```java Optional<Chestnut> chest = Optional.empty(); ``` **b. Simple null evaluation** The second common form of misuse is using isPresent() for simple null evaluation. The original code is as follows: ```java public String getName(Chestnut chestnut){ if(chestnut == null){ return ‘Chestnuts do not exist‘; }else return chestnut.name(); } ``` In the code, the null case is handled by checking chestnut == null. The code for simple null evaluation using isPresent() is as follows: ```java public String getName(Chestnut chestnut){ Optional<Chestnut> opChest = Optional.ofNullable(chestnut); if(!opChest.isPresent()){ return ‘Chestnuts do not exist‘; }else return opChest.getname(); } ``` This doesn’t make much difference, so when using Optional, you should first avoid using Optional.isPresent() to check whether the instance exists, as this method is no different from null!= obj, and it doesn’t make any sense. **c. Simple get** The third common form of misuse is using the Optional.get() method to get the value of Optional value. The get() method will throw an exception when value==null, so it should be done after non-null checking. After testing, get the value from get, or you should be absolutely sure that value is not null, otherwise NoSuchElementException will occur. In contrast, if you’re not sure, it is advisable to use orElse(), orElseGet(), and orElseThrow() to get your results. **d. Serving as an attribute field and method parameter** The fourth form of misuse is likely to happen for Optional beginners, that is, when specifying an attribute in a class or a method whose parameter is Optional, the idea will give the following prompts: Reports any uses of java.util.Optional<T>, java.util.OptionalDouble, java.util.OptionalInt, java.util.OptionalLong or com.google.common.base.Optional as the type for a field or parameter. Optional was designed to provide a limited mechanism for library method return types where there needed to be a clear way to represent ‘no result‘. Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not. The general idea is that Optional is not recommended. First, it is not recommended to use Optional as a field or parameter. It is designed to provide a limited mechanism for library method return types that clearly represent “no result” semantics. Second, Optional does not implement Serilazable and cannot be serialized. This form of misuse is more obvious, and it is easier to repeat and avoid. Nevertheless, the author also wants to further explore the reasons for these two suggestions, so after consulting some materials, I learned that the general reasons are as follows: The first reason, why is it not suitable to serve as attribute field and method parameter? To put it bluntly, it is troublesome. To introduce Optional, you need to add several pieces of boilerplate code, such as null evaluation. Using Optional in the wrong place cannot bring us convenience, but constrain the logic of writing code. Write the following domain model code ```java public class Chestnut { private String firstName; private Optional<String> midName = Optional.empty(); private String lastName; public void setMidName(Optional<String> midName) { this.midName = midName; } public String getFullName() { String fullName = firstName; if(midName != null) { if(midName.isPresent() { fullName = fullName.concat(‘.‘ + midName.get()); } return fullName.concat(‘.‘ + lastName); } } } ``` It can be seen that if there is no check for parameters in the setter method, you need to add null evaluation to the attribute midName in the getFullName() method, as it is entirely possible to make the attribute null through the setter method. If the null evaluation is moved into the setter method, it will not reduce null evaluation, nor just add a piece of boilerplate code for no reason. In addition, when the method is passed in, it also needs to wrap the original value layer before operation, which makes the code cumbersome, for example: ```java chest.setMidName(Optional.empty()); chest.setMidName(Optional.of(‘A chestnut’)); ``` When the attribute is not Optional, assigning to the attribute requires a “consumption” operation, such as orElse(), which takes out the value and assigns it to the attribute, rather than passing in a String type value as a field and parameter directly. The latter is more concise and better. The second reason, why serialization is not implemented? See the panel discussion on Java Lamda for more information.  The JDK is special when it comes to serialization, requiring both forward and backward compatibility, such that objects serialized in JDK7 should be able to be deserialized in JDK8 and vice versa. Besides, serialization depends on the identity of the object to remain unique. Currently Optional is of reference type, but it is marked as a value-based class and is planned to be implemented in later versions of JDK, as shown in figure above. If it is designed to be serializable, two paradoxes will occur: 1) If Optional is serializable, the Optional class cannot be implemented as a value-based class, but must be a reference type. 2) Otherwise, the value-based class will be added to identity-sensitive operations (including reference equality such as: ==, identity hashcode or synchronization, etc.), but this conflicts with the currently released JDK versions. In summary, considering future JDK planning and implementation conflicts, making Optional non-serializable from the outset seems the most appropriate solution. Value-Based Classes. Here’s the explanation from Java doc: Some classes, such as java.util.Optional and java.time.LocalDateTime, are value-based. Instances of a value-based class: 1、are final and immutable (though may contain references to mutable objects); 2、have implementations of equals, hashCode, and toString which are computed solely from the instance's state and not from its identity or the state of any other object or variable; 3、make no use of identity-sensitive operations such as reference equality (==) between instances, identity hash code of instances, or synchronization on an instances's intrinsic lock; 4、are considered equal solely based on equals(), not based on reference equality (==); 5、do not have accessible constructors, but are instead instantiated through factory methods which make no committment as to the identity of returned instances; 6、are freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to equals() in any computation or method invocation should produce no visible change in behavior. A program may produce unpredictable results if it attempts to distinguish two references to equal values of a value-based class, whether directly via reference equality or indirectly via an appeal to synchronization, identity hashing, serialization, or any other identity-sensitive mechanism. Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided. ### 2)Best practice In practice, the above methods are often used in combination, and many of them are often combined with Lambda expressions to get the desired result. Here are two common uses: value type conversions and set element filtering. **a. Example 1** ```java Chestnut chestnut = new Chestnut(‘Hazelnut Chestnut‘); if(chestnut != null){ String chestName = chestnut.getName(); if(chestName != null){ return chestName.concat(‘Yummy!‘); } }else{ return null; } ``` It can be simplified as: ```java Chestnut chestnut = new Chestnut(’Hazelnut Chestnut‘); return Optional.ofNullable(chestnut) .map(Chestnut::getName) .map(name->name.concat(‘Yummy!‘)) .orElse(null); ``` **b. Example 2** ```java public static void main(String[] args) { // Create a chestnut set List<Chestnut> chestList = new ArrayList<>(); // Create a few chestnuts Chestnut chest1 = new Chestnut(‘abc‘); Chestnut chest2 = new Chestnut(‘efg‘); Chestnut chest3 = null; // Add the chestnuts to the set chestList.add(chest1); chestList.add(chest2); chestList.add(chest3); // Create a set to store chestnut names List<String> nameList = new ArrayList(); // Loop through the chestnut list to get chestnut information, the value is not null and the chestnut name begins with ‘a’ // If the criteria are not met, set to default value, and finally add the qualified chestnut name to the chestnut name set for (Chestnut chest : chestList) { nameList.add(Optional.ofNullable(chest) .map(Chestnut::getName) .filter(value -> value.startsWith(‘a‘)) .orElse(‘not filled‘)); } // Output the value in the chestnut name set System.out.println(‘Output the set filtered by Optional:’); nameList.stream().forEach(System.out::println); } ``` ##5. Summary In the paper, the current problems encountered in NPE processing were introduced first, starting from the problems to be solved. Then, the methods in the Optional class were discussed with corresponding examples. After that, several commonly used methods were compared in terms of the source code. Finally, several common misuse forms and best practice were listed. The Optional class: It has the advantage of explicitly expressing the semantics that the value may be null and hiding the uncertainty of the possible existence of a null pointer, but it also has the disadvantage of having a limit range of application (recommended for return values and NPE logic processing) and requiring more consideration when used. But in general, the Optional class is a new feature that comes with functional programming in Java8. It provides more options for the implementation of processing logic, and we look forward to more practices and best practices in the future, bringing more opportunities for Optional. ## 6. References [1] https://mp.weixin.qq.com/s/q_WmD3oMvgPhakiPLAq-CQ Source: WeChat [2] https://www.runoob.com/java/java8-optional-class.html Source: www.runoob.com [3] https://blog.csdn.net/qq_40741855/article/details/103251436 Source: CSDN [4] https://yanbin.blog/java8-optional-several-common-incorrect-usages/#more-8824 Source: blog [5] https://www.javaspecialists.eu/archive/Issue238-java.util.Optional---Short-Tutorial-by-Example.html Source: java specialists [6] Java Core Technology Volume II - Stream Libraries for Java8 - Optional type [7] https://www.zhihu.com/question/444199629/answer/1729637041 Source: Zhihu Your comments are welcome ------------ ###### Programmer Language Specifications Tech-JDL ###### Author: Li Ziqian, B2B R&D Team, Supply Chain Technology Department ------------
Self-justification Tech
number of articles
196
reading volume
771724
Self-justification Tech
number of articles
196
reading volume
771724
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号