Java Optional所有方法使用
一. 创建 Optional 对象
- Optional.of(T value)
- 作用:用非 null 值创建 Optional。
- 注意:参数为 null 会抛出 NullPointerException。
- Optional.ofNullable(T value)
- 作用:用值创建 Optional,允许值为 null。
- Optional.empty()
- 作用:创建一个空的 Optional。
示例:
Optional<String> opt = Optional.empty(); 示例:
Optional<String> opt = Optional.ofNullable(null); // 返回 Optional.empty() 示例:
Optional<String> opt = Optional.of("hello"); 二. 判断和获取值
- isPresent()
- 作用:判断 Optional 是否有值(不是 empty)。
- isEmpty()(Java 11+)
- 作用:判断 Optional 是否为空。
- get()
- 作用:获取值。若为空则抛 NoSuchElementException。
示例:
String value = opt.get(); 示例:
if(opt.isEmpty()) { System.out.println("没有值"); } 示例:
if(opt.isPresent()) { System.out.println(opt.get()); } 三. 值存在时的操作
- ifPresent(Consumer<? super T> action)
- 作用:如果有值,执行 action。
- ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)(Java 9+)
- 作用:有值执行 action,无值执行 emptyAction。
示例:
opt.ifPresentOrElse( val -> System.out.println(val), () -> System.out.println("没有值") ); 示例:
opt.ifPresent(val -> System.out.println(val)); 四. 提供默认值
- orElse(T other)
- 作用:有值返回该值,无值返回默认值。
- orElseGet(Supplier<? extends T> supplier)
- 作用:有值返回该值,无值调用 supplier 获取默认值(惰性)。
- orElseThrow()(Java 10+)
- 作用:有值返回该值,无值抛出 NoSuchElementException。
- orElseThrow(Supplier<? extends X> exceptionSupplier)
- 作用:有值返回该值,无值抛出指定异常。
示例:
String result = opt.orElseThrow(() -> new RuntimeException("没有值!")); 示例:
String result = opt.orElseThrow(); 示例:
String result = opt.orElseGet(() -> "默认值"); 示例:
String result = opt.orElse("默认值"); 五. 值转换
- map(Function<? super T, ? extends U> mapper)
- 作用:有值时对值进行转换并返回新的 Optional。
- flatMap(Function<? super T, Optional> mapper)
- 作用:有值时对值进行转换并返回 Optional,避免嵌套 Optional。
- 示例:
Optional<Integer> lenOpt = opt.flatMap(s -> Optional.of(s.length()));
- filter(Predicate<? super T> predicate)
- 作用:有值且满足条件则返回原 Optional,否则返回 empty。
- 示例:
Optional<String> filtered = opt.filter(s -> s.length() > 3);
示例:
Optional<Integer> lenOpt = opt.map(String::length); 六. 其他方法(Java 9+)
- stream()
- 作用:将 Optional 转为 Stream(有值时为单元素流,否则为空流)。
- 示例:
opt.stream().forEach(System.out::println);
七. 综合示例
Optional<String> opt = Optional.ofNullable("abc"); // 判断是否有值 if (opt.isPresent()) { System.out.println(opt.get()); } // 转换值 int len = opt.map(String::length).orElse(0); // 过滤 opt.filter(s -> s.startsWith("a")).ifPresent(System.out::println); // 默认值 String val = opt.orElse("default"); // 异常处理 String mustHave = opt.orElseThrow(() -> new IllegalArgumentException("必须有值"));
总结
| 方法名 | 主要用途 |
|---|---|
| of, ofNullable, empty | 创建 Optional |
| isPresent, isEmpty | 判断是否有值 |
| get | 获取值(不推荐直接用) |
| ifPresent, ifPresentOrElse | 有值时执行操作 |
| orElse, orElseGet, orElseThrow | 提供默认值或异常处理 |
| map, flatMap | 值转换 |
| filter | 条件过滤 |
| stream | 转换为流 |
八、进阶技巧
1. 与集合、流结合使用
在实际开发中,Optional 常与 Stream API 配合,用于处理可能为空的集合元素:
List<User> users = ...; Optional<User> optUser = users.stream() .filter(u -> u.getName().equals("张三")) .findFirst(); optUser.ifPresent(u -> System.out.println(u.getEmail())); 2. 嵌套 Optional 的处理
如果你的对象结构很深,传统的 null 检查会很繁琐。使用 map 可以链式安全访问:
Optional<User> userOpt = Optional.ofNullable(user); String city = userOpt .map(User::getAddress) .map(Address::getCity) .orElse("未知城市"); 这样可以避免多层 null 检查。
3. Optional 与异常处理结合
使用 orElseThrow 可以在缺失值时抛出自定义异常:
User user = optUser.orElseThrow(() -> new UserNotFoundException("用户不存在")); 九、常见误区
- 不要将 Optional 用作字段类型
- Optional 设计初衷是作为返回值类型,不建议用作类的属性字段(成员变量),会增加序列化和内存复杂度。
- 不要滥用 get() 方法
get()只在你确定有值时使用,否则建议用orElse、orElseThrow等方法。
- 不要在集合中使用 Optional
- List<Optional> 不是最佳实践,应该用 Optional<List> 或直接用空集合表示无数据。
推荐做法:
public Optional<User> findUserById(Long id) { ... } 不推荐:
class User { private Optional<String> name; // 不推荐 } 十、最佳实践
- 方法返回值建议用 Optional 表示可能缺失的值。
- 使用
map、flatMap、filter进行链式操作,避免嵌套 if-null 判断。 - 用
orElseGet替代orElse,当默认值计算较为复杂或耗时时(惰性计算)。 - 用
ifPresentOrElse(Java 9+)简化有值/无值的分支逻辑。
十一、实际应用场景举例
1. 数据库查询
public Optional<User> findById(Long id) { User user = jdbcTemplate.queryForObject(...); return Optional.ofNullable(user); } 2. 配置参数读取
Optional<String> config = Optional.ofNullable(System.getProperty("my.config")); String value = config.orElse("默认配置"); 3. RESTful 接口返回值
@GetMapping("/user/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { return userService.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } 十二、综合案例
假设你有一个订单系统,需要安全地获取订单的收货人城市:
public Optional<Order> findOrder(Long orderId) { // 查询订单 } public String getReceiverCity(Long orderId) { return findOrder(orderId) .map(Order::getReceiver) .map(Receiver::getAddress) .map(Address::getCity) .filter(city -> !city.isEmpty()) .orElse("未知城市"); } 这样可以保证即使任何一环为 null,也不会抛出异常,并且逻辑清晰。
十三、常用代码片段速查
// 创建 Optional<String> opt = Optional.ofNullable(value); // 判断 opt.isPresent(); opt.isEmpty(); // Java 11+ // 获取 opt.get(); // 不推荐 opt.orElse("默认值"); opt.orElseGet(() -> "默认值"); opt.orElseThrow(() -> new RuntimeException("没有值")); // 转换 opt.map(String::length); opt.flatMap(s -> Optional.of(s.length())); // 过滤 opt.filter(s -> s.length() > 3); // 条件执行 opt.ifPresent(System.out::println); opt.ifPresentOrElse( System.out::println, () -> System.out.println("没有值") ); // 与流结合 opt.stream().forEach(System.out::println); 十四、与其他框架结合
1. 与 Spring 框架结合
Spring Data JPA 的查询接口可以直接返回 Optional:
public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByUsername(String username); } 这样调用者必须处理可能为空的情况,API更安全。
2. 与 Stream API 深度结合
你可以在流操作中用 Optional 优雅处理可能缺失的值:
List<String> names = Arrays.asList("Tom", null, "Jerry"); names.stream() .map(Optional::ofNullable) .flatMap(Optional::stream) // Java 9+ .forEach(System.out::println); 这可以过滤掉 null 值,避免 NPE。
十五、源码解析(原理简述)
Optional 的核心是一个 final 字段 value:
public final class Optional<T> { private final T value; ... } - 如果 value 为 null,则表示 empty。
- 所有方法都围绕这个 value 做判断和操作。
- Optional 的实例是不可变的(immutable)。
例如,map 方法源码片段:
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) { if (!isPresent()) return empty(); else return Optional.ofNullable(mapper.apply(value)); } 这保证了链式调用的安全性。
十六、复杂业务场景举例
1. 多层嵌套属性安全访问
传统写法容易出现 null 检查地狱:
if (order != null && order.getReceiver() != null && order.getReceiver().getAddress() != null) { String city = order.getReceiver().getAddress().getCity(); } Optional链式写法:
Optional.ofNullable(order) .map(Order::getReceiver) .map(Receiver::getAddress) .map(Address::getCity) .ifPresent(System.out::println); 代码更简洁、更安全。
2. API响应处理
比如你有一个外部接口返回 Optional,结合响应式编程:
public Optional<User> getUserFromApi(String id) { // 调用外部接口 } public void processUser(String id) { getUserFromApi(id) .ifPresentOrElse( user -> save(user), () -> log.warn("用户未找到") ); } 十七、常见面试题
- Optional 的作用是什么?
- 避免空指针异常,提升代码可读性和安全性。
- Optional 的 map 和 flatMap 有什么区别?
- map 用于值转换,flatMap 用于避免嵌套 Optional。
- Optional 可以作为成员变量吗?
- 不推荐。只建议用作方法返回值类型。
- 如何优雅地处理多层嵌套对象的 null?
- 用 Optional 的链式 map。
十八、其他扩展用法
1. 自定义 Optional 工具方法
你可以封装一些通用操作:
public static <T> T getOrDefault(Optional<T> opt, T defaultValue) { return opt.orElse(defaultValue); } 2. Optional 与枚举结合
Optional<Status> statusOpt = Optional.ofNullable(Status.fromCode(code)); statusOpt.ifPresent(status -> handle(status)); 十九、常见坑与注意事项
- 不要在序列化对象时用 Optional(Jackson等可能不支持)。
- Optional 不是万能的,业务逻辑复杂时仍需合理判空。
- Optional 不能替代所有的 null 检查,但能显著减少出错概率。
二十、总结
Optional 的核心价值:
- 明确表达“值可能缺失”的语义。
- 支持函数式、链式操作,简化代码。
- 强制调用者处理缺失值,减少 NPE。
用法精髓:
- 只在返回值用 Optional,不在字段、参数用 Optional。
- 善用 map、flatMap、filter、orElse、orElseGet、orElseThrow。
- 与 Stream、Lambda、Spring 等现代 Java 技术结合,写出更优雅的代码。