前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【小家java】java8新特性之---Optional的使用,避免空指针,代替三目运算符

【小家java】java8新特性之---Optional的使用,避免空指针,代替三目运算符

作者头像
YourBatman
发布2019-09-03 14:08:27
2.4K0
发布2019-09-03 14:08:27
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦


每篇一句

涂磊:嘴不饶人心地善,心不饶人嘴上甜。心善之人能直言,嘴甜之人藏迷奸。宁交一个抬杠的鬼,也不交一个嘴甜的贼

空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,使得我们就不用显式进行空值检测

创建一个Optional

Optional.of()或者Optional.ofNullable():创建Optional对象,差别在于of不允许参数是null,而ofNullable则无限制。

代码语言:javascript
复制
   // 参数不能是null
        Optional<Integer> optional1 = Optional.of(10);
        // 参数可以是非null
        Optional<Integer> optional2 = Optional.ofNullable(20);
        // 参数可以是null
        Optional<Integer> optional3 = Optional.ofNullable(null);

        System.out.println(optional1); //Optional[10]
        System.out.println(optional2); //Optional[20]
        System.out.println(optional3); //Optional.empty

如上,我们直接输出了对象。但其实我们用容器装着,调用它的get方法来获取值。所以我们这么做:

代码语言:javascript
复制
System.out.println(optional1.get()); //10
        System.out.println(optional2.get()); //20
        System.out.println(optional3.get()); //java.util.NoSuchElementException: No value present

我们可以看到,第三句话抛出异常了。这是很多初学者非常容易犯的一个错误,如果里面装的是null值,是不能直接使用get方法的。正确的使用姿势:

代码语言:javascript
复制
if (optional3.isPresent()) {
            System.out.println(optional3.get());
        }
特殊对象:Optional.empty() 所有null包装成的Optional对象
代码语言:javascript
复制
public static void main(String[] args) {
        Optional<Integer> optional1 = Optional.ofNullable(null);
        Optional<Integer> optional2 = Optional.ofNullable(null);
        System.out.println(optional1 == optional2);// true
        System.out.println(optional1 == Optional.<Integer>empty());// true

        //哪怕泛型类型都不一样  都是true
        Object o1 = Optional.<Integer>empty();
        Object o2 = Optional.<String>empty();
        System.out.println(o1 == o2);// true 
    }

从上面我们可以看出来,里面装null,不管泛型是啥,都是true。所以我们推测,它源码内部肯定维护着一个单例,源码:

代码语言:javascript
复制
 private static final Optional<?> EMPTY = new Optional<>();
 public static<T> Optional<T> empty() {
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

看源码里,证实了我们的猜测,没毛病。

isPresent():如果里面有值,返回true,否则返回false

需要注意,empty的就是false。所以一旦get就报错

代码语言:javascript
复制
    public static void main(String[] args) {
        System.out.println(Optional.ofNullable(null).isPresent()); //false
        System.out.println(Optional.ofNullable(1).isPresent()); //true
        System.out.println(Optional.empty().isPresent()); ////false
        System.out.println(Optional.empty().get()); //java.util.NoSuchElementException: No value present
    }
ifPresent(Consumer consumer):如果option对象保存的值不是null,则调用consumer对象,否则不调用
代码语言:javascript
复制
Optional<Integer> optional1 = Optional.ofNullable(1);
 
// 如果不是null,调用Consumer
optional1.ifPresent(new Consumer<Integer>() {
	@Override
	public void accept(Integer t) {
		System.out.println("value is " + t);
	}
orElse(value):如果optional对象保存的值不是null,则返回原来的值,否则返回value。
orElseGet(Supplier supplier):功能与orElse一样,只不过orElseGet参数是一个生产者

本人特意把这两个拿出来放在一起,是因为其实很多人并不知道这两个到底有什么区别呢?下面我就具体来说说他们的区别(完全可以当作面试题,深度啊):

代码语言:javascript
复制
  public static void main(String[] args) {
         Optional.ofNullable(null).orElse(get("a"));
        Optional.ofNullable(null).orElseGet(() -> get("b"));
    }

    private static String get(String s) {
        System.out.println(s + ":~~我执行了~~");
        return s;
    }
输出:
a:~~我执行了~~
b:~~我执行了~~

再看下面这个例子:

代码语言:javascript
复制
 Optional.ofNullable("fill").orElse(get("a"));
 Optional.ofNullable("fill").orElseGet(() -> get("b"));
输出:
a:~~我执行了~~
(这里没有输出哦)

对比两者,我们终于发现区别了吧:如果Optional里面的值为null,那两者的效果一模一样。但是当里面的值为null时,我们发现orElse里面代码还是执行的,但是orElseGet里面就不会执行啦。所以使用起来是不是逼格高一点

orElseThrow(判空等场景特别有用)

如下代码,一句话搞定

代码语言:javascript
复制
Date startTime = new Date(Optional.of(req.getFromTime())
                .orElseThrow(() -> new MessagePopException("开始时间不能为空")));

如果不用这个我们得这么写

代码语言:javascript
复制
if(req.getFromTime() == null){
    throw new MessagePopException("开始时间不能为空");
}
Date startTime = req.getFromTime();

稍微麻烦点。使用orElseThrow显得更加的优雅

map(Function):对Optional中保存的值进行函数运算,并返回新的Optional(可以是任何类型)
flatMap():功能与map()相似 具体区别请参考streamAPI那一章

最后

Optional还有一个作用,三目运算符,可以代替三目运算符从而支持方法连缀。

代码语言:javascript
复制
        System.out.println(Optional.ofNullable("demo").orElse("a")); //demo
        System.out.println(Optional.ofNullable(null).orElse("a")); //a
        //或者 使用supplier生产
        System.out.println(Optional.ofNullable(null).orElseGet(() -> "abc")); //abc

下面使用的例子,还可以使用map映射:

代码语言:javascript
复制
    public static void main(String[] args) {
        //此处会直接抛出空指针异常
        //Optional<String> s = Optional.<String>of(null); //java.lang.NullPointerException

        //s可以直接使用,是empty,但是不能get,请配合isPresent()使用
        //Optional<String> s = Optional.<String>ofNullable(null);
        //System.out.println(s); //Optional.empty
        //System.out.println(s.get()); //java.util.NoSuchElementException: No value present

        //对它进行map操作,我们发现即使为null,我们map方法的x.toString()并没有报错  可谓非常友好
        //Optional<String> s = Optional.<String>ofNullable(null).map(x -> x.toString());
        //System.out.println(s); //Optional.empty
        //System.out.println(s.get()); //java.util.NoSuchElementException: No value present


        ////////////综上,我们可以经常这么来使用,可以很好的达到方法连缀的效果////////////
        //1、非常简单的三目运算符  如果是null,就返回1  否则返回里面的值
        Integer v = Optional.<Integer>ofNullable(null).orElse(1);
        System.out.println(v); //1

        //2、三目运算符  结合map  可以实现类型的转换 非常安全且强大
        Integer vvv = Optional.<String>ofNullable(null).map(x -> Integer.valueOf(x)).orElse(100);
        System.out.println(vvv); //100
    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年08月07日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 每篇一句
  • 创建一个Optional
  • 特殊对象:Optional.empty() 所有null包装成的Optional对象
  • isPresent():如果里面有值,返回true,否则返回false
  • ifPresent(Consumer consumer):如果option对象保存的值不是null,则调用consumer对象,否则不调用
  • orElse(value):如果optional对象保存的值不是null,则返回原来的值,否则返回value。
  • orElseGet(Supplier supplier):功能与orElse一样,只不过orElseGet参数是一个生产者
  • orElseThrow(判空等场景特别有用)
  • map(Function):对Optional中保存的值进行函数运算,并返回新的Optional(可以是任何类型)
  • flatMap():功能与map()相似 具体区别请参考streamAPI那一章
  • 最后
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档