Java 8 Optional 介绍

简介: Java 8 Optional 介绍

1. 前言

空指针确实会产生很多问题,我们经常遇到空的引用,然后又想从这个空的引用上去获取其他的值,接着理所当然的碰到了 NullPointException。这是你可能会想,这报错很好处理,然后你看了眼报错行数,对比了下代码。脑海里瞬间闪过 ” 对对对,这里有可能为空 “,然后加上 null check 轻松处理。然而你不知道这已经是你处理的第多少个空指针异常了。 为了解决上面的问题,在 Java SE8 中引入了一个新类 java.util.Optional,这个类可以缓解上面的问题。

你可能已经发现了,上面我用的是缓解而不是解决。这也是很多人理解不太对的地方,以为 Java SE8 中的 Optional 类可以解决空指针问题。其实 Optional 类的的使用只是提示你这里可能存在空值,需要特殊处理,并提供了一些特殊处理的方法。如果你把 Optional 类当作空指针的救命稻草而不加思考的使用,那么依旧会碰到错误。

2.Optional 创建

/**
 * 创建一个 Optional
 */
@Test
public void createOptionalTest() {
    // Optional 构造方式1 - of 传入的值不能为 null
    Optional<String> helloOption = Optional.of("hello");
    // Optional 构造方式2 - empty 一个空 optional
    Optional<String> emptyOptional = Optional.empty();
    // Optional 构造方式3 - ofNullable 支持传入 null 值的 optional
    Optional<String> nullOptional = Optional.ofNullable(null);
}

注:其中构造方式 1 中 of 方法,如果传入的值会空,会报出 NullPointerException 异常。

3ea7843234d2460a910b15fc3b0db494.png

3. Optional 判断

Optional 只是一个包装对象,想要判断里面有没有值可以使用 isPresent 方法检查其中是否有值

Optional<String> helloOptional = Optional.of("Hello");
        System.out.println(helloOptional.isPresent());
        Optional<Object> emptyOptional = Optional.empty();
        System.out.println(emptyOptional.isPresent());

得到的结果:

true
false

如果想要在有值的时候进行一下操作。可以使用 ifPresent 方法。

Optional<String> helloOptional = Optional.of("Hello");
    Optional<String> emptyOptional = Optional.empty();
    helloOptional.ifPresent(s -> System.out.println(s.length()));
    emptyOptional.ifPresent(s -> System.out.println(s.length()));

打印的结果:

5

4. Optional 获取值

使用 get 方法可以获取值,但是如果值不存在,会抛出 NoSuchElementException 异常。

Optional<String> stringOptional = Optional.of("hello");
    System.out.println(stringOptional.get());
    // 如果没有值,会抛异常
    Optional<String> name2 = Optional.ofNullable(null);
    System.out.println(name2.get());
    //报 错
    Optional<String> emptyOptional = Optional.empty();
    System.out.println(emptyOptional.get());
    //报错

得到的结果:

hello
java.util.NoSuchElementException: No value present
java.util.NoSuchElementException: No value present

5. Optional 默认值

使用 orElse, orElseGet 方法可以在没有值的情况下获取给定的默认值。

// 如果没有值,获取默认值
    Optional<String> emptyOptional = Optional.empty();
    String orElse = emptyOptional.orElse("orElse default");
    String orElseGet = emptyOptional.orElseGet(() -> "orElseGet default");
    System.out.println(orElse);
    System.out.println(orElseGet);

得到的值为:

orElse default
orElseGet default

看到这里你可能会有些疑惑了,这两个方法看起来效果是一模一样的,为什么会提供两个呢?下面再看一个例子,你会发现两者的区别。

/**
 * orElse 和 orElseGet 的区别
 */
@Test
public void orElseAndOrElseGetTest() {
    // 如果没有值,默认值
    Optional<String> emptyOptional = Optional.empty();
    System.out.println("空Optional.orElse");
    String orElse = emptyOptional.orElse(getDefault());
    System.out.println("空Optional.orElseGet");
    String orElseGet = emptyOptional.orElseGet(() -> getDefault());
    System.out.println("空Optional.orElse结果:"+orElse);
    System.out.println("空Optional.orElseGet结果:"+orElseGet);
    System.out.println("--------------------------------");
    // 如果没有值,默认值
    Optional<String> stringOptional = Optional.of("hello");
    System.out.println("有值Optional.orElse");
    orElse = stringOptional.orElse(getDefault());
    System.out.println("有值Optional.orElseGet");
    orElseGet = stringOptional.orElseGet(() -> getDefault());
    System.out.println("有值Optional.orElse结果:"+orElse);
    System.out.println("有值Optional.orElseGet结果:"+orElseGet);
}
public String getDefault() {
    System.out.println("   获取默认值中..run getDeafult method");
    return "hello";
}

得到的输出:

空Optional.orElse
   获取默认值中..run getDeafult method
空Optional.orElseGet
   获取默认值中..run getDeafult method
空Optional.orElse结果:hello
空Optional.orElseGet结果:hello
--------------------------------
有值Optional.orElse
   获取默认值中..run getDeafult method
有值Optional.orElseGet
有值Optional.orElse结果:hello
有值Optional.orElseGet结果:hello

在这个例子中会发现 orElseGet 传入的方法在有值的情况下并不会运行。而 orElse 却都会运行

6. Optional 异常

使用 orElseThrow 在没有值的时候抛出异常

/**
 * 如果没有值,抛出异常
 */
@Test
public void whenIsNullThrowExceTest() throws Exception {
    // 如果没有值,抛出异常
    Optional<String> emptyOptional = Optional.empty();
    String value = emptyOptional.orElseThrow(() -> new Exception("发现空值"));
    System.out.println(value);
}

得到的结果:

java.lang.Exception: 发现空值

7. Optional 函数接口

Optional 随 JDK8 一同出现,必然会有一些 JDK8 中的新特性,比如函数接口。Optional 中主要有三个传入函数接口的方法,分别是 filter,map,flatMap。这里面的实现其实是 JDK8 的另一个新特性了,因此这里只是简单演示,不做解释。

@Test
public void functionTest() {
    // filter 过滤
    Optional<Integer> optional123 = Optional.of(123);
    optional123.filter(num -> num == 123).ifPresent(num -> System.out.println(num));
    Optional<Integer> optional456 = Optional.of(456);
    optional456.filter(num -> num == 123).ifPresent(num -> System.out.println(num));
    // map 转换
    Optional<Integer> optional789 = Optional.of(789);
    optional789.map(String::valueOf).map(String::length).ifPresent(length -> System.out.println(length));
}

得到的结果:

123
3

8. Optional 总结

在本文中,我们看到了如何使用 Java SE8 的 java.util.Optional 类。Optional 类的目的不是为了替换代码中的每个空引用,而是为了帮助更好的设计程序,让使用者可以仅通过观察属性类型就可以知道会不会有空值。另外,Optional 不提供直接获取值的方法,使用时会强迫你处理不存在的情况。间接的让你的程序免受空指针的影响。


目录
相关文章
|
5天前
|
Java Unix 程序员
java 8 新特性讲解Optional类--Fork/Join 框架--新时间日期API--以及接口的新特性和注解
java 8 新特性讲解Optional类--Fork/Join 框架--新时间日期API--以及接口的新特性和注解
65 1
|
7月前
|
Java 程序员 API
Java8特性第三讲:如何使用Optional类优雅解决业务npe问题
Java8特性第三讲:如何使用Optional类优雅解决业务npe问题
|
3天前
|
自然语言处理 Java API
Java 8的Stream API和Optional类:概念与实战应用
【5月更文挑战第17天】Java 8引入了许多重要的新特性,其中Stream API和Optional类是最引人注目的两个。这些特性不仅简化了集合操作,还提供了更好的方式来处理可能为空的情况,从而提高了代码的健壮性和可读性。
26 7
|
5天前
|
安全 Java 开发者
Java一分钟之-Optional类:优雅处理null值
【5月更文挑战第13天】Java 8的`Optional`类旨在减少`NullPointerException`,提供优雅的空值处理。本文介绍`Optional`的基本用法、创建、常见操作,以及如何避免错误,如直接调用`get()`、误用`if (optional != null)`检查和过度使用`Optional`。正确使用`Optional`能提高代码可读性和健壮性,建议结合实际场景灵活应用。
22 3
|
5天前
|
Java 编译器 API
Java基础教程(17)-Java8中的lambda表达式和Stream、Optional
【4月更文挑战第17天】Lambda表达式是Java 8引入的函数式编程特性,允许函数作为参数或返回值。它有简洁的语法:`(parameters) -> expression 或 (parameters) ->{ statements; }`。FunctionalInterface注解用于标记单方法接口,可以用Lambda替换。
|
5天前
|
存储 Java API
java8新特性 lambda表达式、Stream、Optional
java8新特性 lambda表达式、Stream、Optional
|
5天前
|
Java
Java8 Optional
Java8 Optional
13 0
|
5天前
|
安全 Java 开发者
Java 8 `Optional` 类的用法和优势
【2月更文挑战第15天】
15 0
|
5天前
|
存储 Java
java8新特性-Optional
java8新特性-Optional
21 0
|
5天前
|
JSON 安全 Java
JAVA8实战 - Optional工具类
JAVA8实战 - Optional工具类
86 0