Any Java developer will encounter a NullPointerException, and the usual way to avoid nPES is to NullPointerException before accessing an object, using branch statements to determine if (xx! = null). However, too many branching statements, especially when combined with business logic, can lead to code readability and maintainability, so they need to be reduced. Fortunately, Java8 provides an Optional tool that eliminates most short calls and some common judgments.

Optional

Option.ofnullable () creates an Optional that accepts NULL. Option.ofnullable () creates an Optional that accepts null, and option.of () immediately throws an NPE. This article is not an introduction to the use of Optional methods, but rather an example of Optional replacing if in a specific situation.

Alternate short call branch

Most short branches can be replaced by Optional.

Object sth = ... ;// Throws a business exception for null
if(sth == null) {throw new Exception...
}
// Or provide default values
if(sth == null){
	sth = ...
}
// Get it from another source
if(sth == null){
	sth = getFrom...()
}
// When not free, do something else
if(sth ! =null){
	...
}
// if not null, null (for Java 9 and above)
if(sth ! =null){
	...
}else{... }Copy the code

All can be refactored using Optional’s corresponding methods:

// Throws a business exception for nullOptional.ofNullable(...) .orElseThrow(() ->newException...) ;// Or provide default valuesOptional.ofNullable(...) .orElse(xxx);// Get it from another sourceOptional.ofNullable(...) .orElseGet(() -> getFrom... ());// When not free, do something elseOptional.ofNullable(...) .ifPresent(x -> ...) ;// if not null, null (for Java 9 and above)Optional.ofNullable(...) .ifPresentOrElse(x -> ... , () - >...). ;Copy the code

Secure chain call

Object result = sth.getA().getB().getC().getD().getE();
Copy the code

Chain calls are cool to write, but when used, if one of them is null, it can be frustrating 😫, and since null fields can be indeterminate, you may need to nest branches or use an extra-long conditional branch to null.

if(sth.getA() ! =null){
    Object sth2 = sth.getA();
	if(sth2.getB() ! =null) {... }}/ / or
if(sth.getA() ! =null&& sth.getA().getB() ! =null...). {return. }// The rest are not examples
Copy the code

This can be avoided using the Optional map method:

Optional.ofNullable(sth).map(xxx::getA).map(yyy::getB)...
Copy the code

Map automatically wraps the return value as Optional, as opposed to the flatMap method, which only accepts method references that return Optional. FlatMap was introduced to prevent multiple wrappers, such as Optional
.

public class X{
    public Optional<Y> getName(a){
        return. } } X sth = ... Optional.ofNullable(sth).flatMap(X::getName)...Copy the code

Substitute partial conditional judgment branch

Optional can also replace some simple Bean criteria by using the filter method.

XXX sth = ...
if(sth.getB() > 10) {return sth.getB().getC();
}
if(sth.getA() > 5) {throw new. }// Use Optional instead
// If getC() does not return null, NoSuchElementException will be raised.
return Optional.of(sth).map(XXX::getB).filter(x -> x > 10).map(XXX:getB).get();
// Note that this is orElse, so the filter should be reversed!
Optional.of(sth).map(XXX::getA).filter(x -> x <= 5).orElseThrow(() -> new...). ;Copy the code

Good practice using if

Even in cases where you must use if, there are tricks to optimize the structure of your code. One rule is to minimize code nesting, write short branch paths under if, and reverse if if necessary. One idea is to use if as a filter to judge a special condition, judge the “abnormal state” in time and return, taking login as an example:

if(checkPassword(password,userInput)){
    // A number of operations may take place after a successful login password verification. }else{
    // If there is a lot of code above, do not review what else
	throw new Exception("Password error")}// It would be much better to write it like this
if(! checkPassword(password,userInput)){// The short branch path is written under if
    // Override the if condition to filter the authentication password error as a special case
	throw new Exception("Password error")}// A bunch of operations are not in the branch and are treated as normal.Copy the code