我常说学习一定要有目的,首先发现问题,或者不便之处,然后寻找解决方案,解决方案可能有很多,我们要选择好的方法来使用
10多年的多伦网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。营销型网站建设的优势是能够根据用户设备显示端的尺寸不同,自动调整多伦建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。创新互联建站从事“多伦网站设计”,“多伦网站推广”以来,每个客户项目都认真落实执行。
这篇文章介绍JDK8推出的Optional容器,会从以下几点展开:
由此一起来认识Optional的正确使用方式,远比我们想象的强大,好用,看很多文章和教程都在讲API,个人感觉调用一个方法谁不会?它到底好在哪才是最重要的,我发布的文章都秉承发现问题,解决问题的理念展开,好了,不吹了,精彩的要来了!
作为Java程序员遇到NullPointerException是非常痛苦的,这可能是我们遇到的最多的异常了
前后端联调:嗨!哥们,你这500啥意思呀?
后端:先是沉思,这怎么会有空指针?对前端说:哥们等1分钟,马上解决,我可不能说空指针,我可是老开发了!说空指针多没面子。
产生过这种无奈的请在评论区大声说出来!无论是新手还是专家,在NullPointerException面前可谓众生平等
我们编程时经常承受:写了类型检查,值判断,最终没想到竟然是一个null的痛苦,毫不留情的甩出来一个令人厌烦的NullPointerException,比如:
系统中用户,有些用户进行了实名认证,拥有身份证信息,有些用户并没有完成实名认证就没有身份证信息【不要深究设计是否合理,仅仅是举例讲解Optional知识点】
用户类:
public class User {
private Long id;
private String name;
// 身份证对象
private IdCard idCard;
// getter、setter、toString
}
身份证类:
public class IdCard {
private Long id;
// 身份证号码
private String idNum;
// getter、setter、toString
}
测试类:获取用户的身份证号码
public class OptionalMain {
public static void main(String[] args) {
// 创建用户对象
User user = new User();
// 调用一系列get方法获取身份证号码
// 因为调用 getIdCard()时并没有身份证对象为null,再调用getIdNum方法则出现 NullPointerException
String idNum = user.getIdCard().getIdNum();
System.out.println(idNum);
}
}
运行结果:
如果user是传递进来的,传进来的user也有可能是null
怎样做才能避免不期而至的NullPointerException?通常,在需要的地方添加null的检查,所以我们的代码多了很多的判断是否为null的验证,影响代码结构,甚至有时不加思索是否需要验证也会统一加上非空判断,来避免不可预知的空值,防止生产环境造成损失!并且添加的方式往往各有不同:
嵌套判断:
public class OptionalMain {
public static void main(String[] args) {
User user = new User();
// 判断user是否为null
if(user != null) {
IdCard idCard = user.getIdCard();
// 判断 idCard 是否为null
if(idCard != null) {
// 获取身份证号码
System.out.println(idCard.getIdNum());
}else {
System.out.println("未实名认证!");
}
}else {
System.out.println("该用户不存在!");
}
}
}
逐个判断:
public class OptionalMain {
/**
* 获取身份证号码
* @param user:用户
* @return:身份证号码
*/
public static String getUserIdcardNum(User user) {
// 判断用户是否为空
if(user == null) {
return "无此用户";
}
// 判断是否实名认证
if(user.getIdCard() == null) {
return "该用户未实名认证";
}
// 返回身份证号码,如果:要对身份证号码进行操作,也要对idNum进行非空判断
return user.getIdCard().getIdNum();
}
public static void main(String[] args) {
// 创建用户对象
User user = new User();
// 1、调用获取身份证方法,有用户但未实名
System.out.println("******未认证******");
String userIdcardNum1 = getUserIdcardNum(user);
System.out.println("结果:" + userIdcardNum1);
// 2、传递空用户
System.out.println("******空用户******");
String userIdcardNum2 = getUserIdcardNum(null);
System.out.println("结果:" + userIdcardNum2);
// 3、创建身份证对象
IdCard idCard = new IdCard();
idCard.setId(1L);
idCard.setIdNum("411481199611111516");
user.setIdCard(idCard);
// 传递实名认证的用户
System.out.println("******已认证******");
String userIdcardNum3 = getUserIdcardNum(user);
System.out.println("结果:" + userIdcardNum3);
}
}
运行结果:
如果有其他要求,就要做更多的非空判断,影响代码的连贯性,净判断空值了
一旦忘记判断某一个值是否为空,就又要和 NullPointerException 偶遇了,它并不是女朋友,而是最不想遇见的【债主】
Java团队结合Haskell和Scala语言对null值的处理方式,在JDK8时推出Optional类来专门处理空值问题,当然该类并不是为了避免我们去写!=null的非空判断,他功能很强,配合Lambda表达式更香
/**
* A container object which may or may not contain a non-null value.
一个可以包含或不包含非空值的容器对象
* If a value is present, {@code isPresent()} will return {@code true} and
* {@code get()} will return the value.
如果存在值,isPresent()方法会返回true,通过get()方法返回值
*
*Additional methods that depend on the presence or absence of a contained
* value are provided, such as {@link #orElse(java.lang.Object) orElse()}
* (return a default value if value not present) and
* {@link #ifPresent(java.util.function.Consumer) ifPresent()} (execute a block
* of code if the value is present).
提供了取决于是否存在包含值的其他方法,比如orElse,如果值不存在,则返回默认值 并且 可以通过ifPresent()
判断值是否存在,存在则执行代码块
*This is a value-based
* class; use of identity-sensitive operations (including reference equality
* ({@code ==}), identity hash code, or synchronization) on instances of
* {@code Optional} may have unpredictable results and should be avoided.
这是一个基于值的类,应避免使用于身份敏感操作【这里应该意思是:对象是否存在不确定的敏感操作】(包括引用 ==,哈希或同步)的实例可能会产生不可预测的结果
* @since
从Optional类的定义和声明来看特点如下:
通过案例感受Optional处理null的套路:
User类:
public class User {
private Long id;
private String name;
// 将可能为null的对象放入Optional中
private OptionalidCard;
// getter、setter、toString
}
IdCard类:
public class IdCard {
private Long id;
// 如果身份证号码也允许为null,也可以放入Optional中【Optional】
// 但是实名认证了,身份证号码就是必须的了不是吗,
// 一旦使用了Optional,没有身份证号码时,也不会出现报错,可能会出现数据错误,所以也不要滥用
private String idNum;
// getter、setter、toString
}
测试类:
public class OptionalMain {
/**
* 获取身份证号码
* @param user:用户
* @return:身份证号码
*/
public static String getUserIdcardNum(User user){
// 将User通过Optional.of() 方法 存储进Optional
OptionaloptionalUser = Optional.of(user);
// 通过map方法先获取user中身份对象,orElse:如果没有,返回一个自定义的Optional对象
OptionaloptionalIdCard = optionalUser.map(User::getIdCard).orElse(Optional.of(new IdCard()));
// 通过map方法获取IdCard中的idNum,如果没有返回 "无实名认证"字符串
String idNum = optionalIdCard.map(IdCard::getIdNum).orElse("无实名认证");
return idNum;
}
public static void main(String[] args){
User user = new User();
// 将user对象传进方法中,该对象中的IdCard为null
System.out.println(getUserIdcardNum(user));
}
}
运行结果:
我们仅仅传入了user对象,IdCard为null,通过getUserIdcardNum方法处理之后,返回定义的无实名认证,这里并没有做if...else的判断,这样的代码看起来更优雅,不是吗?
总结来说:
接下来讲解一下Optional中的API,系统认识,学习强大的Optional
方法 |
作用 |
Optional.empty() |
创建一个空的 Optional 实例 |
Optional.of(T t) |
创建一个 Optional 实例,当 t为null时抛出异常 |
Optional.ofNullable(T t) |
创建一个 Optional 实例,但当 t为null时不会抛出异常,而是返回一个空的实例 |
get() |
获取optional实例中的对象,当optional 容器为空时报错 |
isPresent() |
判断optional是否为空,如果空则返回false,否则返回true |
ifPresent(Consumer c) |
如果optional不为空,则将optional中的对象传给Comsumer函数 |
orElse(T other) |
如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个默认值 |
orElseGet(Supplier |
如果optional不为空,则返回optional中的对象;如果为null,则使用Supplier函数生成默认值other |
orElseThrow(Supplier |
如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常 |
filter(Predicate |
如果optional不为空,则执行断言函数p,如果p的结果为true,则返回原本的optional,否则返回空的optional |
map(Function |
如果optional不为空,则将optional中的对象 t 映射成另外一个对象 u,并将 u 存放到一个新的optional容器中 |
flatMap(Function< T,Optional> mapper) |
跟上面一样,在optional不为空的情况下,将对象t映射成另外一个optional,区别在于:map会自动将u放到optional中,而flatMap则需要手动给u创建一个optional |
强烈建议:打开编辑器,多翻阅源码,对学习和编码都有很大帮助,刚开始看不懂没关系,量变产生质变
通过Optional源码发现:
代码实现:
// 创建一个包装对象值为空的Optional对象
Optional
作用:获取optional实例中的对象,当optional 容器为空时报错
源码:
null值Optional:
// 创建值为null的Optional对象
Optionaloptional = Optional.empty();
// get返回 NoSuchElementException("No value present")
String result = optional.get();
System.out.println(result);
非null值Optional:
// 创建值为:optional的Optional对象
Optionaloptional = Optional.of("optional");
// 返回值 optional
String result = optional.get();
System.out.println(result);
作用:判断optional是否为空,如果空则返回false,否则返回true
源码:
代码实现:
Listusers = new ArrayList<>();
users.add("柯南");
users.add("佩奇");
users.add("喜洋洋");
Optional> optional = Optional.of(users);
// 判断并消费
optional.ifPresent(System.out::println);
作用:如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个默认值
源码:
代码实现:
User user = new User(1L,"格雷福斯");
// 1、存储非null数据
OptionaluserOptional = Optional.ofNullable(user);
// 获取用户名
String name1 = userOptional.orElse(new User(0L, "帅气添甄")).getName();
// 非null,结果为:格雷福斯
System.out.println(name1);
// 2、存储null数据
OptionalnullOptional = Optional.ofNullable(null);
String name2 = nullOptional.orElse(new User(0L, "帅气添甄")).getName();
// 为null,结果:帅气添甄
System.out.println(name2);
作用:如果optional不为空,则返回optional中的对象;如果为null,则使用Supplier函数生成默认值other
源码:
代码实现:
User user = new User(1L,"格雷福斯");
OptionaluserOptional = Optional.ofNullable(user);
// 为null直接返回`Supplier`生产型函数接口返回的对象
String name = userOptional.orElseGet(() new User(0L, "添甄")).getName();
System.out.println(name);
作用:如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常
源码:
代码实现:
User user = new User(1L,"格雷福斯");
OptionaluserOptional = Optional.ofNullable(user);
// 为null直接返回`Supplier`生产型函数接口返回的对象
String name = userOptional.orElseGet(() new User(0L, "添甄")).getName();
System.out.println(name);
作用:如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常
源码:
代码实现:
User user = new User(1L,"格雷福斯");
OptionaluserOptional = Optional.ofNullable(user);
// 如果数据为null,抛出 指定异常
String name = userOptional.orElseThrow(() new RuntimeException("无数据")).getName();
System.out.println(name);
作用:如果optional不为空,则执行断言函数p,如果p的结果为true,则返回原本的optional,否则返回空的optional
源码:
代码实现:
User user = new User(1L,"格雷福斯");
OptionaluserOptional = Optional.ofNullable(user);
// 过滤名字长度大于3,如果有值才输出,没值就不输出
userOptional.filter(item -> item.getName().length() > 3).ifPresent(System.out::println);
作用:如果optional不为空,则将optional中的对象 t 映射成另外一个对象 u,并将 u 存放到一个新的optional容器中,该方法与Stream的map作用一样
源码:
代码实现:
User user = new User(1L,"格雷福斯");
OptionaluserOptional = Optional.ofNullable(user);
// 只获取用户名
String name = userOptional.map(User::getName).orElse("添甄");
System.out.println(name);
作用:在optional不为空的情况下,将对象t映射成另外一个optional,17-flatMapmap接收的是U类型,而flatMap接收的是Optional类型,返回也是需要放进Optional中
源码:
代码实现:
User user = new User(1L,"格雷福斯");
OptionaluserOptional = Optional.ofNullable(null);
Optionaloptional = userOptional.flatMap(item -> Optional.ofNullable(item.getName()));
String name = optional.orElse("添甄");
System.out.println(name);
获取用户名:
User user = new User(1L,"格雷福斯");
OptionaluserOptional = Optional.ofNullable(user);
// 判断是否有值
if (userOptional.isPresent()) {
String name = userOptional.get().getName();
System.out.println(name);
}else {
System.out.println("无值");
}
通过调用isPresent方法判断是否有值,这还是增加了判断,破坏代码结构
正确姿势:
多用map,orElse,filter方法发挥Optional的作用
User user = new User(1L,"格雷福斯");
OptionaluserOptional = Optional.ofNullable(user);
String name = userOptional.map(User::getName).orElse("无值");
System.out.println(name);
文章出自:石添的编程哲学,如有转载本文请联系【石添的编程哲学】今日头条号。
新闻标题:正确使用Java8中的Optional,它远比我们想象的优秀
浏览地址:http://www.gawzjz.com/qtweb/news43/185393.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联