Java基础知识11--Optional类

1.Optional概念

java.util.Optional<T>类是一个封装了Optional值的容器对象,Optional值可以为null,如果值存在,调用isPresent()方法返回true,调用get()方法可以获取值。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 类的引入很好的解决空指针异常。

以下是 java.util.Optional<T> 类的声明:

public final class Optional<T> extends Object

2.为什么要使用Optional

目的:避免使用null检查

作为Java开发人员,几乎所有人都遇到过NullPointerException异常,大多数人遇到NullPointerException异常时都会在异常出现的地方加上if代码块来判断值不为空,比如下面的代码:

public void bindUserToRole(User user) {
    if (user == null) {
        return;
    }

    String roleId = user.getRoleId();
    if (roleId == null) {
        return;
    }

    Role = roleDao.findOne(roleId);
    if (role != null) {
        role.setUserId(user.getUserId());
        roleDao.save(role);
    }
}

方法内有三个不同的返回点,出错后调试也不容易,你都不知道是那个值导致了NullPointerException异常。

基于上面的原因,Java 8中引入了一个新的类Optional,用以避免使用null值引发的种种问题。

Optional<String> roleOpt = Optional.ofNullable(user).map(User::getRoleId);
if(roleOpt.isPresent()){
    ....
}

3.创建Optional对象

 Optional类提供类三个方法用于实例化一个Optional对象,它们分别为empty()of()ofNullable(),这三个方法都是静态方法,可以直接调用。

(1)empty()方法

empty()方法用于创建一个没有值的Optional对象:

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

empty()方法创建的对象没有值,如果对emptyOpt变量调用isPresent()方法会返回false,调用get()方法抛出NullPointerException异常。

(2)of()方法

of()方法使用一个非空的值创建Optional对象:

String str = "Hello World";
Optional<String> notNullOpt = Optional.of(str);

(3)ofNullable()方法

ofNullable()方法接收一个可以为null的值:

Optional<String> nullableOpt = Optional.ofNullable(str);

如果str的值为null,得到的nullableOpt是一个没有值的Optional对象。

若是集合类型:

Optional<List<Student>> studentList1 = Optional.ofNullable(studentList);

(4)of()ofNullable()方法辨析

当你很确定一个对象不可能为null的时候,应该使用of()方法,否则,尽可能使用ofNullable()方法,比如:

public static void method(Role role) {
    // 当Optional的值通过常量获得或者通过关键字new初始化,可以直接使用of()方法
    Optional<String> strOpt = Optional.of("Hello World");
    Optional<User> userOpt = Optional.of(new User());

    // 方法参数中role值不确定是否为null,使用ofNullable()方法创建
    Optional<Role> roleOpt = Optional.ofNullable(role);
}

4.map()方法提取Optional对象中的值

如果我们要获取User对象中的roleId属性值,常见的方式是直接获取:

String roleId = null;
if (user != null) {
    roleId = user.getRoleId();
}

使用Optional中提供的map()方法可以以更简单的方式实现:

Optional<User> userOpt = Optional.ofNullable(user);
Optional<String> roleIdOpt = userOpt.map(User::getRoleId);
List<String> paramNameList = Optional.ofNullable(ruleProcessParaList).orElse(new ArrayList<>()).stream().map(PmRuleProcessPara::getAttrCode).collect(Collectors.toList());

map()方法与Stream API中的map()一样,类似于映射操作,将原始类型映射为一个新的类型。

5.使用orElse()方法获取值

源码:

public T orElse(T var1) {
        return this.value != null ? this.value : var1;
    }

orElse():如果有值就返回T,否则返回一个给定的值作为默认值;

案例1:

return str != null ? str : "Hello World"

上面的代码表示判断字符串str是否为空,不为空就返回,否则,返回一个常量。使用Optional类可以表示为:

return strOpt.orElse("Hello World")

案例2:

public class OptionalTest {
    public static void main(String[] args) {
        List<Student> studentList=new ArrayList<>();
        Student student1=new Student();
        student1.setAge(10);
        student1.setName("lucky");
        Student student2=new Student();
        student2.setAge(12);
        student2.setName("linda");
        studentList.add(student1);
        studentList.add(student2);
        Optional<List<Student>> studentList1 = Optional.ofNullable(studentList);
        List<Student> studentList2 = Optional.ofNullable(studentList).orElse(new ArrayList<>());
        
        List<Integer> collect = Optional.ofNullable(studentList).orElse(new ArrayList<>()).stream().map(Student::getAge).collect(Collectors.toList());
        System.out.println("hello");

    }
}

debug截图:

6.ifPresent()方法

如果值存在则使用该值调用 consumer , 否则不做任何事情。示例如下

    public void ifPresent(Consumer<? super T> var1) {
        if (this.value != null) {
            var1.accept(this.value);
        }

    }

代码实例:

Optional<String> optional=Optional.ofNullable("zh");
optional.ifPresent(s1 -> System.out.println(s1));

典型应用1:将map转为字符串str

    public static void main(String[] args) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("key1", "One");
        paramsMap.put("key2", "Two");
        StringBuffer sb=new StringBuffer();
        Optional.ofNullable(paramsMap.entrySet()).ifPresent(paramSet->{
            paramSet.forEach((entry)->{
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            });
        });
        System.out.println(sb);
    }
}

debug断点:

控制台输出:

key1=One&key2=Two&

典型应用2:

public class OptionalTest {
    public static void main(String[] args) {
        List<Person> personList=new ArrayList<>();
        Person person1=new Person();
        person1.setName("lucky");
        person1.setAge(27);

        Person person2=new Person();
        person2.setName("linda");
        person2.setAge(25);

        personList.add(person1);
        personList.add(person2);
        Optional.ofNullable(personList).ifPresent(persons->{
             persons.forEach(person->{
                 person.setName("tom");
             });
        });
        System.out.println(personList);
    }
}

控制台输出:

[Person(name=tom, age=27), Person(name=tom, age=25)]

debug发现:personList地址与persons地址一致

源码执行逻辑分析:

public final class Optional<T> {
    private static final Optional<?> EMPTY = new Optional();
    private final T value;

    private Optional() {
        this.value = null;
    }private Optional(T var1) {
        this.value = Objects.requireNonNull(var1);
    }

    public static <T> Optional<T> of(T var0) {
        return new Optional(var0);
    }

    public static <T> Optional<T> ofNullable(T var0) {
        return var0 == null ? empty() : of(var0);
    }public boolean isPresent() {
        return this.value != null;
    }

    public void ifPresent(Consumer<? super T> var1) {
        if (this.value != null) {
            var1.accept(this.value);
        }

    }
    ......
}

阅读源码可见,ofNullable方法里调用了of方法,of方法里调用了构造方法。

ifPresent方法里调用了Consumer类里的accept方法

参考文献:https://lw900925.github.io/java/java8-optional.html

posted @ 2021-09-14 19:52  雨后观山色  阅读(1573)  评论(0编辑  收藏  举报