Java8 Optional用法

Jdk1.8 java.util包新增了Optional、OptionalInt、OptionalLong、OptionalDouble等容器对象,接下来我们来分析下这些对象出现的缘由和基本用法。这几个类使用方式都大同小异,我们只分析其中的一个Optional。我们来想象一个很常见的场景,根据ID获取一个对象,然后取出这个对象的其中一个属性值的一般写法。如下:

public class OptionalTest {
    public static void main(String[] args) {
        // 模拟从数据库中取数据
        Person person = new OptionalTest().getById(1);

        String name = null;
        // 判断对象是否为空,为了防止空指针异常,这儿必须有判断
        if (person != null) {// 当然也完全可以用三目表达式判断
            name = person.getName();
        }

        System.out.println(name);
    }

    /**
     * 这儿是模拟从数据库中取出的数据(因为重点不是学习如何从数据库中取数据的,也为了减少代码量)
     * @param id
     * @return
     */
    public Person getById(int id) {
        if (id == 1) {// 模拟数据库中id=1取不到值
            return null;
        } else {// 模拟数据库中id为其他值都能取到值
            Person person = new Person();
            person.setId(1);
            person.setName("zhangsan");
            return person;
        }
    }

    class Person {
        private int id;
        private String name;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

以上代码是完全没有任何问题的。如果这样的话,我们的代码里会有很多类似的判断,要想获取一个对象属性,先判断该对象是否为空的逻辑,那么有没有简单点的写法或者语义更加直接的写法呢?
现在我们看下Jdk1.8以后用Optional如何获取一个对象的属性。

    public static void main(String[] args) {
        // 模拟从数据库中取数据
        Person person = new OptionalTest().getById(1);

        // Optional写法
        String name = Optional.ofNullable(person).map(Person::getName).orElse(null);

        System.out.println(name);
    }

以上就是Optional的简单用法,不过发现也没有简单多少啊,看着还没有if - else可读性强呢。其实我们仔细分析一下,如果我们想获取指定对象属性的属性呢(eg: person->address.city 假设Person类有个Address属性),是不是还得写判断呢,并且呢这种写法的更加语句化,更加符合我们写文章的思维(行云流水).

Optional 用法

Optional 其实是一个对象容器,顾名思义就是存放对象的,但只能放一个对象。
以下Optional 空实例是指Optional容器中没有对象

Optional常见方法:
    a. 如何获取一个Optional对象(把对象放入Optional容器)
        1. of(T t) :返回一个Optional实例,但T对象不能为空
        2. ofNullable(T t): 返回一个Optional实例,T对象可以为空

    b. 对Optional 容器里对象进行操作的常用方法
        1. get():获取容器中的对象,如果对象为空会抛出异常
        2. orElse():获取容器中的对象,可以为空
        3. isPresent():Optional容器对象里的值是否为空
        4. ifPresent(Consumer consumer):如果Optional容器里的对象不为空,则调用consumer对象的accept方法
        5. map(Function<? super T, ? extends U> mapper): 生成一个新的Optional容器,容器里对象的值就是mapper.apply方法的返回值
        6. filter(Predicate<? super T> predicate):对Optional容器里的对象过滤,如果predicate.test返回true,返回当前的Optional实例,否则返回一个空的Optional实例(Optional容器中没有对象)

现在我们对Optional有了基本的了解,那我们就通过示例来看看具体用法

示例

public static void main(String[] args) {
        // 模拟从数据库中取数据
        Person person = new OptionalTest().getById(1);

        // 获取一个Optional实例(容器里对象是person),如果person为空,则抛出NullPointerException
        Optional<Person> optional1 = Optional.of(person);

        // 获取一个Optional实例(容器里对象是person),person允许为空
        Optional<Person> optional2 = Optional.ofNullable(person);

        // 获取Optional容器里的对象,如果为空抛出NoSuchElementException
        Person person1 = optional1.get();
        // 获取Optional容器里的对象,如果为空则返回orElse里的值
        Person person2 = optional2.orElse(null);

        // 当前Optional容器里对象是否为空
        boolean flag = optional1.isPresent();

        // 对Optional容器里对象进行处理(简单处理了下,把名字小写转换成大写)
        optional1.ifPresent((r) -> {
            r.setName(r.getName().toUpperCase());
        });
        
        // 通过map方法获取一个新的Optional实例,然后返回新Optional容器里对象的值
        String name = optional2.map((r) -> r.getName()).orElse(null);

        // 对Optional容器里的对象过滤,如果满足条件,返回当前Optional对象,否则返回一个空Optional对象
        Optional<Person> optional3 = optional2.filter((r) -> r.getId() == 1);

}

目的

  1. 语义化更强,减少if - else
  2. 避免NullPointerException异常
原文地址:https://www.cnblogs.com/rookie-test/p/12634751.html