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

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

相关阅读

【小家java】java5新特性(简述十大新特性) 重要一跃

【小家java】java6新特性(简述十大新特性) 鸡肋升级

【小家java】java7新特性(简述八大新特性) 不温不火

【小家java】java8新特性(简述十大新特性) 饱受赞誉

【小家java】java9新特性(简述十大新特性) 褒贬不一

【小家java】java10新特性(简述十大新特性) 小步迭代

【小家java】java11新特性(简述八大新特性) 首个重磅LTS版本


【小家java】java8新特性之—Base64加密和解密原理

【小家java】java8新特性之—反射获取方法参数名

【小家java】java8新特性之—全新的日期、时间API(完全实现了JSR 310规范)

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

【小家java】java8新特性之—lambda表达式的的原理

【小家java】java8新特性之—函数式接口(Supplier、Consumer、Predicate、Function、UnaryOperator,通往高阶设计的好工具)

【小家java】java8新特性之—方法引用

【小家java】java8新特性之—Stream API 详解 (Map-reduce、Collectors收集器、并行流)

【小家java】java8新特性之—外部迭代和内部迭代(对比性能差异)


每篇一句


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


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


创建一个Optional


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

// 参数不能是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方法来获取值。所以我们这么做:


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方法的。正确的使用姿势:

if (optional3.isPresent()) {
            System.out.println(optional3.get());
        }

特殊对象:Optional.empty() 所有null包装成的Optional对象



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。所以我们推测,它源码内部肯定维护着一个单例,源码:

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就报错


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对象,否则不调用

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参数是一个生产者


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


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:~~我执行了~~

再看下面这个例子:


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

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


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


如下代码,一句话搞定


Date startTime = new Date(Optional.of(req.getFromTime())
                .orElseThrow(() -> new MessagePopException("开始时间不能为空")));

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


if(req.getFromTime() == null){
    throw new MessagePopException("开始时间不能为空");
}
Date startTime = req.getFromTime();


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


map(Function):对Optional中保存的值进行函数运算,并返回新的Optional(可以是任何类型)


flatMap():功能与map()相似 具体区别请参考streamAPI那一章

最后


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


     

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映射:

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
    }
相关文章
|
6月前
|
Java Go 开发工具
【Java】(4)五种运算符的说明(&&、||、>=、>、<=、<)、4种控制语句(if、for、while、dowhile)、输入和输出说明
扩展类的赋值运算符不改变运算结果类型,假设最初这个变量的的类型byte类型,无论怎么进行加或追减,最终该变量的数据类型还是byte类型。注:一个表达式中有多个运算符,运算符有优先级,不确定的加小括号,优先级得到提升。当布尔表达式的结果是false的时候,选择表达式2作为整个表达式的执行结果。当布尔表达式的结果是true的时候,选择表达式1作为整个表达式的执行结果。当用户输入的时候,并且最终敲回车键的时候,键入的信息会自动赋值给a。并且,连接运算之后的结果还是一个字符串类型。表达式1 : 表达式2。
215 1
|
6月前
|
安全 Java 容器
告别空指针噩梦:Optional让Java代码更优雅
告别空指针噩梦:Optional让Java代码更优雅
482 94
|
6月前
|
安全 Java 容器
告别繁琐判空:Optional让你的Java代码更优雅
告别繁琐判空:Optional让你的Java代码更优雅
|
6月前
|
安全 Java 开发者
告别NullPointerException:掌握Java Optional的精髓
告别NullPointerException:掌握Java Optional的精髓
|
7月前
|
安全 Java 开发者
告别NullPointerException:拥抱Java Optional
告别NullPointerException:拥抱Java Optional
|
8月前
|
存储 缓存 算法
Java数据类型与运算符深度解析
本文深入解析Java中容易混淆的基础知识,包括八大基本数据类型(如int、Integer)、自动装箱与拆箱机制,以及运算符(如&与&&)的使用区别。通过代码示例剖析内存布局、取值范围及常见陷阱,帮助开发者写出更高效、健壮的代码,并附有面试高频问题解析,夯实基础。
|
9月前
|
存储 人工智能 Java
Java 8 的 Optional:提高代码安全性与可读性
本文深入解析 Java 中的 `NullPointerException` 及其传统处理方式,并介绍了 Java 8 引入的 `Optional` 类。通过示例代码讲解了 `Optional` 的创建、使用及其 API,探讨了其在实际开发中的最佳实践与局限性,帮助开发者提升代码的健壮性与可读性。
144 0
Java 8 的 Optional:提高代码安全性与可读性
|
10月前
|
人工智能 Java
Java运算符中的隐式转换
本文介绍了 Java 运算符中的隐式类型转换规则,涵盖算数、逻辑、位、关系、赋值及其他运算符。重点分析了算数和位运算符在处理小于 int 位长的数据时会自动转换为 int 类型的特性,并通过代码示例说明可能引发的类型不匹配错误。逻辑、关系、赋值及其他运算符则不涉及类型转换。总结指出,部分运算符在计算时会将小位长数据隐式转为 int 类型,结果也为 int。
116 0
|
10月前
|
人工智能 Rust Java
Java中的算数、关系、逻辑、条件、赋值 五大运算符详解
本文介绍了Java中的运算符及其优先级,包括算数运算符(如+、-、*、/、%、++、--)、关系运算符(如&lt;、&gt;、==、!=)、逻辑运算符(如&&、||、!)、条件运算符(三目运算符)和赋值运算符(如=、+=、-=等)。详细解释了每种运算符的功能与用法,例如自增自减运算符的特点、逻辑运算符的短路法运算以及位运算符的操作规则。最后还提供了运算符优先级表格,帮助开发者理解复杂表达式的计算顺序。文中提醒,在实际开发中,建议使用括号明确运算顺序以提高代码可读性。
468 0
|
12月前
|
存储 Java API
Java Optional 完全指南:彻底告别 NullPointerException
Java 8 引入的 `Optional` 类旨在解决 `null` 带来的空指针异常问题,通过提供容器类显式处理可能为空的值,提升代码健壮性和可读性。本文从基础到进阶解析 `Optional` 的用法,涵盖创建、检查、获取值、处理值等核心功能,结合实际应用场景与最佳实践,助你彻底告别 `NullPointerException`,编写更优雅的 Java 代码。
643 0