java8中Optional类的使用

一、简述

Optional类是java8中引入的一个非常有用的类,主要用处是解决编程中的空指针异常,本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。

二、场景

在java8之前,任何访问对象方法或属性的调用都有可能导致空指针异常,例如:


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();
            }
        }
    }
}

这样看起来太繁琐了,而且看起来很low,那么如何才能简洁的实现以上判断呢?

三、Optional容器类的常用方法


Optional.of(T t):创建一个Optional实例
Optional.empty():创建一个空的Optional实例
Optional.ofNullable(T t):若t不为null,创建Optional实列,否则创建空实例
isPresent():判断是否包含值
orElse(T t):如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值
map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
flatMap(Function mapper):与map类似,要求返回值必须是Optional

1.创建Optional实例

使用empty()创建空实例


Optional<User> emptyOpt = Optional.empty();

尝试访问emptyOpt变量的值会导致NoSuchElementException

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


Optional<User> opt1 = Optional.of(user);
Optional<User> opt1 = Optional.ofNullable(user);

2.访问Optional对象的值

使用get()方法获取Optional的值


Optional<User> opt1 = Optional.of(user);
User tmp = opt1.get();

3.返回默认值

orElse()方法可以在创建实例时就指定返回的默认值


User user = null;
User user2 = new User("[email protected]", "1234");
User result = Optional.ofNullable(user).orElse(user2);

因为user是空,所以此时我们想获取result的值的话会得到user2

我们也可以使用orElseGet(),如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果


User result = Optional.ofNullable(user).orElseGet( () -> user2);

不同的是使用orElse的话无论创建的值是否为空,都会orElse里的代码,如果里面有创建新的实例,这会对性能产生很大影响

另外我们可以使用orElseThrow(),它会在对象为空的时候抛出异常,而不是返回备选的值


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

此时如果user为空,会抛出我们定义的异常IllegalArgumentException

4.转换值

我们可以使用map方法,将 Optional里的元素进行转换


User user = new User("[email protected]", "1234");
String email = Optional.ofNullable(user)
        .map(u -> u.getEmail()).orElse("[email protected]");
        

注意无论是user为null,还是user里的Email为空,都会触发返回orElse里的默认值,这也就Optional的map操作的链式调用的精髓,我们可以不断的接着写map,无需一次次地判断是否为空

5.过滤值

filter()接受一个Predicate参数,返回测试结果为 true 的值

用法和stream的filter一模一样,例如我们可以检查用户的邮箱是否带@


User user = new User("[email protected]", "1234");
Optional<User> result = Optional.ofNullable(user)
        .filter(u -> u.getEmail() != null && u.getEmail().contains("@"));
        

6.对原来if的改进

对于User类我们对其进行重构,使其getter方法返回Optional类


public class User {
    
    
    private Address address;

    public Optional<Address> getAddress() {
    
    
        return Optional.ofNullable(address);
    }

    // ...
}
public class Address {
    
    
    private Country country;

    public Optional<Country> getCountry() {
    
    
        return Optional.ofNullable(country);
    }

    // ...
}

之前冗杂的if判断我们就可以改成这样:


String result = Optional.ofNullable(user)
        .flatMap(u -> u.getAddress())
        .flatMap(a -> a.getCountry())
        .map(c -> c.getIsocode())
        .orElse("default");
        

也可以简写成这样:


String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");
  

四、代码示例

 public static void main(String[] args) {
    
    
        test1();

    }

    //1、Optional.of(T t):创建一个Optional实例
    public static void test1() {
    
    
        Optional<User> op = Optional.of(new User());
        User emp = op.get();
        System.out.println(emp);
    }
运行结果:
User{
    
    id=null, name='null', sex='null', age=null, createDt='null', updateDt='null'}
 //2、Optional.empty():创建一个空的Optional实例
    public static void test2() {
    
    
        Optional<User> op = Optional.empty();
        System.out.println(op.get());
    }
运行结果:
Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at org.sang.test.OptionalDemo.test2(OptionalDemo.java:28)
	at org.sang.test.OptionalDemo.main(OptionalDemo.java:14)

语法说明
标题文本样式列表图片链接目录代码片表格注脚注释自定义列表LaTeX 数学公式插入甘特图插入UML图插入Mermaid流程图插入Flowchart流程图插入类图快捷键
代码片复制

下面展示一些 内联代码片

// A code block
var foo = 'bar';
 //3、Optional.ofNullable(T t):若t不为null,创建Optional实列,否则创建空实例
    public static void test3() {
    
    
        Optional<User> op = Optional.ofNullable(null); //不能传null
        if (op.isPresent()) {
    
    
            System.out.println(op.get());
//            System.out.println(op1.get());
        }
        System.out.println("-------------------------------------------------------");
        User emp = op.orElse(new User(1,"zhangsan", "man",18));
        System.out.println(emp);
        System.out.println("-------------------------------------------------------");
        User emp1 = op.orElseGet(() -> new User());
        System.out.println(emp1);

    }
运行结果:
User{
    
    id=1, name='zhangsan', sex='man', age=18, createDt='null', updateDt='null'}
-------------------------------------------------------
User{
    
    id=null, name='null', sex='null', age=null, createDt='null', updateDt='null'}
 public static void test4() {
    
    
        Optional<User> op = Optional.ofNullable(new User(1,"zhangsan", "man",18));
//        Optional<String> s = op.map((e) -> e.getName());
//        System.out.println(s.get());
        //多一步判空
        Optional<String> s = op.flatMap((e) -> Optional.of(e.getName()));
        System.out.println(s.get());

    }
运行结果:
zhangsan

猜你喜欢

转载自blog.csdn.net/m0_37899908/article/details/131055658