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);
}
目的
- 语义化更强,减少if - else
- 避免NullPointerException异常