航运网站建设计划书,手机端模板网站,怎样进入外贸公司网站,教育门户网站建设一、前言
我们在开发中最常见的异常就是NullPointerException#xff0c;防不胜防啊#xff0c;相信大家肯定被坑过#xff01;
这种基本出现在获取数据库信息中、三方接口#xff0c;获取的对象为空#xff0c;再去get出现#xff01;
解决方案当然简单#xff0c;只…一、前言
我们在开发中最常见的异常就是NullPointerException防不胜防啊相信大家肯定被坑过
这种基本出现在获取数据库信息中、三方接口获取的对象为空再去get出现
解决方案当然简单只需要判断一下不是空在去后续操作为空返回
所有在JDK8时出现了专门处理的方案出来很早了但是小编惭愧一直没有去使用它
最近在看《Java开发手册》一直想着提高自己的代码水平文中就指出了使用Optional来解决NullPointerException
二、Java开发手册规范
小编使用的是2022版的黄山版29页写到
【推荐】防止 NPE是程序员的基本修养注意 NPE 产生的场景
返回类型为基本数据类型return 包装数据类型的对象时自动拆箱有可能产生 NPE
反例public int method() { return Integer 对象; }如果为 null自动解箱抛 NPE。
数据库的查询结果可能为 null。集合里的元素即使 isNotEmpty取出的数据元素也可能为 null。远程调用返回对象时一律要求进行空指针判断防止 NPE。对于 Session 中获取的数据建议进行 NPE 检查避免空指针。级联调用 obj.getA().getB().getC()一连串调用易产生 NPE。
正例使用 JDK8 的 Optional 类来防止 NPE 问题。
这份手册还是不错的推荐反复阅读虽然进不去大厂也要自觉约束自己的代码风格努力向大厂靠
大家现在不知道哪里找的可以下载一下
《Java开发手册》
三、Optional常用方法
小编带大家一起从api文档中的方法一个个带大家慢慢去了解它
1. empty() 返回一个空的Optional实例Optional.empty OptionalObject empty Optional.empty();
log.info(empty值{},empty);2. of(T value) 传入一个参数返回一个Optional对象如果参数为空报NullPointerException Test testNew new Test();
Test test null;
OptionalTest optionalNew Optional.of(testNew);
log.info( optional对象{},optionalNew);
OptionalTest optional Optional.of(test);源码查看
我们看到参数为空会报NullPointerException我们去方法内部看一下就明白了
public static T OptionalT 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;
}我们发现是在Objects类中的requireNonNull方法中判断了是否为空
这个还会出现NullPointerException所以我们一般使用下面的这个方法
3. ofNullable(T value) 参数传入一个对象返回一个Optional对象如果为空将返回一个空的Optional对象就等于Optional.empty Test testNew new Test();
Test test null;
OptionalTest optionalNew Optional.of(testNew);
log.info( optional对象{},optionalNew);OptionalTest optionalTest Optional.ofNullable(test);
log.info( optional对象中的ofNullable方法返回值{},optionalTest);
OptionalTest optionalTestNew Optional.ofNullable(testNew);
log.info( optional对象中的ofNullable方法new返回值{},optionalTestNew);源码查看
我们发现是在方法开始进行非空判断再去调用上面的of(T value)方法
public static T OptionalT ofNullable(T value) {return value null ? empty() : of(value);
}4. get() 如果此Optional中存在值则返回该值否则抛出NoSuchElementException。 Test testNew new Test();
Test test null;
OptionalTest optionalNew Optional.of(testNew);
log.info( optional对象{},optionalNew);
// OptionalTest optional Optional.of(test);OptionalTest optionalTest Optional.ofNullable(test);
log.info( optional对象中的ofNullable方法返回值{},optionalTest);
OptionalTest 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);源码查看
调用开始会进行值判断如果为空则抛异常
public T get() {if (value null) {throw new NoSuchElementException(No value present);}return value;
}5. isPresent() 如果存在值则返回true否则返回false。 这里代码就不加上面的大家参考上面的获取一个Optional对象
boolean present optionalTestNew.isPresent();
log.info(optionalTestNew调用是否为空{},present);
boolean present1 optionalTest.isPresent();
log.info(optionalTest调用是否为空{},present1);源码查看
这就比较简单了!
public boolean isPresent() {return value ! null;
}6. ifPresent(Consumer? super T consumer) 如果存在值则使用该值调用指定的使用者否则不执行任何操作。 主要的就是入参数一个函数式接口有值就会去执行为空则不进行任何操作
小技巧
开始对lambda不了解时可以先按照上面这种方式进行写
大家可以看到Idea给置灰了就是可以优化我们AltEnter 然后再次Enter就会变成后面的lambda optionalTest.ifPresent(new ConsumerTest() {Overridepublic void accept(Test test) {log.info(我是调用ifPresent执行后的打印);}
});
optionalTestNew.ifPresent(testInner - log.info(我是调用ifPresent执行后的打印));源码查看
还是先判断不为空才去执行函数式接口
public void ifPresent(Consumer? super T consumer) {if (value ! null)consumer.accept(value);
}7. filter(Predicate? super T predicate) 如果存在值并且该值符合规则则返回描述该值的Optional否则返回空Optional 是一个Predicate函数接口可以传入实现了Predicate接口的lambda表达式 如果不符合条件就会返回一个Optional.empty
testNew.setName(萧炎);
testNew.setAge(33);
OptionalTest optionalTest1 optionalTestNew.filter(test1 - test1.getAge() 30);
log.info(过滤后的结果{},optionalTest1.get());源码查看
就是判断一下表达式和值是否为空然后就是根据规则判断
public OptionalT filter(Predicate? super T predicate) {Objects.requireNonNull(predicate);if (!isPresent())return this;elsereturn predicate.test(value) ? this : empty();
}8. map(Function? super T,? extends U mapper) 如果存在值则将提供的映射函数应用于该值如果结果为非空则返回描述结果的Optional。否则返回空的Optional。 也是一个函数式接口
OptionalString stringOptional optionalTestNew.map(Test::getName);
log.info(map后获得字段值{},stringOptional.get());源码查看
也是进行非空判断然后执行lambda得到字段后放到ofNullable方法中
publicU OptionalU 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) 如果存在值则将提供的Optional方位映射函数应用于该值返回该结果否则返回空的Optional。此方法类似于map但提供的映射器的结果已经是可选的并且如果调用flatMap不会不会在最后进行任何包装。 OptionalString optional optionalTestNew.flatMap(OptionalTest::getFlatMap);
log.info(flatMap后得到的字段{},optional.get());private static OptionalString getFlatMap(Test test){return Optional.ofNullable(test).map(Test::getName);
}源码查看
也是进行非空判断然后和map不同的是不执行ofNullable方法
publicU OptionalU flatMap(Function? super T, OptionalU mapper) {Objects.requireNonNull(mapper);if (!isPresent())return empty();else {return Objects.requireNonNull(mapper.apply(value));}
}10. orElse(T other) 如果有值则将其返回否则返回指定的其它值。 如果你是一个对象orElse()也要是相同对象
String message null;
String messageNew 关注公众号小王博客基地;String nullString Optional.ofNullable(message).orElse(这是一个空字符串);
log.info(这是空字符串打印的{},nullString);
String string Optional.ofNullable(messageNew).orElse(这是一个空字符串);
log.info(这是字符串打印的{},string);源码查看
简单的为空返回自己定义的不为空直接返回
public T orElse(T other) {return value ! null ? value : other;
}11. orElseGet(Supplier? extends T other) 返回值如果存在否则调用other并返回该调用的结果。 区别 orElse方法将传入的参数作为默认值orElseGet方法可以接受Supplier接口的实现用来生成默认值
如果没有复杂操作Idea也会提醒我们不要使用这个使用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);源码查看
和orElse一样只不过为空调用lambda执行
public T orElseGet(Supplier? extends T other) {return value ! null ? value : other.get();
}12. orElseThrow(Supplier? extends X exceptionSupplier) 返回包含的值如果存在否则抛出由提供的供应商创建的异常。 String message null;
String messageNew 关注公众号小王博客基地;
Optional.ofNullable(messageNew).orElseThrow(() - new RuntimeException(为空了还不看看));
Optional.ofNullable(message).orElseThrow(() - new RuntimeException(为空了还不看看));我们可以自定义异常然后来引用 源码查看
为空则走自己写的异常
public X extends Throwable T orElseThrow(Supplier? extends X exceptionSupplier) throws X {if (value ! null) {return value;} else {throw exceptionSupplier.get();}
}13. 例子汇总
/*** author wangzhenjun* date 2023/2/27 10:22*/
Slf4j
public class OptionalTest {public static void main(String[] args) {OptionalObject empty Optional.empty();log.info(empty值{},empty);Test testNew new Test();Test test null;OptionalTest optionalNew Optional.of(testNew);log.info( optional对象{},optionalNew);
// OptionalTest optional Optional.of(test);OptionalTest optionalTest Optional.ofNullable(test);log.info( optional对象中的ofNullable方法返回值{},optionalTest);OptionalTest 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 ConsumerTest() {Overridepublic void accept(Test test) {log.info(我是调用ifPresent执行后的打印);}});optionalTestNew.ifPresent(testInner - log.info(我是调用ifPresent执行后的打印));testNew.setName(萧炎);testNew.setAge(33);OptionalTest optionalTest1 optionalTestNew.filter(test1 - test1.getAge() 30);log.info(过滤后的结果{},optionalTest1.get());OptionalString stringOptional optionalTestNew.map(Test::getName);log.info(map后获得字段值{},stringOptional.get());OptionalString 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 OptionalString getFlatMap(Test test){return Optional.ofNullable(test).map(Test::getName);}}
四、总结
这里就不在演示实战了基本上组合使用
Optional.ofNullable(需要判断的对象).ifPresent(具体操作)
其实和if相比就是显得优雅一些主要是防止某处没考虑到忘记if判断那么后续可能会导致空指针如果使用Optional的话那么这个问题能够得到避免。
就像多使用设计模式一样让自己的代码更加健壮优雅还是要多使用一些的当然不能过渡使用
对你有帮助还请不要吝啬你的发财小手点点关注哈、 写作不易大家给点支持你的支持是我写作的动力哈
关注小编的微信公众号一起交流学习文章首发看哦