JAVA8之工具类Optional
一. 概述
Optional类并不像之前介绍的工具都是借口,他是一个被final修饰的具体的类,我们一般拿它做一些对空(null)的判定.基本提供的都是静态方法,可以之间用.方法名调用.先看其源码:
package java.util;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
public T orElse(T other) {
return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}
这么多方法是不是惊呆了.首先先从
构造方法讲起.
1. empty方法(私有)
没有入参,直接new出一个Optional实例返回.
2. of方法
接受一个传入类型构造一个包含传入值的Optional实例返回,该方法并没有对入参做非空判定,如果传入的参数是null的话,直接就会抛出异常,可用来阻挡null值的传入.
3. ofNullable方法
看名字就知道,在传入参数的时候,对入参做了非空判定,如果传入的参数是null的话,就会new出来一个新的Optional实例.如果不是null,则构造一个包含传入值的Optional实例返回.
下面讲解其他方法.
4. isPresent方法
没有入参,返回一个布尔值(boolean).判断调用方法的对象是否为空,为空则返回false,非空则返回true.如同object != null的返回结果.
5. get方法
如果Optional中有值,则返回该值,如果没有,则抛出NoSuchElementException的异常.
6. ifPresent方法
如果Optional中有值,则进行下面的操作,如果为空,则什么也不做.
7. orElse方法
接受一个传入类型,如果Optional中有值,则返回该值,如果为空,则返回默认值
8. orElseGet方法
接受一个Supplier类型的数据,如果Optional中有值,则返回该值,如果为空,则返回一个Supllier生成的一个数据.
9. orElseThrow方法
同第8个方法,只是在为空的时候,抛出一个由Supplier生成的指定异常.
10. filter方法
顾名思义,这是一个过滤方法.传入一个Predicate类型的参数,如果满足Predicate条件,则返回该Optional的值,反之则返回一个空的Optional对象.
11. map方法
如果Optional的值存在,则进行传入的Function接口的方法,并返回其方法结束后的值,并封装成一个Optional的对象,否则返回一个空的Optional对象.
12. flatMap方法
如同第11方法,但是其返回值必须是一个Optianal类型的对象.
二. 示例
方法较多,我们写几个常用示例,先创建一个用户实体类,有姓名和年龄参数,getter,setter方法,并重写了toString方法方便打印结果:
package com.yczuoxin.demo.optional;
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1. 传入一个对象,如果是空我们不做任何操作,如果不是空,就讲对象打印出来.
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<User> user = Optional.ofNullable(new User("张三",18));
Optional<User> empty = Optional.ofNullable(null);
user.ifPresent(existUser -> System.out.println(existUser));
}
}
测试成功,只打印出了非空的结果.注意,此处如果用of代替ofNullable的话会直接抛出异常.
2. 传入一个字符串,如果是空,则返回empty string, 如果不是空则返回其值.
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<String> str = Optional.ofNullable("string");
Optional<String> empty = Optional.ofNullable(null);
System.out.println(str.orElse("new string"));
System.out.println(empty.orElse("empty string"));
}
}
也可以使用另一个方法
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<String> str = Optional.ofNullable("string");
Optional<String> empty = Optional.ofNullable(null);
System.out.println(str.orElseGet(() -> new String("is empty")));
System.out.println(empty.orElseGet(() -> new String("is empty")));
}
}
测试成功.
3. 传入一个用户,如果用户存在,则获取用户的用户名,并将其用户名的字母全部大写输出.
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
User user = new User("zhangsan",18);
User empty = null;
System.out.println(Optional.ofNullable(user).map(user1 -> user1.getName()).map(name -> name.toUpperCase()));
System.out.println(Optional.ofNullable(empty).map(user1 -> user1.getName()).map(name -> name.toUpperCase()));
}
}
测试成功.可以看见,如果使用of方法,会报出空指针异常.
4. 年龄大于20的用户则输出其用户名.
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
User zhangsan = new User("zhangsan",18);
User lisi = new User("lisi",21);
Optional<String> zhangsanName = Optional.ofNullable(zhangsan).filter(user -> user.getAge() > 20)
.map(user -> user.getName());
System.out.println(zhangsanName);
Optional<String> lisiName = Optional.ofNullable(lisi).filter(user -> user.getAge() > 20)
.map(user -> user.getName());
System.out.println(lisiName);
}
}
测试成功.输出了年龄大于20的用户的姓名.
三. 总结
这个工具类被用作对空的判定.该工具类有几个使用限制:
1. 单纯使用isPresent方法和get方法跟我们之前的写法并没有什么减少代码书写的工作量,反而还增加了对Optional的封装.
2. Optional类没有实现Serializable的接口,所以不能被序列化,即不能作为类的属性或者方法入参.