I. Introduction
The most common exception in our development is NullPointerException
that 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 Optional
solve 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 Optional
class 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:
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);
2. of(T value)
Pass in a parameter and return an
Optional
object, if the parameter is empty, reportNullPointerException
!
Test testNew = new Test();
Test test = null;
Optional<Test> optionalNew = Optional.of(testNew);
log.info(" optional对象:{}",optionalNew);
Optional<Test> optional = Optional.of(test);
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 Objects
in 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);
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);
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);
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 Enter
will become lambda again!
optionalTest.ifPresent(new Consumer<Test>() {
@Override
public void accept(Test test) {
log.info("我是调用ifPresent执行后的打印=====");
}
});
optionalTestNew.ifPresent(testInner -> log.info("我是调用ifPresent执行后的打印"));
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());
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());
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);
}
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);
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);
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!
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!