Say goodbye to null pointers and make the code more elegant. Optional uses graphic examples to interpret the source code

I. Introduction

The most common exception in our development is NullPointerExceptionthat it is impossible to prevent. I believe everyone must have been tricked!

This basically appears in the acquisition of database information, the three-party interface, the acquired object is empty, and then go to get to appear!

The solution is of course simple, you only need to judge, it is not empty to go to the follow-up operation, return empty!

All the special processing solutions appeared in JDK8, which came out very early, but I am ashamed that I have not used it!

I have been reading the "Java Development Manual" recently, and I have been thinking about improving my code level, and the article points out how to use it to Optionalsolve it NullPointerException!

2. Java Development Manual Specification

The editor used the 2022 version of the Huangshan version. On page 29 it was written:

【推荐】Preventing NPE is the basic cultivation of programmers. Pay attention to the scenarios where NPE occurs:

  • The return type is a basic data type. When return wraps an object of a data type, automatic unboxing may generate NPE

counterexample: public int method() { return Integer object; }, if it is null, it will automatically unbox and throw NPE.

  • The query result of the database may be null.
  • Even if the elements in the collection are NotEmpty, the retrieved data elements may be null.
  • When a remote call returns an object, a null pointer judgment is required to prevent NPE.
  • For the data obtained in the Session, it is recommended to perform NPE checks to avoid null pointers.
  • Cascading calls to obj.getA().getB().getC(); a series of calls are prone to NPE.

positive example: Use JDK8's Optionalclass to prevent NPE problems.

This manual is still good, and it is recommended to read it repeatedly. Although you can't get into a big factory, you must consciously restrain your code style and try to rely on the big factory!

If you don't know where to find it now, you can download it:

"Java Development Manual"

Three, Optional common methods

The editor will take everyone from the methods in the api documentation, and take everyone to understand it slowly one by one!

1. empty()

Returns an empty Optional instance: Optional.empty

Optional<Object> empty = Optional.empty();
log.info("empty值:{}",empty);

insert image description here

2. of(T value)

Pass in a parameter and return an Optionalobject, if the parameter is empty, report NullPointerException!

Test testNew  = new Test();
Test test = null;
Optional<Test> optionalNew = Optional.of(testNew);
log.info(" optional对象:{}",optionalNew);
Optional<Test> optional = Optional.of(test);

insert image description here

Source code view:

We see that the parameter is empty and it will be reported NullPointerException. Let's go to the inside of the method to see:

public static <T> Optional<T> of(T value) {
    
    
    return new Optional<>(value);
}
private Optional(T value) {
    
    
    this.value = Objects.requireNonNull(value);
}
public static <T> T requireNonNull(T obj) {
    
    
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

We found that it is judged whether it is empty in the method Objectsin the class !requireNonNull

This will still appear NullPointerException, so we generally use the following method!

3. ofNullable(T value)

The parameter is passed in an object, and an Optional object is returned. If it is empty, an empty Optional object will be returned, which is equal to Optional.empty

Test testNew  = new Test();
Test test = null;
Optional<Test> optionalNew = Optional.of(testNew);
log.info(" optional对象:{}",optionalNew);

Optional<Test> optionalTest = Optional.ofNullable(test);
log.info(" optional对象中的ofNullable方法返回值:{}",optionalTest);
Optional<Test> optionalTestNew = Optional.ofNullable(testNew);
log.info(" optional对象中的ofNullable方法new返回值:{}",optionalTestNew);

insert image description here

Source code view:

We found that the non-empty judgment is made at the beginning of the method, and then the above of(T value)method is called

public static <T> Optional<T> ofNullable(T value) {
    
    
    return value == null ? empty() : of(value);
}

4. get()

Returns a value if present in this Optional, otherwise throws NoSuchElementException.

Test testNew  = new Test();
Test test = null;
Optional<Test> optionalNew = Optional.of(testNew);
log.info(" optional对象:{}",optionalNew);
// Optional<Test> optional = Optional.of(test);

Optional<Test> optionalTest = Optional.ofNullable(test);
log.info(" optional对象中的ofNullable方法返回值:{}",optionalTest);
Optional<Test> optionalTestNew = Optional.ofNullable(testNew);
log.info(" optional对象中的ofNullable方法new返回值:{}",optionalTestNew);

Test test2 = optionalTestNew.get();
log.info("原来有值的:经过Optional包装后get后得到原来的值:{}",test2);
Test test1 = optionalTest.get();
log.info("原来没有值的:经过Optional包装后get后得到原来的值:{}",test1);

insert image description here

Source code view:

The value will be judged at the beginning of the call, and an exception will be thrown if it is empty!

public T get() {
    
    
    if (value == null) {
    
    
        throw new NoSuchElementException("No value present");
    }
    return value;
}

5. isPresent()

Returns true if a value exists, false otherwise.

Here the code does not add the above, you can refer to the above to get an Optional object

boolean present = optionalTestNew.isPresent();
log.info("optionalTestNew调用是否为空:{}",present);
boolean present1 = optionalTest.isPresent();
log.info("optionalTest调用是否为空:{}",present1);

insert image description here

Source code view:

That's easier!

public boolean isPresent() {
    
    
   return value != null;
}

6. ifPresent(Consumer<? super T> consumer)

If a value exists, invokes the specified consumer with that value, otherwise does nothing.

The main thing is to enter a functional interface as a parameter, if there is a value, it will be executed, if it is empty, no operation will be performed!

Tips:

When you don't know lambda at the beginning, you can write it in the above way first,

You can see that Idea is grayed out, it can be optimized, and Alt+Enter
then we Enterwill become lambda again!

insert image description here

optionalTest.ifPresent(new Consumer<Test>() {
    
    
    @Override
    public void accept(Test test) {
    
    
        log.info("我是调用ifPresent执行后的打印=====");
    }
});
optionalTestNew.ifPresent(testInner -> log.info("我是调用ifPresent执行后的打印"));

insert image description here

Source code view:

It is better to judge that it is not empty before executing the functional interface!

public void ifPresent(Consumer<? super T> consumer) {
    
    
    if (value != null)
        consumer.accept(value);
}

7. filter(Predicate<? super T> predicate)

Returns an Optional describing the value if a value exists, and the value matches the rules, otherwise returns an empty Optional

It is a Predicate function interface, which can be passed in the lambda expression that implements the Predicate interface!
If the condition is not met it will return aOptional.empty

testNew.setName("萧炎");
testNew.setAge(33);
Optional<Test> optionalTest1 = optionalTestNew.filter(test1 -> test1.getAge() > 30);
log.info("过滤后的结果:{}",optionalTest1.get());

insert image description here

Source code view:

It is to judge whether the expression and value are empty, and then judge according to the rules

public Optional<T> filter(Predicate<? super T> predicate) {
    
    
   Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}

8. map(Function<? super T,? extends U> mapper)

If a value is present, applies the provided mapping function to the value, returning an Optional describing the result if the result is non-null. Otherwise, returns an empty Optional.

Also a functional interface!

Optional<String> stringOptional = optionalTestNew.map(Test::getName);
log.info("map后获得字段值:{}",stringOptional.get());

insert image description here

Source code view:

It is also a non-null judgment, and then execute the lambda to get the field and put it in the ofNullable method!

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));
    }
}

9. flatMap(Function<? super T,Optional> mapper)

Applies the provided Optional bearing mapping function to the value if present, returning that result, otherwise returns an empty Optional. This method is like map, but the result of the provided mapper is already optional, and flatMap will not do any wrapping at the end if called.

Optional<String> optional = optionalTestNew.flatMap(OptionalTest::getFlatMap);
log.info("flatMap后得到的字段:{}",optional.get());

private static Optional<String> getFlatMap(Test test){
    
    
    return Optional.ofNullable(test).map(Test::getName);
}

insert image description here
Source code view:

It is also a non-empty judgment, and then the difference from map is that the ofNullable method is not executed

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));
    }
}

10. orElse(T other)

Returns a value if available, otherwise returns the specified other value.

If you are an object, orElse()be the same object too!

String message = null;
String messageNew = "关注公众号:小王博客基地";

String nullString = Optional.ofNullable(message).orElse("这是一个空字符串!");
log.info("这是空字符串打印的:{}",nullString);
String string = Optional.ofNullable(messageNew).orElse("=====这是一个空字符串!");
log.info("这是字符串打印的:{}",string);

insert image description here

Source code view:

Simply return your own definition if it is empty, and return directly if it is not empty!

public T orElse(T other) {
    
    
    return value != null ? value : other;
}

11. orElseGet(Supplier<? extends T> other)

Returns the value if present, otherwise calls other and returns the result of that call.

Difference:
The orElse method takes the incoming parameter as the default value, and the orElseGet method can accept the implementation of the Supplier interface to generate the default value

If there is no complicated operation, Idea will also remind us not to use this, just use orElse!

String message = null;
String messageNew = "关注公众号:小王博客基地";
String orElseGet = Optional.ofNullable(message).orElseGet(() -> "这还是一个空的字符串");
log.info("orElseGet调用:这是空字符串打印的:{}",orElseGet);
String orElseGetString = Optional.ofNullable(messageNew).orElseGet(() -> "这还是一个空的字符串");
log.info("orElseGet调用:这是字符串打印的:{}",orElseGetString);

insert image description here

Source code view:

Same as orElse, but implemented as a lambda for the conditioner!

public T orElseGet(Supplier<? extends T> other) {
    
    
    return value != null ? value : other.get();
}

12. orElseThrow(Supplier<? extends X> exceptionSupplier)

Returns the contained value if present, otherwise throws an exception created by the provided provider.

String message = null;
String messageNew = "关注公众号:小王博客基地";
Optional.ofNullable(messageNew).orElseThrow(() -> new RuntimeException("为空了,还不看看!"));
Optional.ofNullable(message).orElseThrow(() -> new RuntimeException("为空了,还不看看!"));

We can customize the exception, and then refer to it!

insert image description here

Source code view:

If it is empty, go to the exception written by yourself!

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    
    
    if (value != null) {
    
    
        return value;
    } else {
    
    
        throw exceptionSupplier.get();
    }
}

13. Summary of examples

/**
 * @author wangzhenjun
 * @date 2023/2/27 10:22
 */
@Slf4j
public class OptionalTest {
    
    

    public static void main(String[] args) {
    
    

        Optional<Object> empty = Optional.empty();
        log.info("empty值:{}",empty);


        Test testNew  = new Test();
        Test test = null;
        Optional<Test> optionalNew = Optional.of(testNew);
        log.info(" optional对象:{}",optionalNew);
//        Optional<Test> optional = Optional.of(test);

        Optional<Test> optionalTest = Optional.ofNullable(test);
        log.info(" optional对象中的ofNullable方法返回值:{}",optionalTest);
        Optional<Test> optionalTestNew = Optional.ofNullable(testNew);
        log.info(" optional对象中的ofNullable方法new返回值:{}",optionalTestNew);

        Test test2 = optionalTestNew.get();
        log.info("原来有值的:经过Optional包装后get后得到原来的值:{}",test2);
        // Test test1 = optionalTest.get();
        // log.info("原来没有值的:经过Optional包装后get后得到原来的值:{}",test1);

        boolean present = optionalTestNew.isPresent();
        log.info("optionalTestNew调用是否为空:{}",present);
        boolean present1 = optionalTest.isPresent();
        log.info("optionalTest调用是否为空:{}",present1);

        optionalTest.ifPresent(new Consumer<Test>() {
    
    
            @Override
            public void accept(Test test) {
    
    
                log.info("我是调用ifPresent执行后的打印=====");
            }
        });
        optionalTestNew.ifPresent(testInner -> log.info("我是调用ifPresent执行后的打印"));

        testNew.setName("萧炎");
        testNew.setAge(33);
        Optional<Test> optionalTest1 = optionalTestNew.filter(test1 -> test1.getAge() > 30);
        log.info("过滤后的结果:{}",optionalTest1.get());

        Optional<String> stringOptional = optionalTestNew.map(Test::getName);
        log.info("map后获得字段值:{}",stringOptional.get());

        Optional<String> optional = optionalTestNew.flatMap(OptionalTest::getFlatMap);
        log.info("flatMap后得到的字段:{}",optional.get());

        String message = null;
        String messageNew = "关注公众号:小王博客基地";

        String nullString = Optional.ofNullable(message).orElse("这是一个空字符串!");
        log.info("这是空字符串打印的:{}",nullString);
        String string = Optional.ofNullable(messageNew).orElse("=====这是一个空字符串!");
        log.info("这是字符串打印的:{}",string);

        String orElseGet = Optional.ofNullable(message).orElseGet(() -> "这还是一个空的字符串");
        log.info("orElseGet调用:这是空字符串打印的:{}",orElseGet);
        String orElseGetString = Optional.ofNullable(messageNew).orElseGet(() -> "这还是一个空的字符串");
        log.info("orElseGet调用:这是字符串打印的:{}",orElseGetString);

        Optional.ofNullable(messageNew).orElseThrow(() -> new RuntimeException("为空了,还不看看!"));
        Optional.ofNullable(message).orElseThrow(() -> new RuntimeException("为空了,还不看看!"));



    }

    private static Optional<String> getFlatMap(Test test){
    
    
        return Optional.ofNullable(test).map(Test::getName);
    }

}

Four. Summary

Here is no demonstration of actual combat, basically combined use:

Optional.ofNullable(需要判断的对象).ifPresent(具体操作)

In fact, compared with if, it is more elegant. The main purpose is to prevent that some places are not considered and if the judgment of if is forgotten, then the follow-up may lead to a null pointer. If you use Optional, then this problem can be avoided.

Just like using more design patterns, you still need to use more to make your code more robust and elegant! Of course you can't overuse it! !

It's helpful to you, please don't be stingy with your little hands of getting rich and pay attention! ,
Writing is not easy, please give me some support, your support is the driving force for my writing!

Pay attention to the editor's WeChat public account, and communicate and learn together! Read the article first!

Guess you like

Origin blog.csdn.net/qq_52423918/article/details/129240891
Recommended