Optional优雅处理空值问题
Optional 是 Java 8 引入的容器类,用于表示可能为空的值。本文讲解其正确用法和常见误区。
为什么需要 Optional
传统空值处理的问题:
String city = user.getAddress().getCity();
String city = null; if (user != null) { Address address = user.getAddress(); if (address != null) { city = address.getCity(); } }
|
Optional 基本用法
创建 Optional
Optional<String> opt1 = Optional.of("hello");
Optional<String> opt2 = Optional.ofNullable(getString());
Optional<String> opt3 = Optional.empty();
|
获取值
Optional<String> opt = Optional.of("hello");
String val1 = opt.get();
String val2 = opt.orElse("default");
String val3 = opt.orElseGet(() -> expensiveOperation());
String val4 = opt.orElseThrow(() -> new NotFoundException());
|
条件操作
Optional<String> opt = Optional.of("hello");
opt.ifPresent(System.out::println);
Optional<String> upper = opt.map(String::toUpperCase);
Optional<String> result = opt.flatMap(this::findByName);
Optional<String> filtered = opt.filter(s -> s.length() > 3);
|
实战场景
1. 链式调用避免嵌套
String city = null; if (user != null && user.getAddress() != null) { city = user.getAddress().getCity(); }
String city = Optional.ofNullable(user) .map(User::getAddress) .map(Address::getCity) .orElse("Unknown");
|
2. 方法返回值
public Optional<User> findById(Long id) { User user = userDao.findById(id); return Optional.ofNullable(user); }
User user = findById(1L) .orElseThrow(() -> new UserNotFoundException(1L));
|
3. 异常转换
Optional.ofNullable(user) .filter(u -> u.getStatus() == Status.ACTIVE) .orElseThrow(() -> new IllegalStateException("用户未激活"));
|
常见误区
1. Optional 作为字段
public class User { private Optional<String> nickname; }
public class User { private String nickname; public Optional<String> getNickname() { return Optional.ofNullable(nickname); } }
|
2. Optional 作为方法参数
public void process(Optional<String> name) { ... }
public void process(String name) { process(name, false); }
public void process(String name, boolean uppercase) { ... }
|
3. isPresent + get 的组合
if (opt.isPresent()) { String val = opt.get(); }
opt.ifPresent(val -> { });
opt.map(...).filter(...).orElse(...);
|
4. 默认值为null
String val = opt.orElse(null);
String val = opt.orElse("");
|
Optional 与 Stream 结合
List<Optional<String>> optionals = Arrays.asList( Optional.of("a"), Optional.empty(), Optional.of("b") );
List<String> results = optionals.stream() .flatMap(Optional::stream) .collect(Collectors.toList());
List<String> results = optionals.stream() .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList());
|
性能考量
Optional 是对象,有创建开销:
public String findName() { return condition ? "name" : null; }
public String findCity() { return Optional.ofNullable(user) .map(User::getAddress) .map(Address::getCity) .orElse("Unknown"); }
|
最佳实践
- 作为返回值:明确表示方法可能不返回结果
- 不用于字段:字段用null,通过getter返回Optional
- 不用于参数:使用重载或Builder模式
- 避免isPresent + get:使用函数式操作
- 不提供null默认值:默认值应是有意义的值
public class UserService { public Optional<User> findById(Long id) { ... } public User getById(Long id) { ... } }
|
总结
Optional 是处理空值的优雅方案,但不是银弹。正确使用它能提高代码可读性和安全性,滥用则会导致性能问题和代码冗余。记住:Optional 是用于返回值的,不是用于字段和参数的。