Java 8 新特性,Optional介绍 | 春松客服

缘起

我们在写Java代码时,最长遇到的异常就是:NullPointerException。大量的null值的检测,降低了代码的可读性,而随时可能发生的NullPointerException降低了程序的健壮性。在Java 8中引入了Optional类,就是为了解决这样的问题,那么Optional怎么用?

在春松客服 v5中,我们大量的使用Optional类,对于学习春松客服代码的人会带来学习上的负担,本文是为了帮助大家快速学习而作,同时关注延伸阅读内容,您将快速掌握Optional使用。

Optional类

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

Optional对象可以包含或者不包含非 null 值的容器。如果值存在则 isPresent()方法会返回 true,调用 get() 方法会返回该对象。

Optional对象构造方法

  1. Optional.of(T value),该方法通过一个非 null 的 value 来构造一个 Optional,返回的 Optional 包含了 value 这个值。对于该方法,传入的参数一定不能为 null,否则便会抛出 NullPointerException

  2. Optional.ofNullable(T value),该方法和 of 方法的区别在于,传入的参数可以为 null 。

  3. Optional.empty(),该方法用来构造一个空的 Optional,即该 Optional 中不包含值 —— 其实底层实现还是 如果 Optional 中的 value 为 null 则该 Optional 为不包含值的状态,然后在 API 层面将 Optional 表现的不能包含 null 值,使得 Optional 只存在 包含值 和 不包含值 两种状态。

提取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);

使用orElse()方法获取值

Optional类还包含其他方法用于获取值,这些方法分别为:

  • orElse():如果有值就返回,否则返回一个给定的值作为默认值;
  • orElseGet():与orElse()方法作用类似,区别在于生成默认值的方式不同。该方法接受一个Supplier<? extends T>函数式接口参数,用于生成默认值;
  • orElseThrow():与前面介绍的get()方法类似,当值为null时调用这两个方法都会抛出NullPointerException异常,区别在于该方法可以指定抛出的异常类型。

下面来看看这三个方法的具体用法:

String str = "Hello World";
Optional<String> strOpt = Optional.of(str);
String orElseResult = strOpt.orElse("Hello Shanghai");
String orElseGet = strOpt.orElseGet(() -> "Hello Shanghai");
String orElseThrow = strOpt.orElseThrow(
        () -> new IllegalArgumentException("Argument 'str' cannot be null or blank."));

此外,Optional类还提供了一个ifPresent()方法,该方法接收一个Consumer<? super T>函数式接口,一般用于将信息打印到控制台:

Optional<String> strOpt = Optional.of("Hello World");
strOpt.ifPresent(System.out::println);

使用filter()方法过滤

filter()方法可用于判断Optional对象是否满足给定条件,一般用于条件过滤:

Optional<String> optional = Optional.of("lw900925@163.com");
optional = optional.filter(str -> str.contains("164"));

在上面的代码中,如果filter()方法中的Lambda表达式成立,filter()方法会返回当前Optional对象值,否则,返回一个值为空的Optional对象。

示例程序

package getstarted.features.optional;

import junit.framework.TestCase;

import java.util.Optional;

public class OptionalTestcase extends TestCase {

    public class Name {
        private String name;

        public Name(final String name) {
            this.name = name;
        }

        public Optional<String> getName() {
            return Optional.ofNullable(name);
        }

    }


    public class Person {
        private Name name;
        private int age;
        private String password;

        public Optional<Name> getName() {
            return Optional.ofNullable(name);
        }

        public Optional<Integer> getAge() {
            return Optional.ofNullable(age);
        }

        public Optional<String> getPassword() {
            return Optional.ofNullable(password);
        }

        // normal constructors and setters

        Person(final String name, final int age) {
            this.name = new Name(name);
            this.age = age;
        }
    }

    public void testIfPresent() {
        Optional<String> opt = Optional.of("baeldung");
        opt.ifPresent(System.out::println);
    }


    public void testFlatMap() {
        Person person = new Person("john", 26);
        Optional<Person> personOptional = Optional.of(person);

        String name = personOptional
                .flatMap(Person::getName)
                .flatMap(Name::getName)
                .orElse("");
        assertEquals("john", name);

    }

}

注意事项

使用场景

So, there are solutions to avoid using Optionals as method parameters. The intent of Java when releasing Optional was to use it as a return type, thus indicating that a method could return an empty value. As a matter of fact, the practice of using Optional as a method parameter is even discouraged by some code inspectors.

简而言之,使用Optional对象作为函数的返回值,而不要使用它作为函数的参数。

orElseGet 和 orElse的区别

orElseGet中的函数并不是每次都执行,只有Optional包含的对象是null时执行,而使用 orElse则其中的代码每次都执行。

  • 不好的代码
AgentUser agentUser = agentUserRes.findOne(xxx).orElse(new AgentUser());
  • 更好的代码
AgentUser agentUser = agentUserRes.findOne(xxx).orElseGet(() -> (new AgentUser()));

所以,在使用时,应优先采用 orElseGet。

JPA Data 返回 Optional

Spring Boot中使用Spring Data JPA, 是可以直接用Optional 类型返回的,比如 AgentStatusRepository.java

 @Query(value = "SELECT * FROM uk_agentstatus WHERE agentno = ?1 AND orgi = ?2 ORDER BY createtime DESC LIMIT 1", nativeQuery = true)
    Optional<AgentStatus> findOneByAgentnoAndOrgi(final String agentid, final String orgi);

如此以来,我们的代码可读性和程序健壮性都有了提高。

延伸阅读

Guide To Java 8 Optional

Java 8新特性(三):Optional类

Java8(5):使用 Optional 处理 null

开源智能客服系统

春松客服是 Chatopera 自主研发的,Apache2.0开源协议授权的智能客服系统,企业可以免费使用。春松客服会不断增强客服系统的智能化,这包括利用自然语言处理、机器学习和语音识别等技术让客服工作更有效率、客服满意度更高、成本更低。

开源力量 社区共建

实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值