@value 默认值为null_JAVA8之妙用Optional解决判断Null为空的问题

引言在文章的开头,先说下NPE问题,NPE问题就是,我们在开发中经常碰到的NullPointerException.假设我们有两个类,他们的UML类图如下图所示

9a925ccc36bb62c01d3848f11771a061.png

在这种情况下,有如下代码

user.getAddress().getProvince();

这种写法,在user为null时,是有可能报NullPointerException异常的。为了解决这个问题,于是采用下面的写法

if(user!=null){
    Address address = user.getAddress();
    if(address!=null){
        String province = address.getProvince();
    }
}

这种写法是比较丑陋的,为了避免上述丑陋的写法,让丑陋的设计变得优雅。JAVA8提供了Optional类来优化这种写法,接下来的正文部分进行详细说明

API介绍先介绍一下API,与其他文章不同的是,本文采取类比的方式来讲,同时结合源码。而不像其他文章一样,一个个API罗列出来,让人找不到重点。

1、Optional(T value),empty(),of(T value),ofNullable(T value)

这四个函数之间具有相关性,因此放在一组进行记忆。

先说明一下,Optional(T value),即构造函数,它是private权限的,不能由外部调用的。其余三个函数是public权限,供我们所调用。那么,Optional的本质,就是内部储存了一个真实的值,在构造的时候,就直接判断其值是否为空。好吧,这么说还是比较抽象。直接上Optional(T value)构造函数的源码,如下图所示

ae9c2f8ff3223793a08cd94f9263fed0.png

那么,of(T value)的源码如下

public static  Optional of(T value) {return new Optional<>(value);
}

也就是说of(T value)函数内部调用了构造函数。根据构造函数的源码我们可以得出两个结论:

  • 通过of(T value)函数所构造出的Optional对象,当Value值为空时,依然会报NullPointerException。

  • 通过of(T value)函数所构造出的Optional对象,当Value值不为空时,能正常构造Optional对象。

除此之外呢,Optional类内部还维护一个value为null的对象,大概就是长下面这样的

public final class Optional<T> {
    //省略....
    private static final Optional> EMPTY = new Optional<>();
    private Optional() {
        this.value = null;
    }
    //省略...
    public static Optional empty() {
        @SuppressWarnings("unchecked")
        Optional t = (Optional) EMPTY;return t;
    }
}

那么,empty()的作用就是返回EMPTY对象。

好了铺垫了这么多,可以说ofNullable(T value)的作用了,上源码

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

好吧,大家应该都看得懂什么意思了。相比较of(T value)的区别就是,当value值为null时,of(T value)会报NullPointerException异常;ofNullable(T value)不会throw Exception,ofNullable(T value)直接返回一个EMPTY对象。

那是不是意味着,我们在项目中只用ofNullable函数而不用of函数呢?

不是的,一个东西存在那么自然有存在的价值。当我们在运行过程中,不想隐藏NullPointerException。而是要立即报告,这种情况下就用Of函数。但是不得不承认,这样的场景真的很少。博主也仅在写junit测试用例中用到过此函数。

2、orElse(T other),orElseGet(Supplier extends T> other)和orElseThrow(Supplier extends X> exceptionSupplier)

这三个函数放一组进行记忆,都是在构造函数传入的value值为null时,进行调用的。orElse和orElseGet的用法如下所示,相当于value值为null时,给予一个默认值:

@Test
public void test() {
    User user = null;
    user = Optional.ofNullable(user).orElse(createUser());
    user = Optional.ofNullable(user).orElseGet(() -> createUser());

}
public User createUser(){
    User user = new User();
    user.setName("zhangsan");
    return user;
}

这两个函数的区别:当user值不为null时,orElse函数依然会执行createUser()方法,而orElseGet函数并不会执行createUser()方法,大家可自行测试。

至于orElseThrow,就是value值为null时,直接抛一个异常出去,用法如下所示

User user = null;
Optional.ofNullable(user).orElseThrow(()->new Exception("用户不存在"));

3、map(Function super T, ? extends U> mapper)和flatMap(Function super T, Optional> mapper)

这两个函数放在一组记忆,这两个函数做的是转换值的操作。

直接上源码

public final class Optional<T> {
    //省略....
     public Optional map(Function super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);if (!isPresent())return empty();else {return Optional.ofNullable(mapper.apply(value));
        }
    }//省略...public Optional flatMap(Function super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);if (!isPresent())return empty();else {return Objects.requireNonNull(mapper.apply(value));
        }
    }
}

这两个函数,在函数体上没什么区别。唯一区别的就是入参,map函数所接受的入参类型为Function super T, ? extends U>,而flapMap的入参类型为Function super T, Optional>。

在具体用法上,对于map而言:

如果User结构是下面这样的

public class User {
    private String name;
    public String getName() {
        return name;
    }
}

这时候取name的写法如下所示

String city = Optional.ofNullable(user).map(u-> u.getName()).get();

对于flatMap而言:

如果User结构是下面这样的

public class User {
    private String name;
    public Optional getName() {
        return Optional.ofNullable(name);
    }
}

这时候取name的写法如下所示

String city = Optional.ofNullable(user).flatMap(u-> u.getName()).get();

4、isPresent()和ifPresent(Consumer super T> consumer)

这两个函数放在一起记忆,isPresent即判断value值是否为空,而ifPresent就是在value值不为空时,做一些操作。这两个函数的源码如下

public final class Optional<T> {
    //省略....
    public boolean isPresent() {
        return value != null;
    }
    //省略...
    public void ifPresent(Consumer super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
}

需要额外说明的是,大家千万不要把

if (user != null){
   // TODO: do something
}

给写成

User user = Optional.ofNullable(user);
if (Optional.isPresent()){
   // TODO: do something
}

因为这样写,代码结构依然丑陋。博主会在后面给出正确写法

至于ifPresent(Consumer super T> consumer),用法也很简单,如下所示

Optional.ofNullable(user).ifPresent(u->{
    // TODO: do something
});

5、filter(Predicate super T> predicate)

不多说,直接上源码

public final class Optional<T> {
    //省略....
   Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
}

filter 方法接受一个 Predicate 来对 Optional 中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个 Optional;否则返回 Optional.empty。

用法如下

Optional user1 = Optional.ofNullable(user).filter(u -> u.getName().length()<6);

如上所示,如果user的name的长度是小于6的,则返回。如果是大于6的,则返回一个EMPTY对象。

实战使用例一

在函数方法中

以前写法

public String getCity(User user)  throws Exception{
        if(user!=null){
            if(user.getAddress()!=null){
                Address address = user.getAddress();
                if(address.getCity()!=null){
                    return address.getCity();
                }
            }
        }
        throw new Excpetion("取值错误"); 
    }

JAVA8写法

public String getCity(User user) throws Exception{
    return Optional.ofNullable(user)
                   .map(u-> u.getAddress())
                   .map(a->a.getCity())
                   .orElseThrow(()->new Exception("取指错误"));
}

例二

比如,在主程序中

以前写法

if(user!=null){
    dosomething(user);
}

JAVA8写法

Optional.ofNullable(user)
    .ifPresent(u->{
        dosomething(u);
});

例三

以前写法

public User getUser(User user) throws Exception{
    if(user!=null){
        String name = user.getName();
        if("zhangsan".equals(name)){
            return user;
        }
    }else{
        user = new User();
        user.setName("zhangsan");
        return user;
    }
}

java8写法

public User getUser(User user) {
    return Optional.ofNullable(user)
                   .filter(u->"zhangsan".equals(u.getName()))
                   .orElseGet(()-> {
                        User user1 = new User();
                        user1.setName("zhangsan");
                        return user1;
                   });
}

其他的例子,不一一列举了。不过采用这种链式编程,虽然代码优雅了。但是,逻辑性没那么明显,可读性有所降低,大家项目中看情况酌情使用。

zjhred

blog.csdn.net/zjhred/article/details/84976734

4fd2cdbd994cedeaf437597977b593a4.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/534636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql百万数据根据索引查询_mysql创建多列索引查询百万表数据的性能优化经验分享...

最近发现最代码网站中的收到的评论&#xff0c;提到我的&#xff0c;心情被赞的查询异常缓慢&#xff0c;通过nginx日志发现响应时间快的在5s&#xff0c;慢的有13s&#xff0c;终于忍无可忍花时间来解决了。执行explain之后的截图如下&#xff1a;可以看到possible_keys中有很…

php用到的mysql语句_PHP中常用到的一些MySQL语句_php

在php开发中&#xff0c;经常会使用到mysql语句&#xff0c;下面就为您列举了一些经常使用的MySQL语句&#xff0c;希望对您平时的学习和开发工作能起到些许的作用。MySQL语句显示数据库或表:show databases;//然后可以use database_name;show tables;MySQL语句更改表名:alter …

mysql执行计划性能_MySQL SQL性能分析Explain执行计划

一. 执行计划返回信息详解①. 执行计划所含字段输出列含义id查询标识select_type查询类型table查询涉及的表partitions匹配到的分区信息type连接类型possible_keys可能选择的索引key实际使用的索引key_len实际使用的索引的长度ref和索引进行比较的列rows需要被检索的大致行数fi…

mysql定时作业_mysql 让一个存储过程定时作业的代码(转)

1、在mysql 中建立一个数据库 test1语句&#xff1a;create database test12、创建表examinfocreate table examinfo(id int auto_increment not null,endtime datetime,primary key(id));3 插入数据&#xff1a;insert into examinfo values(‘1‘,‘2011-4-23 23:26:50‘);4 …

table虚线边框_web前端工程师7天0基础到精通(TABLE+CSS制作《互联世纪网》)

项目七 项目实践&#xff1a;TABLECSS制作《互联世纪网》实践目标1、 熟悉CSS属性2、 熟练运用CSS属性控制网页样式3、 熟悉网页制作流程项目简介&#xff1a;通过上一章节的学习&#xff0c;我们了解了CSS样式能更加方便、有效地控制网页结构和布局网页元素&#xff0c;大大提…

mixamo骨骼_mixamo动作库的模型和动作绑定控制器的方法-上集

1.首先从网站下载带调好动作的文件fbx&#xff0c;我们将fbx场景文件转换成c4d场景文件。没转换之前转换之后选择场次&#xff0c;在文件菜单里找到当前场次到新文档&#xff01;2.我们将模型重置为Tpose方便后续操作&#xff0c;没重置之前模型为k好的动作模式不能使用选中权重…

mysql 101_MySQL 调优/优化的 101 个建议!

原文&#xff1a;http://www.monitis.com/blog/101-tips-to-mysql-tuning-and-optimization/MySQL是一个强大的开源数据库。随着MySQL上的应用越来越多&#xff0c;MySQL逐渐遇到了瓶颈。这里提供 101 条优化 MySQL 的建议。有些技巧适合特定的安装环境&#xff0c;但是思路是相…

数据安全:保护个人隐私和企业机密的关键

在当今数字化时代&#xff0c;数据已经成为了一种宝贵的资源。无论是个人还是企业&#xff0c;都离不开数据的支持。然而&#xff0c;随着数据的不断增长和广泛应用&#xff0c;数据安全问题也日益突出。数据泄露、黑客攻击、网络诈骗等安全事件层出不穷&#xff0c;给个人和企…

python批量跑plsql_python实现自动化报表(Oracle/plsql/Excel/多线程)

# -*- coding: utf-8 -*-# Create time: 2019-10-16# Update time: 2019-11-28# Version: 1.0# Version: 2.0 增加多线程/出错自动重新运行模块# 导入模块import cx_Oracleimport osimport pandas as pdimport pandas.io.sql as sqlimport timeimport openpyxlimport xlwings a…

mysql 配置邮件_SQL 邮件配置篇

exec sp_configure show advanced options,1RECONFIGURE WITHOVERRIDEgoexec sp_configure database mail xps,1RECONFIGURE WITHOVERRIDEgo--2.创建邮件帐户信息EXECmsdb..Sysmail_add_account_spACCOUNT_NAME OCTMamiETL,--邮件帐户名称EMAIL_ADDRESS OCTMamiETL163.com,--发…

python 抽奖 配音乐_抖音上超好听的神曲音乐,Python教你一次性下载

不知道什么时候开始&#xff0c;中国出现了南抖音、北快手的互文格局(东市买骏马&#xff0c;西市买鞍鞯…)。刚才提到了&#xff0c;之前比较喜欢刷抖音&#xff0c;对于我这种佛系程序猿&#xff0c;看网上这些整容妹子基本一个样。喜欢抖音主要是两个初衷&#xff0c;学做菜…

mysql批量写入100万数据_Mysql数据库实践操作之————批量插入数据(100万级别的数据)-阿里云开发者社区...

第一种方法&#xff1a;使用insert into 插入从Redis每次获取100条数据&#xff0c;根据条件去插入到Mysql数据库中&#xff1a;条件&#xff1a;如果当前队列中的值大于1000条&#xff0c;则会自动的条用该方法&#xff0c;该方法每次获取从队列的头部每次获取100掉数据插入到…

mysql多客户端数据不同步_一种多终端设备上的数据同步方法

一种多终端设备上的数据同步方法【技术领域】[0001] 属于移动通信技术领域&#xff0c;特别是涉及基于离网环境下多种移动终端设备之间的数 据同步的方法。 技术背景[0002] 90年代未&#xff0c;数据同步始于有线连接&#xff0c;如MAC机作为数据中心&#xff0c;与终端设备(iP…

oem监控mysql_OEM12c 安装配置MySQL Plug-in用来监控MySQL

Plug-in--注册信息[roottest agent]# /oem/emcli setup -urlhttps://omsdb.localdomain:7301/em -usernamesysmanOracle Enterprise Manager 12c 3.Copyright (c) 1996, 2013 Oracle Corporation and/or its affiliates. All rights reserved.The configuration directory &quo…

怎么利用迭代器写入mysql_range()是什么?为什么不生产迭代器?

本篇文章给大家带来的内容是关于range()是什么&#xff1f;为什么不生产迭代器&#xff1f;有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你有所帮助。迭代器是 23 种设计模式中最常用的一种(之一)&#xff0c;在 Python 中随处可见它的身影&#x…

java 流式_Java开发笔记(七十二)Java8新增的流式处理

通过前面几篇文章的学习&#xff0c;大家应能掌握几种容器类型的常见用法&#xff0c;对于简单的增删改和遍历操作&#xff0c;各容器实例都提供了相应的处理方法&#xff0c;对于实际开发中频繁使用的清单List&#xff0c;还能利用Arrays工具的asList方法给清单对象做初始化赋…

java保留二位小数_java使double保留两位小数的多方法 java保留两位小数

复制代码代码如下:mport java.text.DecimalFormat;DecimalFormat df new DecimalFormat("######0.00");double d1 3.23456double d2 0.0;double d3 2.0;df.format(d1);df.format(d2);df.format(d3);3个结果分别为:复制代码代码如下:3.230.002.00java保留两位…

linux java jar打包_【Java】Java程序打包成jar包在Linux上运行

当需要把在Windows上开发的Java程序用在Linux上运行时&#xff0c;就需要吧该Java程序打包成jar包上传到Linux上去运行。1.Java程序用MyEclipse打包成可运行的jar包(1)在MyEclipse中选中需要打包的项目&#xff0c;点击右键&#xff0c;选择&#xff1a;Export... 如下图所示&a…

java匿名对象 回收_Java 匿名对象

我们知道一般实例化一个对象的格式&#xff0c;如下&#xff1a;Car car new Car();其中&#xff0c;变量名 car 就是 new Car() 这个对象的名字。car 是引用类型的变量&#xff0c;它的值存放的是对象的引用(或地址)&#xff0c;通过 car 这个变量我们就可以间接使用对象。那…

java int 正则表达式_java正则表达式

Java正则表达式正则表达式定义了字符串的模式。正则表达式可以用来搜索、编辑或处理文本。正则表达式并不仅限于某一种语言&#xff0c;但是在每种语言中有细微的差别。Java正则表达式和Perl的是最为相似的。java.util.regex包主要包括以下三个类&#xff1a;Pattern类&#xf…