详解Java8中Optional的常见用法

作者:look-word 时间:2022-04-30 14:32:21 

一、 简介

Opitonal是java8引入的一个新类,目的是为了解决空指针异常问题。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。

Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此。

二、Java8 之前,空指针异常判断

java在使用对象过程中,访问任何方法或属性都可能导致 NullPointerException:

比如:String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();

在这个小示例中,如果我们需要确保不触发异常,就得在访问每一个值之前对其进行明确地检查:

if (user != null) {
   Address address = user.getAddress();
}if (address != null) {
   Country country = address.getCountry();
}if (country != null) {
   String isocode = country.getIsocode();
}if (isocode != null) {
   isocode = isocode.toUpperCase();
}

为了简化这个过程,我们来看看用Optional类是怎么做的。

三、Optional的使用

1.创建Optional实例

重申一下,这个类型的对象可能包含值,也可能为空。你可以使用同名方法创建一个空的 Optional。

// 创建一个空的 Optional
       Optional<User> empty = Optional.empty();
       // 获取Optional的值
       empty.get();

毫不奇怪,尝试访问 emptyOpt 变量的值会导致 NoSuchElementException。

你可以使用 of() 和 ofNullable() 方法创建包含值的 Optional。两个方法的不同之处在于如果你把 null 值作为参数传递进去,of() 方法会抛出 NullPointerException:

User user = null;
Optional<User> user = Optional.of(user);

因此,你应该明确对象不为 null 的时候使用 of()。

如果对象即可能是 null 也可能是非 null,你就应该使用 ofNullable() 方法:

User user = null;
Optional<User> opt = Optional.ofNullable(null);

2.访问 Optional 对象的值

从 Optional 实例中取回实际值对象的方法之一是使用 get() 方法:

String name = "John";
Optional<String> opt = Optional.ofNullable(name);
assertEquals("John", opt.get());

不过,你看到了,这个方法会在值为 null的时候抛出异常。要避免异常,你可以选择首先验证是否有值:

方法返回值作用
Optional.isPresent()boolean当前对象为null 返回false 否则返回true
Optional.ifPresent(Consumer<? super T> action)void当前对象为null,啥都不做,否则执行函数式接口中的内容
User user = new User("湖南");
       Optional<User> opt = Optional.ofNullable(user);
       // opt 是否为Null
       System.out.println(opt.isPresent() ? "存在" : "不存在");
       // 不为null时执行的操作 这里也可以写成lambda方式
       opt.ifPresent(new Consumer<User>() {
           @Override
           public void accept(User user) {
System.out.println(user);
           }
       });

在我们的开发中,NullPointerException可谓是随时随处可见,为了避免空指针异常,我们常常需要进行 一

些防御式的检查,所以在代码中常常可见if(obj != null) 这样的判断。幸好在JDK1.8中,java为我们提供了

一个Optional类,Optional类能让我们省掉繁琐的非空的判断。下面先说一下Optional中为我们提供的方法。

接下来,我们来看看提供空值的方法。

3.返回默认值

方法返回值作用
Optional.orElse()User对象为空的时候返回默认值
Optional.orElseGet()User对象为空的时候返回函数式接口的返回值(需要我们定义)

分ptional类提供了API用以返回对象值,或者在对象为空的时候返回默认值:orElse(),

如果有值则返回该值,否则返回传递给它的参数值:

User user = null;
       User user1 = new User("湖南");
// 当user 为空时 返回orElse中的默认值
       User result = Optional.ofNullable(user).orElse(user1);
       System.out.println(result);
       // 执行结果
       User(address=湖南)

第二个同类型 Api 则有所不同,这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果:

也就是说,其返回的结果是由我们所创建的

User user = null;
       // 当user 为空时 返回orElseGet 函数式接口中定义的返回值
       User result = Optional.ofNullable(user).orElseGet(() -> new User("默认"));
       System.out.println(result);

下面我们来看一个示例,突出二者的区别:

注意: 这里的Optional不是空的哦

public static void main(String[] args) {
       User user = new User("湖南");
       User user1 = (User) Optional.ofNullable(user).orElse(createUser("orElse"));
       User result = Optional.ofNullable(user).orElseGet(() -> createUser("orElseGet"));
       System.out.println(result);
   }

private static User createUser(String str) {
       log.info("{} 创建的对象--", str);
       return new User("默认值");
   }
//  执行结果
[INFO ] 2022-09-12 13:40:30,987(0) --> [main] look.word.Optional.Demo2.createUser(Demo2.java:31): orElse 创建的对象--  
User(address=湖南)
User(address=湖南)

可以看到,这个示例中,两个 Optional 对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象。

在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响。

4.返回异常 (常用)

方法返回值作用
Optional.orElseThrow()void它会在对象为空的时候抛出异常,而不是返回备选的值:

除了 orElse() 和 orElseGet() 方法,Optional 还定义了 orElseThrow() API &mdash;&mdash; 它会在对象为空的时候抛出异常,而不是返回备选的值:

User result = Optional.ofNullable(user).orElseThrow( () -> new IllegalArgumentException());

这里,如果 user 值为 null,会抛出 IllegalArgumentException。

这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException

现在我们已经很好地理解了如何使用 Optional,我们来看看其它可以对 Optional 值进行转换和过滤的方法。

5.转换值

有很多种方法可以转换 Optional 的值。我们从 map() 和 flatMap() 方法开始。

先来看一个使用 map() API 的例子:

User user = new User("湖南");
       String address = Optional.ofNullable(user).map(u -> u.getAddress()).orElse("默认!");
       System.out.println(address.equals(user.getAddress())?"相同":"不相同");
// 执行结果  User user = new User(); 结果 为 不相同
// 相同

map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中。这就使对返回值进行链试调用的操作成为可能 &mdash;&mdash; 这里的下一环就是 orElse()。

相比这下,flatMap() 也需要函数作为参数,并对值调用这个函数,然后直接返回结果。

下面的操作中,我们给 User 类添加了一个方法,用来返回 Optional:

User user = new User();
       String address = Optional.ofNullable(user)
               .flatMap(u -> Optional.ofNullable(u.getAddress()))
               .orElse("默认!");
       System.out.println(address.equals(user.getAddress()) ? "相同" : "不相同");
// 执行结果  User user = new User(); 结果 为 不相同
// 相同

二者区别:

简单来说: 二者返回值类型不同

  • map()的返回值类型: 比如返回的是字符串 那么他的返回值类型就是字符串

  • flatMap()的返回值类型:则是用Optional包裹的,我们还可以对他进行一系列操作

6.过滤值

filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。

来看一个根据基本的电子邮箱验证来决定接受或拒绝 User(用户) 的示例:

User user = new User( "234");
       Optional<User> result = Optional.ofNullable(user)
               .filter(u -> u.getAddress() != null && u.getAddress().contains("1"));
       System.out.println(result);

来源:https://www.cnblogs.com/look-word/p/16687712.html

标签:Java,Optional
0
投稿

猜你喜欢

  • Java输入/输出流体系详解

    2023-03-01 06:37:00
  • Java语言一元运算符实例解析

    2023-01-14 15:31:22
  • IDEA全量替换一次性解决旧项目并将所有文件换行符改为LF问题

    2022-09-17 18:44:32
  • vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

    2021-06-16 04:05:47
  • JavaWeb利用struts实现文件下载时改变文件名称

    2023-10-24 11:26:53
  • java页面中文乱码的解决办法

    2022-09-01 22:59:20
  • Java动态数组Arraylist存放自定义数据类型方式

    2023-07-25 10:41:30
  • IDEA+JRebel实现全自动热部署的方法步骤

    2023-11-29 13:53:30
  • 用Java连接sqlserver数据库时候几个jar包的区别分析

    2021-11-07 02:18:01
  • Springboot内置的工具类之CollectionUtils示例讲解

    2023-08-23 20:47:13
  • springboot使用log4j2异步日志提升性能的实现方式

    2021-05-31 16:54:55
  • java8新特性教程之time包使用总结

    2023-02-08 03:58:19
  • Java面向接口编程之简单工厂模式示例

    2021-07-14 21:40:27
  • Flutter图片与文件选择器使用实例

    2023-07-17 09:11:12
  • SpringBoot中@ConfigurationProperties注解实现配置绑定的三种方法

    2023-03-19 12:36:25
  • Java 1.0和Java 1.1 的IO类的比较

    2023-10-07 10:48:39
  • java信号量控制线程打印顺序的示例分享

    2023-05-09 12:27:38
  • 如何基于JavaFX开发桌面程序

    2023-10-30 11:06:19
  • JDK1.8中的ConcurrentHashMap源码分析

    2023-11-27 06:02:32
  • C#语言主要语言区域

    2021-10-05 13:58:38
  • asp之家 软件编程 m.aspxhome.com