Optional类

介绍

是什么,为什么,做什么

Optional 类是 JDK 8 新增的特性,目的是为了对对象的空指针异常进行优雅的处理。

特点

首先通过查看 Optional 类的代码,可以看到 Optional 类是 final 修饰的,是一个不可变类。即是,一、它不能被继承;二、Optional 对象创建后,是不可修改的。

public final class Optional<T> {
 ...
}

Optional 类还有一个成员变量 value,即是真正我们所要处理的对象。同样是 final 修饰,不可变。

private final T value;

个人理解

以面向对象的角度来做个比喻:

  • 直接处理对象:如果一个对象可能为空,为了避免空指针异常,我会在调用这个对象的方法的时候,先进行一个 if 判断,判断对象不为空之后,再进行方法调用,如果这时候是有多个层次的调用,并且每一层都有可能为空的时候,就会让代码嵌套了很多层的 if ,又臭又长。这不是我想要的。
  • 使用 Optional :Optional 就像是一个盒子,将我们想要操作的对象包装起来(成员变量 value 即是这个对象),我们通过 Optional 操作对象,如果对象不为空,操作如常;如果对象为空,Optional 类的代码会让我们在调用的时候更加优雅,不用显式地做 if 判断。

API

构造对象

Optional 的构造函数是私有的,意味着不能直接通过 new 创建 Optional 对象。

private Optional() {
	this.value = null;
}

private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

Optional 的构造方法有 2 个:of()ofNullable() ,都是静态方法:

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 static<T> Optional<T> empty() {
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

private static final Optional<?> EMPTY = new Optional<>();

两个构造方法如何选用,从方法名就可以看出一二:如果所包装的对象绝对不为空,则选择 of() 方法创建 Optional 对象;如果所包装的对象可能为空,则选择 ofNullable() 方法创建 Optional 对象。

我自己在使用 Optional 时,绝大部分时候用的都是 ofNullable() 来进行创建的,因为毕竟 Optional 主要就是为了处理空指针嘛。少数情况下,对象绝对不为空,但我需要使用 Optional 的 API ,我就用 of() 来创建。

处理 value

get

获取 value 对象

public T get() {
    if (value == null) {
    	throw new NoSuchElementException("No value present");
    }
    return value;
}

isPresent

判断 value 是否存在

public boolean isPresent() {
	return value != null;
}

ifPresent

value 如果存在,调用一个方法

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

fliter

value 如果存在,调用一个判断方法对 value 进行判断,true 则返回原 Optional 对象,false 则返回空 Optional 对象

public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}

map

value 如果存在,调用一个方法对 value 进行处理,然后将处理之后的 value 值放到一个新的 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 方法类似,但是没有将处理之后的 value 值封装到 Optional 对象中,但方法声明中的参数要求返回的是 Optional<U> 对象,所以比起 map 方法,需要自己手动将处理之后的 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));
    }
}

orElse

这个跟 get 方法类似,同样是取 value 的方法,不同的是,如果 value 为空,则返回方法参数中 other 这个对象

public T orElse(T other) {
    return value != null ? value : other;
}

orElseGet

与 orElse 方法类似,不同的是参数是函数式接口,相比 orElse 更加灵活,可以写逻辑根据不同情况返回不同的 value 类型的对象

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}

与 orElse 不同的还有一点,如果 orElse 参数中的对象也是由方法返回,当 value 为空时,orElse 和 orElseGet 没有区别,当 value 不为空时,orElse 参数中的方法会执行,orElseGet 方法中的方法不会执行,后者性能会高一点。

orElseThrow

与 orElse 类似,不同的是当 value 为空时,会抛出参数中定制的异常

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

代码示例

User 类

public class User {
    private String name;
    private String address;

    public User() {}

    public User(String name, String address) {
        this.name = name;
        this.address = address;
    }
    
    // getter & setter & toString
}

of / ofNullable 示例

public static void main(String[] args) {
    User user1 = null;
    // 这里会抛出空指针异常
    Optional<User> optional1 = Optional.of(user1);

    User user2 = new User();
    // 正常构造
    Optional<User> optional2 = Optional.of(user2);

    User user3 = null;
    // 正常构造,optioinal3的value为null
    Optional<User> optional3 = Optional.ofNullable(user3);
}

isPresent / ifPresent / get 示例

public static void main(String[] args) {
    // optionalConstructor();

    User user = new User();
    user.setName("Jack");

    Optional<User> optional = Optional.ofNullable(user);
    // isPresent
    System.out.println(optional.isPresent());
    
    // ifPresent
    optional.ifPresent((value)-> value.setAddress("guangzhou"));
    System.out.println(optional.get());
}

控制台打印:

true
User{name='Jack', address='guangzhou'}

filter 示例

User user1 = new User("Jack", "guangzhou");
User user2 = new User("Mary", "beijing");

Optional<User> optional1 = Optional.ofNullable(user1).filter((value) -> "guangzhou".equals(value.getAddress()));
System.out.println(optional1.get());

Optional<User> optional2 = Optional.ofNullable(user2).filter((value) -> "guangzhou".equals(value.getAddress()));
System.out.println(optional2);

控制台打印:

User{name='Jack', address='guangzhou'}
Optional.empty

可以看到,由于 user2 的 address 不是 guangzhou ,所以 optional2 中的 value 是空的。

map / flatMap 示例

User user1 = new User("Jack", "guangzhou");
User user2 = new User("Mary", "beijing");

List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);

Optional<List<String>> optional1 = Optional.ofNullable(list).map((value) -> {
    List<String> addressList = new ArrayList<>(value.size());
    for (User user : value) {
        addressList.add(user.getAddress());
    }
    return addressList;
});
System.out.println(optional1.get());

Optional<List<String>> optional2 = Optional.ofNullable(list).flatMap((value) -> {
    List<String> nameList = new ArrayList<>(value.size());
    for (User user : value) {
        nameList.add(user.getName());
    }

    return Optional.ofNullable(nameList);
});
System.out.println(optional2.get());

控制台输出:

[guangzhou, beijing]
[Jack, Mary]

map 是对原来的 value 进行处理映射,然后自动将返回的对象包装到 optional 对象中返回。

flatMap 需要我们手动将 nameList 进行包装再返回。

public class OptionalTest {
    public static void main(String[] args) {
        User nullUser = null;

        User user1 = Optional.ofNullable(nullUser).orElse(getUser());
        System.out.println(user1);

        User user2 = Optional.ofNullable(nullUser).orElseGet(OptionalTest::getUser);
        System.out.println(user2);

        Optional.ofNullable(nullUser).orElseThrow(()-> new RuntimeException("User 为空!"));
    }

    private static User getUser() {
        return new User("nobody", "default");
    }
}

控制台输出:

User{name='nobody', address='default'}
User{name='nobody', address='default'}
Exception in thread "main" java.lang.RuntimeException: User 为空!

附录:示例代码全文

public class OptionalTest {
    public static void main(String[] args) {
        optionalConstructor();

        isPresentAndIfPresent();

        filter();

        mapAndFlatMap();

        orElse();
    }

    private static void orElse() {
        User nullUser = null;

        User user1 = Optional.ofNullable(nullUser).orElse(getUser());
        System.out.println(user1);

        User user2 = Optional.ofNullable(nullUser).orElseGet(OptionalTest::getUser);
        System.out.println(user2);

        Optional.ofNullable(nullUser).orElseThrow(()-> new RuntimeException("User 为空!"));
    }

    private static User getUser() {
        return new User("nobody", "default");
    }

    private static void mapAndFlatMap() {
        User user1 = new User("Jack", "guangzhou");
        User user2 = new User("Mary", "beijing");

        List<User> list = new ArrayList<>();
        list.add(user1);
        list.add(user2);

        Optional<List<String>> optional1 = Optional.ofNullable(list).map((value) -> {
            List<String> addressList = new ArrayList<>(value.size());
            for (User user : value) {
                addressList.add(user.getAddress());
            }
            return addressList;
        });
        System.out.println(optional1.get());

        Optional<List<String>> optional2 = Optional.ofNullable(list).flatMap((value) -> {
            List<String> nameList = new ArrayList<>(value.size());
            for (User user : value) {
                nameList.add(user.getName());
            }

            return Optional.ofNullable(nameList);
        });
        System.out.println(optional2.get());
    }

    private static void filter() {
        User user1 = new User("Jack", "guangzhou");
        User user2 = new User("Mary", "beijing");

        Optional<User> optional1 = Optional.ofNullable(user1).filter((value) -> "guangzhou".equals(value.getAddress()));
        System.out.println(optional1.get());

        Optional<User> optional2 = Optional.ofNullable(user2).filter((value) -> "guangzhou".equals(value.getAddress()));
        System.out.println(optional2);
    }

    private static void isPresentAndIfPresent() {
        User user = new User();
        user.setName("Jack");

        Optional<User> optional = Optional.ofNullable(user);
        // isPresent
        System.out.println(optional.isPresent());

        // ifPresent
        optional.ifPresent((value) -> value.setAddress("guangzhou"));
        System.out.println(optional.get());
    }

    private static void optionalConstructor() {
        User user1 = null;
        // 这里会抛出空指针异常
        Optional<User> optional1 = Optional.of(user1);

        User user2 = new User();
        // 正常构造
        Optional<User> optional2 = Optional.of(user2);

        User user3 = null;
        // 正常构造,optioinal3的value为null
        Optional<User> optional3 = Optional.ofNullable(user3);
    }
}
上一篇:Java8新特性(转载 from:https://blog.csdn.net/huifeng773950918/article/details/80333246)


下一篇:如何在 Java8 中风骚走位避开空指针异常