新同事一来就把整个项目中可能存在NPE解决了
Posted 李哥技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了新同事一来就把整个项目中可能存在NPE解决了相关的知识,希望对你有一定的参考价值。
大家好,我是李哥。
JDK1.6和JDK1.8是主流的两个大版本,目前市场上用的最多最多的依然是JDK1.8。所以,我们有必要聊一聊Java8的一些新特性。
- 深入理解lambda的奥秘
- 深入理解Stream之原理剖析
- 深入理解Stream之foreach源码解析
- 深入浅出NPE神器Optional
- 谈谈接口默认方法与静态方法
- 深入浅出重复注解与类型注解
- 深入浅出JVM元空间metaspace
- 深入理解CompletableFuture异步编程
今天我们先来聊聊Optional深度解析。
防止NPE:程序员的基本素养
身为一名Java程序员,大家可能都有这样的经历: 调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法。我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数。
没错,防止NPE(NullPointerException),这就是我们作为一名开发工程师的基本素养。
还有很多场景都可能发生NPE,一一列举:
- 返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生 NPE。比如public int f() return null;
- 数据库的查询结果可能为 null。
- 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null,因为null也可以作为一个元素存入集合之中。
- 远程调用返回对象时,一律要求进行空指针判断,防止 NPE。
- 对于 Session 中获取的数据,建议 NPE 检查,避免空指针。
- 级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。建议使用 JDK8 的 Optional 类来防止 NPE 问题。
Optional
Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException)
Optional 最有用武之地的是在那些“更接近数据”的地方,在问题空间中代表实体的对象上,代表月亮消灭你(NPE)。
...扯远了...我们回归正题...
Optional类的doc注释如下:
一个容器对象,可能包含也可能不包含非空值。如果存在值,isPresent() 将返回 true,而 get() 将返回该值。
empty
返回一个空的可选实例。 此 Optional 没有值。
Optional内部包含一个空的实例对象,value值为null,我们可以使用empty这个静态方法来获取。
of
返回具有指定当前非空值的 Optional。
// 调用工厂方法创建Optional实例
Optional<String> lige = Optional.of("Lige");
// 传入参数为null,会抛出NullPointerException.
Optional<String> someNull = Optional.of(null);
通过静态方法of可以获取一个Optional实例,值得注意的是此时不允许传入null,如果传入参数为null,则抛出NullPointerException 。
如果你觉得你也不确定是否为null,那么应该使用ofNullable。
ofNullable
返回一个描述指定值的 Optional,如果非 null,否则返回一个空 Optional。
ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况。
get
如果此 Optional 中存在值,则返回该值,否则抛出 NoSuchElementException。
可见如果当前Optional对象的value是null,调用get方法则会抛出异常,这一点需要注意。
isPresent
如果存在值,则返回 true,否则返回 false。
if (optional.isPresent())
Object object = optional.get();
// TODO: 2022/8/18 todo something
一般情况下isPresent与get配合使用。
ifPresent
如果存在值,则使用该值调用指定的使用者,否则不执行任何操作。
optional.ifPresent(obj ->
// TODO: 2022/8/18 todo something
);
直接使用get有可能抛出异常,如果使用isPresent加以判断后再使用get略显复杂,使用ifPresent能有效解决问题,让我们的重心偏向于有数据的情况,去对数据进行处理。在这里使用lambda表达式,代码简洁,可读性也好。
对于lambda表达式,了解更多可以参考:深入理解lambda的奥秘
filter
如果存在一个值,并且该值与给定的谓词匹配,则返回一个描述该值的 Optional,否则返回一个空的 Optional。
这里的filter与Stream内的filter没有任何关系,不过实现思路都是一致的,都是对当前对象做过滤动作。
optional.filter(it ->
if (it.equals("lige"))
return true;
return false;
).ifPresent(it ->
System.out.println(it);
);
map与flatMap
如果存在值,则将提供的 Optional-bearing 映射函数应用于它,返回该结果,否则返回空 Optional。 此方法类似于 map(Function),但提供的映射器是其结果已经是 Optional 的映射器,如果被调用,flatMap 不会用附加的 Optional 包装它。
可以看到,map与flatMap非常的相似,只不过是传入的Function内的泛型对象不一样。功能也是一样的,针对类型做转换。
Optional<String> flatMapResult = optional.flatMap(new Function<String, Optional<String>>()
@Override
public Optional<String> apply(String s)
return Optional.of(s.toLowerCase());
);
flatMapResult.ifPresent(it ->
System.out.println(it);
);
Optional<String> mapResult = optional.map(new Function<String, String>()
@Override
public String apply(String s)
return s.toLowerCase();
);
mapResult.ifPresent(System.out::println);
orElse、orElseGet、orElseThrow
上面我们说完了if存在如何处理,当然也需要else的处理逻辑了,那就是这仨兄弟了。
原理都是如果Optional的value不为null则返回,如果为null则返回指定值或执行指定逻辑。
orElse与orElseGet都是返回指定值,orElseThrow会抛出指定异常。
String orElseResult = optional.orElse("orElseResult ligejishu");
String orElseGetResult1 = optional.orElseGet(new Supplier<String>()
@Override
public String get()
return "orElseGetResult1 ligejishu";
);
String orElseGetResult2 = optional.orElseGet(() -> "orElseGetResult2 ligejishu");
try
String orElseThrowResult1 = optional.orElseThrow(new Supplier<Throwable>()
@Override
public Throwable get()
return new RuntimeException("ligejishu throw RuntimeException.");
);
String orElseThrowResult2 = optional.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("ligejishu throw RuntimeException."));
catch (Throwable e)
e.printStackTrace();
总结
虽然 Optional 是 Java 8 为了支持流式编程才引入的,但其实它是一个通用的工具。
实际上,在所有地方都使用 Optional 是没有意义的,但是对于不确定的因素的地方检查一下是否为 null 是非常有意义的。
以上是关于新同事一来就把整个项目中可能存在NPE解决了的主要内容,如果未能解决你的问题,请参考以下文章