缘起
我们在写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对象构造方法
-
Optional.of(T value)
,该方法通过一个非null
的 value 来构造一个 Optional,返回的 Optional 包含了 value 这个值。对于该方法,传入的参数一定不能为 null,否则便会抛出NullPointerException
。 -
Optional.ofNullable(T value)
,该方法和 of 方法的区别在于,传入的参数可以为 null 。 -
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);
如此以来,我们的代码可读性和程序健壮性都有了提高。
延伸阅读
开源智能客服系统
春松客服是 Chatopera 自主研发的,Apache2.0开源协议授权的智能客服系统,企业可以免费使用。春松客服会不断增强客服系统的智能化,这包括利用自然语言处理、机器学习和语音识别等技术让客服工作更有效率、客服满意度更高、成本更低。
转载:https://blog.csdn.net/watson243671/article/details/106076935