Optional 详细用法

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() 等这样的方法.

  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java中的Optional是一个容器类,用于表示一个值可能存在或不存在的情况。它可以用来解决空指针异常的问题,并提供了一些便捷的方法来处理值的存在与否。 使用Optional的主要步骤是: 1. 创建Optional对象:可以使用of()、ofNullable()或empty()方法来创建Optional对象。 - of()方法用于创建一个非空的Optional对象,如果传入的值为null,则会抛出NullPointerException。 - ofNullable()方法用于创建一个Optional对象,传入的值可以是null。 - empty()方法用于创建一个空的Optional对象。 下面是使用示例: ```java Optional<String> optional1 = Optional.of("Hello"); Optional<String> optional2 = Optional.ofNullable(null); Optional<String> optional3 = Optional.empty(); ``` 2. 判断值的存在与否:可以使用isPresent()方法来判断Optional对象中是否存在值。 ```java if (optional1.isPresent()) { System.out.println(optional1.get()); // 输出:Hello } ``` 3. 获取值:可以使用get()方法来获取Optional对象中的值,前提是该值存在,否则会抛出NoSuchElementException异常。为了避免异常,也可以使用orElse()或orElseGet()方法提供默认值。 - orElse()方法在Optional对象中存在值时返回该值,否则返回传入的默认值。 - orElseGet()方法在Optional对象中存在值时返回该值,否则通过传入的Supplier函数生成默认值。 ```java String value1 = optional1.orElse("Default Value"); // 返回Hello String value2 = optional2.orElseGet(() -> "Default Value"); // 返回Default Value ``` 4. 执行操作:可以使用ifPresent()方法来在Optional对象中存在值时执行特定的操作。 ```java optional1.ifPresent(val -> System.out.println("Value: " + val)); // 输出:Value: Hello ``` 除了上述方法,Optional还提供了一系列用于转换、过滤和映射值的方法,如map()、flatMap()、filter()等,可以根据具体的需求使用。 总结:Optional类提供了一种优雅的方式来处理可能为空的值,避免了空指针异常,并提供了一些便捷的方法来处理和操作值的存在与否。 希望这个说明和示例能帮助到你。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值