Java8新特性之Optional类

时间:2022-07-22
本文章向大家介绍Java8新特性之Optional类,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

从 Java 8 引入的一个很有趣的特性是 Optional 类。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都非常了解的异常。

简单的示例

我们从一个简单的用例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致 NullPointerException:

String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();

在这个小示例中,如果我们需要确保不触发异常,就得在访问每一个值之前对其进行明确地检查:

if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}

你看到了,这很容易就变得冗长,难以维护。

学习 Optional 类

位置:package java.util; 类名:Optional

public final class Optional<T> {
    /**
     * 创建出一个Optional容器,容器里面没有装载着对象
     */
    private static final Optional<?> EMPTY = new Optional<>();

    /**
     * 容器中的对象
     */
    private final T value;

    /**
     * 私有的构造方法
     */
    private Optional() {
        this.value = null;
    }

    /**
     * 得到一个Optional容器,Optional没有装载着对象
     */
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

    /**
     * 私有构造方法(带参数),参数就是具体的要装载的对象,如果传进来的对象为null,则抛出异常
     */
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 创建出Optional容器,并将对象(value)装载到Optional容器中
     *
     * 传入的value如果为null,则抛出异常(调用的是Optional(T value)方法)
     */
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    /**
     * 创建出Optional容器,并将对象(value)装载到Optional容器中
     *
     * 传入的value可以为null,如果为null,返回一个没有装载对象的Optional对象
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    /**
     * 得到容器中的对象,如果为null就抛出异常
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

    /**
     * 判断容器中的对象是否为null
     */
    public boolean isPresent() {
        return value != null;
    }

    /**
     * 如果存在某个值,则使用该值调用指定的使用者,否则不执行任何操作
	 * 该方法除了执行检查,还接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

    /**
     * 如果容器中的对象存在,并且符合过滤条件,返回装载对象的Optional容器,否则返回一个空的Optional容器
     */
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

    /**
     * 如果容器的对象存在,则对其执行调用mapping函数得到返回值。然后创建包含mapping返回值的Optional,否则返回空Optional
     */
    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));
        }
    }

    /**
     * flatMap方法与map方法类似,区别在于apply函数的返回值不同。map方法的apply函数返回值是 ? extends U,而flatMap方法的apply函数返回值必须是Optional
     */
    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;
    }

    /**
     * 如果对象存在,则直接返回,否则返回由Supplier(供应者) 函数式接口的实现用来生成默认值
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

    /**
     * 如果存在,则返回。否则抛出Supplier(供应者) 函数式接口创建的异常
     */
    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";
    }
}

ofNullable() 与 of()

创建Optional容器有两种方式

  1. 调用ofNullable()方法,传入的对象可以为null
  2. 调用of()方法,传入的对象不可以为null,否则抛出NullPointerException
@Test
void test1() {

	User user = new User();
	User userNull = null;

	Optional<User> user2 = Optional.of(user);

	//Optional<User> user3 = Optional.of(userNull); // 抛出NullPointerException

	Optional<User> user3 = Optional.ofNullable(userNull);
}

orElse()

如果容器中的对象存在,则返回。否则返回传递进来的参数

@Test
void test2() {
    User user = new User("1", "Ray", "123456");
    User userNull = null;

    Optional<User> user2 = Optional.ofNullable(user);
    Optional<User> user3 = Optional.ofNullable(userNull);

    System.out.println(user2.orElse(null));
    System.out.println(user3.orElse(null));
}

ifPresent()

进阶用法(主要是因为函数式编程,简化代码)

源码

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

----------------------------

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

用法

@Test
void test3() {
    User user = new User("1", "Ray", "123456");

    // ifPresent 写法
    Optional<User> user2 = Optional.ofNullable(user);
    user2.ifPresent((s -> System.out.println(s.getName())));
		
    System.out.println("------- 结果是一样的 --------");

    // 旧的写法
    if (null != user) {
        System.out.println(user.getName());
    }
}

orElseGet()

如果对象存在,则直接返回,否则返回由Supplier接口的实现用来生成默认值

@Test
void test4() {
    User user = new User("1", "Ray", "123456");

    Optional<User> optional = Optional.ofNullable(user);

    // orElseGet 写法
    User user1 = optional.orElseGet(() -> new User());

    System.out.println("------- 结果是一样的 --------");

    // 旧的写法
    if (null != user) {
        user = new User();
    }
}

如果存在user,则直接返回,否则创建出一个新的User对象

filter()

源码

// 如果容器中的对象存在,并且符合过滤条件,返回装载对象的Optional容器,否则返回一个空的Optional容器
public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}


// 接口
@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
}

用法

@Test
void test5() {
    User user = new User("1", "Ray", "123456");

    Optional<User> optional = Optional.ofNullable(user);

    // filter 写法
    User user1 = optional.filter((value) -> "Ray".equals(value.getName())).orElse(null);
    System.out.println("user1 = " + user1);

    System.out.println("------- 结果是一样的 --------");

    if (null != user) {
        if ("Ray".equals(user.getName())) {
            System.out.println("user1 = " + user1);
        } else {
            System.out.println("user1 = " + user1);
        }
    }
}

map()

源码

// 如果容器的对象存在,则对其执行调用mapping函数得到返回值。然后创建包含mapping返回值的Optional,否则返回空Optional。
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));
    }
}


// 接口
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

用法

@Test
void test6() {
    User user = new User("1", "Ray", "123456");

    Optional<User> optional = Optional.ofNullable(user);

    // 如果容器的对象存在,则对其执行调用mapping函数得到返回值。然后创建包含mapping返回值的Optional,否则返回空Optional。
    String name = optional.map(user1 -> user1.getName()).orElse("Ray");
    System.out.println("name = " + name);

    System.out.println("------- 结果是一样的 --------");
    if (null != user) {
        System.out.println("name = " + user.getName());
    } else {
        System.out.println("name = Ray");
    }
}

总结

再来感受一下Optional的魅力

/**
 * 以前的代码 1.0
 */
public static String version1(User user) {
    if (user != null) {
        String name = user.getName();
        if (name != null) {
            return name.toUpperCase();
        } else {
            return null;
        }
    } else {
        return null;
    }
}


/**
 * 以前的代码 2.0
 */
public static String version2(User user) {
    if (user != null && StringUtils.isNotBlank(user.getName())) {
        return user.getName().toUpperCase();
    }
    return null;
}


/**
 * 现在的代码 3.0
 */
public static String version3(User user) {
    return Optional.ofNullable(user)
            .map(user1 -> user1.getName())
            .map(s -> s.toUpperCase())
            .orElse(null);
}

filter,map或flatMap一个函数,函数的参数拿到的值一定不是null。所以我们通过filter,map 和 flatMap之类的函数可以将其安全的进行变换,最后通过orElse系列,get,isPresent 和 ifPresent将其中的值提取出来。