- The premise
During code development, we often return null; Or a null scenario like this. public String test(String str){ if (Objects.equals(str.toUpperCase(),"TEST")){ return str; } return null; } A null pointer exception will be thrown if the input parameter is null. But in the real world this is a fault-tolerant situation. This will not cause a program error. So you can use Optional to solve the problem. public String test(String str){ str = Optional.ofNullable(str).orElseGet("GG"); If (objects.equals (STR. TouPperCase (),"TEST")){return STR; } return null; }
2. Optional method
Create an Optional instance
To reiterate, an object of this type may contain a value or it may be empty. You can create an empty Optional using the method with the same name. Optional<User> emptyOpt = Optional.empty(); emptyOpt.get(); Not surprisingly, trying to access the value of the EMPTYOPT variable results in a NoSuchElementException. You can use the ofNullable() and ofNullable() methods to create Optional values. The difference between the two methods is that if you pass NULL as an argument, the of() method throws NullPointerException: Optional<User> opt = option.of (User); Therefore, you should explicitly use of() when the object is not NULL. OfNullable () if the object is either NULL or non-NULL: Optional<User> opt = option. ofNullable(User); ofNullable(User) is Optional.
2, Access the value of the Optional object
One way to retrieve an actual value object from an Optional instance is to use the get() method: String name = "John"; Optional<String> opt = Optional.ofNullable(name); assertEquals("John", opt.get()); However, as you can see, this method will throw an exception if the value is null. To avoid exceptions, you can choose to verify the value first: User User = new User("[email protected]", "1234"); Optional<User> opt = Optional.ofNullable(user); assertTrue(opt.isPresent()); assertEquals(user.getEmail(), opt.get().getEmail()); Another option to check for a value is the ifPresent() method. In addition to performing a check, this method takes a Consumer argument and executes the passed Lambda expression on the object if it is not empty: opt.ifPresent( u -> assertEquals(user.getEmail(), u.getEmail())); In this example, the assertion is performed only if the user user is not null. Next, let's look at ways to provide null values.
3, return the default value
The Optional class provides an API to return the value of an object, or the default value if the object is empty: orElse(), if any, or the value of the argument passed to it: User user2 = new User("[email protected]", "1234"); User result = Optional.ofNullable(user).orElse(user2); assertEquals(user2.getEmail(), result.getEmail()); Here the User object is empty, so user2 is returned as the default value. If the object's initial value is not null, then the default value is ignored: User User = new User("[email protected]","1234"); User user2 = new User("[email protected]", "1234"); User result = Optional.ofNullable(user).orElse(user2); assertEquals("[email protected]", result.getEmail()); The second API of this type is orelSeGet () -- which behaves slightly differently. This method returns a value if it has one. If there is no value, it executes the Supplier(Supplier) functional interface passed in as an argument and returns the result of its execution: User result = Optional.ofNullable(user).orElseGet( () -> user2);
4, The difference between orElse() and orElseGet()
At first glance, the two approaches seem to work in the same way. However, this is not the case. Let's create some examples to highlight the differences and similarities in their behavior. Debug ("Using orElse"); debug("Using orElse"); User result = Optional.ofNullable(user).orElse(createNewUser()); logger.debug("Using orElseGet"); User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser()); private User createNewUser() { logger.debug("Creating New User"); return new User("[email protected]", "1234"); } In the code above, both methods call the createNewUser() method, which logs a message and returns the User object. Using Orelse Creating New User Using OrelseGet Creating New User This shows that when the object is empty and the default object is returned, there is no difference in behavior. Let's look at a similar example, but here Optional is not null: @test public void givenpresentValue_whwhencompencompess_thenok () {User User = new User("[email protected]", "1234"); Logger. The info (" Using orElse "); The User result = Optional. OfNullable (User). OrElse (createNewUser ()); Logger. The info (" Using orElseGet "); User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser()); Using Orelse Creating New User Using OrelseGet In this example, two Optional objects contain non-null values. Both methods return the corresponding non-null values. However, the orElse() method still creates the User object. In contrast, the orelSeGet () method does not create a User object. This difference can have a significant impact on performance when performing more intensive invocations, such as invoking Web services or data queries.
5, return an exception
In addition to the orElse() and orelseGet () methods, Optional also defines the orelseThrow () API, which throws an exception when an object is empty rather than returning an alternative value: User result = Optional.ofNullable(user).orElseThrow( () -> new IllegalArgumentException()); Here, if the User value is NULL, an IllegalArgumentException is thrown. This approach allows us to have richer semantics to decide what exceptions to throw rather than always throwing NullPointerExceptions. Now that we have a good understanding of how to use Optional, let's look at other ways to convert and filter Optional values.
6. Convert values
There are many ways to convert the value in Optional. We start with the map() and flatMap() methods. Let's start with an example using the map() API: User User = new User("[email protected]", "1234"); String email = Optional.ofNullable(user) .map(u -> u.getEmail()).orElse("[email protected]"); assertEquals(email, user.getEmail()); Map () applies (calls) the function as an argument to the value and wraps the returned value in Optional. This makes it possible to make a chain-trial call to the return value -- the next step here is orElse(). In contrast, flatMap() also takes a function as an argument, calls the function on the value, and returns the result directly. Public class User {private String position; public class User {private String position; public Optional<String> getPosition() { return Optional.ofNullable(position); } / /... } Since the getter method returns the String value as Optional, you can call flatMap() on the User's Optional object with it as an argument. The value returned is the unwrapped String value: User User = new User("[email protected]", "1234"); user.setPosition("Developer"); String position = Optional.ofNullable(user) .flatMap(u -> u.getPosition()).orElse("default"); assertEquals(position, user.getPosition().get());
7, Filter value
In addition to converting values, the Optional class also provides a way to "filter" values by condition. Filter () takes a Predicate argument and returns a value that tests true. If the test result is false, an empty Optional is returned. Consider an example of accepting or rejecting User based on basic E-mail validation: User User = new User("[email protected]", "1234"); Optional<User> result = Optional.ofNullable(user) .filter(u -> u.getEmail() ! = null && u.getEmail().contains("@")); assertTrue(result.isPresent()); If the filter tests, the Result object will contain non-null values.
8, Chained methods of the Optional class
To use Optional more fully, you can link and combine most of its methods because they all return the same, similar object. We overwrote the original example using Optional. First, refactor the class so that its getter method returns an Optional reference: public class User {private Address Address; public Optional<Address> getAddress() { return Optional.ofNullable(address); } / /... } public class Address { private Country country; public Optional<Country> getCountry() { return Optional.ofNullable(country); } / /... } can now remove the null check and replace it with Optional: @Test public void whenChaining_thenOk() { User user = new User("[email protected]", "1234"); String result = Optional.ofNullable(user) .flatMap(u -> u.getAddress()) .flatMap(a -> a.getCountry()) .map(c -> c.getIsocode()) .orElse("default"); assertEquals(result, "default"); } The above code can be further reduced by method references: String result = Optional.ofNullable(user) .flatMap(User::getAddress) .flatMap(Address::getCountry) .map(Country::getIsocode) .orElse("default"); As a result, the code now looks much cleaner than the verbose code that used conditional branching.
How should Optional be used?
There are a few things you need to consider when using Optional to decide when and how to use it. The important thing is that Optional is not Serializable. Therefore, it should not be used as a field of a class. If the object you want to serialize contains Optional values, the Jackson library supports Optional as a normal object. That is, Jackson will treat an empty object as null, while an object with a value will treat its value as the value of the corresponding field. This feature is in the Jackson-Modules-Java8 project. It is also not very useful in another context, when its type is used as a parameter to a method or a build method. This would complicate the code unnecessarily: User User = new User("[email protected]", "1234", optional.empty ()); It is much easier to use overloaded methods to handle unwanted parameters. Optional is mainly used as the return type. After getting an instance of the type, if it has a value, you can get that value, otherwise you can do some alternate behavior. One useful use case for the Optional class is to combine it with a stream or other method that returns Optional to build a smooth API. List<User> Users = new ArrayList<>(); List<User> Users = new ArrayList<>(); User user = users.stream().findFirst().orElse(new User("default", "1234")); assertEquals(user.getEmail(), "default");
conclusion
Optional is a useful addition to the Java language -- it aims to reduce NullPointerExceptions in your code, although it does not eliminate them completely. It is also a well-designed feature that naturally fits into Java 8's functional support. Overall, this simple and powerful class helps create simpler, more readable programs with fewer errors than their counterparts.