Java 8 特性之Optional用法详解

简介: NPE(NullPointerException)一直是Java程序员最深恶痛绝的异常,冗长的非空校验使代码的可读性和优雅性都大大降低。那么本篇文章,笔者将详细介绍一下Java 8 引入的特性--*Optional*类,看看它是如何避免空指针异常的。

前言

NPE(NullPointerException)一直是Java程序员最深恶痛绝的异常,冗长的非空校验使代码的可读性和优雅性都大大降低。那么本篇文章,笔者将详细介绍一下Java 8 引入的特性--Optional类,看看它是如何避免空指针异常的。

什么是Optional?

Optional是一个容器对象,它可能包含或不包含非空值。如果存在值,isPresent()将返回true,而get()则返回该值。提供了取决于所包含值的存在与否的其他方法,例如orElse()(如果值不存在,则返回默认值)和ifPresent()(若值存在,则执行一段代码)。这是一个基于值的类;对Optional实例使用身份敏感操作(包括引用相等(==)、身份哈希码或同步)可能会产生不可预测的结果,应避免

Optional解决了什么问题?

在 Java 8 之前,我们进行对象校验是这样的:

public String getCity(User user){
   
    if(user != null){
   
        Address address = user.getAddress();
        if(address != null){
   
            return address.getCity();
        }else{
   
            return "北京市";
        }
    }else{
   
        return "北京市";
    }
}

Java 8 写法:

public String getCity(User user){
   
    return Optional.ofNullable(user)
        .map(u -> u.getAddress())
        .map(address -> address.getCity())
        .orElse("北京市");

}

方法详解

empty

描述

返回空的 Optional 实例。

源码
public static<T> Optional<T> empty() {
   
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
用法
Optional<Object> empty = Optional.empty();

创建了一个空的Optional对象,如果此时调用get()方法,会抛出NoSuchElementException

Optional<Object> empty = Optional.empty();
System.out.println(empty.get());// 抛出 NoSuchElementException

of(T value)

描述

为非Null值创建一个Optional,传入参数不能为null,否则会抛出NullPointerException。

源码
public static <T> Optional<T> of(T value) {
   
    return new Optional<>(value);
}
用法
Optional<String> userName = Optional.of("userName");

如果传入null,则会抛出NullPointerException

Optional<String> userName = Optional.of(null);// 抛出 NullPointerException

ofNullable(T value)

描述

创建可为空的Optional,如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。

源码
public static <T> Optional<T> ofNullable(T value) {
   
    return value == null ? empty() : of(value);
}
用法
Optional<String> userName = Optional.ofNullable("userName");

get()

描述

如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException。

源码
public T get() {
   
    if (value == null) {
   
        throw new NoSuchElementException("No value present");
    }
    return value;
}
用法
Optional<String> userName = Optional.ofNullable("userName");
System.out.println(userName.get());//输出 userName

isPresent()

描述

如果存在值,则返回true,否则返回false。

源码
public boolean isPresent() {
   
    return value != null;
}
用法
Optional<String> userName = Optional.ofNullable("userName");
System.out.println(userName.isPresent());//输出 true
Optional<String> empty = Optional.ofNullable(null);
System.out.println(empty.isPresent());//输出 false

ifPresent(Consumer<? super T> consumer)

描述

如果值存在则使用该值调用 consumer , 否则不执行任何操作。

要理解ifPresent方法,首先需要了解Consumer类。简答地说,Consumer类包含一个抽象方法。该抽象方法对传入的值进行处理,但没有返回值。Java8支持不用接口直接通过lambda表达式传入参数。
如果Optional实例有值,调用ifPresent()可以接受接口段或lambda表达式。

源码
public void ifPresent(Consumer<? super T> consumer) {
   
    if (value != null)
        consumer.accept(value);
}
用法
Optional<String> userName = Optional.ofNullable("userName");
userName.ifPresent((value) -> System.out.println(value.length()));//输出 8
Optional<String> empty = Optional.ofNullable(null);
empty.ifPresent((value) -> System.out.println(value.length()));//无输出,此时Optional为空值,不执行操作

filter(Predicate<? super T> predicate)

描述

如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。

源码
public Optional<T> filter(Predicate<? super T> predicate) {
   
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}
用法
Optional<String> userName = Optional.ofNullable("userName");
Optional<String> filterUserName1 = userName.filter((value) -> value.length() > 4);
System.out.println(filterUserName1.get());//输出 userName
Optional<String> filterUserName2 = userName.filter((value) -> value.length() < 4);
System.out.println(filterUserName2.get());//抛出 NoSuchElementException,因为此时没有找到匹配的值,返回一个空的Optional

map(Function<? super T, ? extends U> mapper)

描述

如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空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));
    }
}
用法
Optional<String> userName = Optional.ofNullable("userName");
Optional<String> mapUserName = userName.map((value) -> value.toUpperCase(Locale.ROOT));
System.out.println(mapUserName.get());//输出 USERNAME

flatMap(Function<? super T, Optional<> mapper)

描述

如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional,此方法类似于map(Function),但提供的mapper的返回值必须是Optional,如果调用,flatMap不会用附加的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));
    }
}
用法
Optional<String> userName = Optional.ofNullable("userName");
Optional<String> flatMapUserName = userName.flatMap((value) ->
                     Optional.of(value.toUpperCase(Locale.ROOT)) //mapper的返回值必须为Optional
);
System.out.println(flatMapUserName.get());//输出 USERNAME

orElse(T other)

描述

如果存在该值,返回值, 否则返回 other。

源码
public T orElse(T other) {
   
    return value != null ? value : other;
}
用法
Optional<String> userName = Optional.ofNullable("userName");
System.out.println(userName.orElse("mobile"));//输出 userName
Optional<Object> empty = Optional.empty();
System.out.println(empty.orElse("mobile"));//输出 mobile

orElseGet(Supplier<? extends T> other)

描述

如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。

源码
public T orElseGet(Supplier<? extends T> other) {
   
    return value != null ? value : other.get();
}
用法
Optional<String> userName = Optional.ofNullable("userName");
System.out.println(userName.orElseGet(() -> "mobile"));//输出 userName
Optional<Object> empty = Optional.empty();
System.out.println(empty.orElseGet(() -> "mobile"));//输出 mobile

orElseThrow(Supplier<? extends X> exceptionSupplier)

描述

如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常

源码
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
   
    if (value != null) {
   
        return value;
    } else {
   
        throw exceptionSupplier.get();
    }
}
用法
try {
   
    Optional<String> userName = Optional.ofNullable("userName");
    System.out.println(userName.orElseThrow(Exception::new));//输出 userName
} catch (Exception e) {
   
    e.printStackTrace();
}
try {
   
    Optional<Object> empty = Optional.empty();
    System.out.println(empty.orElseThrow(Exception::new));
} catch (Exception e) {
   
    e.printStackTrace(); //异常捕获
}

总结

以上便是Optional的各个方法的用法介绍,还是建议大家熟练使用,这样能让自己的代码变得更加优雅。

相关文章
|
19天前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
46 2
|
20天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
33 3
|
20天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
31 2
|
2天前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
11 4
|
16天前
|
存储 安全 Java
深入理解Java中的FutureTask:用法和原理
【10月更文挑战第28天】`FutureTask` 是 Java 中 `java.util.concurrent` 包下的一个类,实现了 `RunnableFuture` 接口,支持异步计算和结果获取。它可以作为 `Runnable` 被线程执行,同时通过 `Future` 接口获取计算结果。`FutureTask` 可以基于 `Callable` 或 `Runnable` 创建,常用于多线程环境中执行耗时任务,避免阻塞主线程。任务结果可通过 `get` 方法获取,支持阻塞和非阻塞方式。内部使用 AQS 实现同步机制,确保线程安全。
|
16天前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
38 3
|
16天前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
23 2
|
Java 测试技术 API
学习Java8中Optional
Optional 类主要是为了解决(NullPointerException)空指针异常 。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此。
310 0
学习Java8中Optional
|
10天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
下一篇
无影云桌面