1:Optional 是一个对象容器,具有以下两个特点

  • 提示用户要注意该对象有可能为null

  • 简化if else代码

Optional.empty(): 创建一个空的 Optional 实例

Optional.of(T t):创建一个 Optional 实例,当 t为null时抛出异常

//调用工厂方法创建Optional实例
Optional<String> name = Optional.of("Sanaulla");
//控制台打印输出Sanaulla
System.out.println(name.get());
//传入参数为null,抛出NullPointerException.
Optional<String> someNull = Optional.of(null);

Optional.ofNullable(T t):创建一个 Optional 实例,但当 t为null时不会抛出异常,而是返回一个空的实例

//ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况,如果指定的值为null,则返回一个空的Optional
//下面创建了一个不包含任何值的Optional实例
//例如,值为'null'
Optional empty = Optional.ofNullable(null);
//通过isPresent()方法返回false为空,true非空
if (empty.isPresent()) {
	System.out.println(empty.get());
} else {
	System.out.println("值为空");
}

2. 获取:

get():获取optional实例中的对象,当optional 容器为空时报错

3. 判断:

  • isPresent():判断optional是否为空,如果空则返回false,否则返回true
//isPresent方法用来检查Optional实例中是否包含值
if (name.isPresent()) {
  //在Optional实例内调用get()返回已存在的值
  System.out.println(name.get());//输出Sanaulla
}
  • ifPresent(Consumer c):如果optional不为空,则将optional中的对象传给Comsumer函数
//ifPresent方法接受lambda表达式作为参数。
//lambda表达式对Optional的值调用consumer进行处理。
		Optional<String> optional = Optional.of("Hello");
        optional.ifPresent(s -> {
            s = s + "world";
           //打印Helloworld
            System.out.println(s);
        });
        //打印Hello
        System.out.println(optional.get());
//通过ifPresent修改的值,再次通过get获取的时候不会改变
  • 设置(获取)默认值,有时候,我们在创建(获取) Optional 对象的时候,需要一个默认值,orElse() 和 orElseGet() 方法就派上用场了(类似三目运算符)
  • orElse() 方法用于返回包裹在 Optional 对象中的值,如果该值不为 null,则返回;否则返回默认值。该方法的参数类型和值得类型一致(类似三目运算符)
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("沉默王二");
System.out.println(name); // 输出:沉默王二
String nullName = "小王";
String name = Optional.ofNullable(nullName).orElse("沉默王二");
System.out.println(name); // 输出:小王
  • orElseGet() 方法与 orElse() 方法类似,但参数类型不同。如果 Optional 对象中的值为 null,则执行参数中的函数
String nullName = null;
String name = Optional.ofNullable(nullName).orElseGet(()->"沉默王二");
System.out.println(name); // 输出:沉默王二
  • 从输出结果以及代码的形式上来看,这两个方法极其相似,这不免引起我们的怀疑,Java 类库的设计者有必要这样做吗?
  • 假设现在有这样一个获取默认值的方法,很传统的方式
public static String getDefaultValue() {
    System.out.println("getDefaultValue");
    return "沉默王二";
}
  • 然后,通过 orElse() 方法和 orElseGet() 方法分别调用 getDefaultValue() 方法返回默认值
public static void main(String[] args) {
    String name = null;
    System.out.println("orElse");
    String name2 = Optional.ofNullable(name).orElse(getDefaultValue());

    System.out.println("orElseGet");
    String name3 = Optional.ofNullable(name).orElseGet(Demo::getDefaultValue);
}
  • 注:类名 :: 方法名是 Java 8 引入的语法,方法名后面是没有 () 的,表明该方法并不一定会被调用
  • 输出结果如下所示:
orElse
getDefaultValue

orElseGet
getDefaultValue

- 输出结果是相似的,没什么太大的不同,这是在 Optional 对象的值为 null 的情况下。假如 Optional 对象的值不为 null 呢?

public static void main(String[] args) {
    String name = "沉默王三";
    System.out.println("orElse");
    String name2 = Optional.ofNullable(name).orElse(getDefaultValue());

    System.out.println("orElseGet");
    String name3 = Optional.ofNullable(name).orElseGet(OrElseOptionalDemo::getDefaultValue);
}
  • 输出结果如下所示:
orElse
getDefaultValue
orElseGet
  • orElseGet() 没有去调用 getDefaultValue()。orElseGet方法的性能更佳
  • orElseGet() 直观从语义上来看,get() 方法才是最正宗的获取 Optional 对象值的方法,但很遗憾,该方法是有缺陷的,因为假如 Optional 对象的值为 null,该方法会抛出 NoSuchElementException 异常。这完全与我们使用 Optional 类的初衷相悖
public class GetOptionalDemo {
    public static void main(String[] args) {
        String name = null;
        Optional<String> optOrNull = Optional.ofNullable(name);
        System.out.println(optOrNull.get());
    }
}
  • 这段程序在运行时会抛出异常:
Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.get(Optional.java:141)
	at com.cmower.dzone.optional.GetOptionalDemo.main(GetOptionalDemo.java:9)
  • 尽管抛出的异常是 NoSuchElementException 而不是 NPE,但在我们看来,显然是在“五十步笑百步”。建议 orElseGet() 方法获取 Optional 对象的值
  • orElse(T other):如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个默认值
//如果值不为null,orElse方法返回Optional实例的值。
//如果为null,返回传入的消息。
//输出:There is no value present!
System.out.println(empty.orElse("There is no value present!"));
//输出:Sanaulla
System.out.println(name.orElse("There is some value!"));
  • orElseGet(Supplier other):如果optional不为空,则返回optional中的对象;如果为null,则使用Supplier函数生成默认值other

  • orElseThrow(Supplier exception):如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常

4. 过滤:

filter(Predicate p):如果optional不为空,则执行断言函数p,如果p的结果为true,则返回原本的optional,否则返回空的optional

//filter方法检查给定的Option值是否满足某些条件。
//如果满足则返回同一个Option实例,否则返回空Optional。
Optional<String> longName = name.filter((value) -> value.length() > 6);
System.out.println(longName.orElse("The name is less than 6 characters"));//输出Sanaulla

//另一个例子是Optional值不满足filter指定的条件。
Optional<String> anotherName = Optional.of("Sana");
Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
//输出:name长度不足6字符
System.out.println(shortName.orElse("The name is less than 6 characters"));

5. 映射:

  • map(Function<T, U> mapper):如果optional不为空,则将optional中的对象 t 映射成另外一个对象 u,并将 u 存放到一个新的optional容器中。
//map方法执行传入的lambda表达式参数对Optional实例的值进行修改。
//为lambda表达式的返回值创建新的Optional实例作为map方法的返回值。
Optional<String> upperName = name.map((value) -> value.toUpperCase());
System.out.println(upperName.orElse("No value found"));
  • flatMap(Function< T,Optional< U >> mapper):跟上面一样,在optional不为空的情况下,将对象t映射成另外一个optional

  • 区别:map会自动将u放到optional中,而flatMap则需要手动给u创建一个optional

//flatMap与map(Function)非常类似,区别在于传入方法的lambda表达式的返回类型。
//map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional。 
//但flatMap方法中的lambda表达式返回值必须是Optionl实例。 
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));//输出SANAULLA

6:实例演示- Optional 的三种构造方式: Optional.of(obj), Optional.ofNullable(obj) 和明确的 Optional.empty(),生成user

  • 存在即返回, 无则提供默认值
Optional<String> optional = Optional.of("Hello");
//打印Hello
System.out.println(user.orElse(null);  

//而不是 
return user.isPresent() ? user.get() : null;


  • 存在即返回, 无则由函数来产生
return user.orElseGet(() -> fetchAUserFromDatabase()); 

//而不要 
return user.isPresent() ? user: fetchAUserFromDatabase();

  • 存在才对它做点什么
user.ifPresent(System.out::println);

//而不要下边那样
if (user.isPresent()) {
  System.out.println(user.get());
}


  • map 函数隆重登场
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())

//上面避免了我们类似 Java 8 之前的做法
if(user.isPresent()) {
  return user.get().getOrders();
} else {
  return Collections.emptyList();
}

使用 Optional 时尽量不直接调用 Optional.get() 方法, Optional.isPresent() 更应该被视为一个私有方法, 应依赖于其他像 Optional.orElse(), Optional.orElseGet(), Optional.map() 等这样的方法.

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐