Optional类
Optional概述
Optional是Java 8引入的容器类,用于优雅地处理空值,避免NullPointerException。
创建Optional
java
import java.util.Optional;
public class CreateOptional {
public static void main(String[] args) {
// 创建包含值的Optional
Optional<String> opt1 = Optional.of("Hello");
// 创建可能为null的Optional
String str = null;
Optional<String> opt2 = Optional.ofNullable(str);
// 创建空的Optional
Optional<String> opt3 = Optional.empty();
}
}常用方法
获取值
java
Optional<String> opt = Optional.of("Hello");
// get() - 获取值(为空时抛异常)
String value1 = opt.get();
// orElse() - 为空时返回默认值
String value2 = opt.orElse("Default");
// orElseGet() - 为空时通过Supplier获取
String value3 = opt.orElseGet(() -> "Default");
// orElseThrow() - 为空时抛出自定义异常
String value4 = opt.orElseThrow(() -> new RuntimeException("值为空"));判断方法
java
Optional<String> opt = Optional.of("Hello");
// 是否有值
boolean hasValue = opt.isPresent(); // true
// 是否为空(Java 11+)
boolean isEmpty = opt.isEmpty(); // false
// 有值时执行操作
opt.ifPresent(value -> System.out.println(value));
// 有值时执行操作,否则执行另一个操作(Java 9+)
opt.ifPresentOrElse(
value -> System.out.println("值: " + value),
() -> System.out.println("无值")
);转换方法
java
Optional<String> opt = Optional.of("Hello");
// map - 转换值
Optional<Integer> length = opt.map(String::length);
// flatMap - 转换值(返回Optional)
Optional<String> upper = opt.flatMap(s -> Optional.of(s.toUpperCase()));
// filter - 过滤
Optional<String> filtered = opt.filter(s -> s.length() > 3);实战示例
避免空指针
java
// 传统方式
public String getCity(User user) {
if (user != null) {
Address address = user.getAddress();
if (address != null) {
String city = address.getCity();
if (city != null) {
return city;
}
}
}
return "未知";
}
// 使用Optional
public String getCityOptional(User user) {
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.orElse("未知");
}方法返回值
java
public class UserService {
private Map<Integer, User> users = new HashMap<>();
// 返回Optional,明确表示可能为空
public Optional<User> findById(Integer id) {
return Optional.ofNullable(users.get(id));
}
// 使用
public static void main(String[] args) {
UserService service = new UserService();
service.findById(1)
.ifPresent(user -> System.out.println(user.getName()));
String name = service.findById(1)
.map(User::getName)
.orElse("未知用户");
}
}集合处理
java
import java.util.*;
import java.util.stream.Collectors;
public class OptionalCollection {
public static void main(String[] args) {
List<Optional<String>> optionals = Arrays.asList(
Optional.of("A"),
Optional.empty(),
Optional.of("B"),
Optional.empty(),
Optional.of("C")
);
// 过滤掉空值
List<String> values = optionals.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
// [A, B, C]
// Java 9+ 使用Optional::stream
List<String> values2 = optionals.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
}
}配置处理
java
public class Config {
private Properties props = new Properties();
public Optional<String> getString(String key) {
return Optional.ofNullable(props.getProperty(key));
}
public Optional<Integer> getInt(String key) {
return getString(key).map(Integer::parseInt);
}
public Optional<Boolean> getBoolean(String key) {
return getString(key).map(Boolean::parseBoolean);
}
}
// 使用
Config config = new Config();
int timeout = config.getInt("timeout").orElse(30);
boolean debug = config.getBoolean("debug").orElse(false);异常处理
java
public class ExceptionHandling {
// 将可能抛异常的操作包装为Optional
public static Optional<Integer> parseInt(String s) {
try {
return Optional.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
public static void main(String[] args) {
int value = parseInt("123").orElse(0);
System.out.println(value); // 123
int invalid = parseInt("abc").orElse(0);
System.out.println(invalid); // 0
}
}Java 9+ 新增方法
or()
java
Optional<String> opt = Optional.empty();
// 为空时返回另一个Optional
Optional<String> result = opt.or(() -> Optional.of("Default"));
System.out.println(result); // Optional[Default]ifPresentOrElse()
java
Optional<String> opt = Optional.of("Hello");
opt.ifPresentOrElse(
value -> System.out.println("值: " + value),
() -> System.out.println("无值")
);stream()
java
Optional<String> opt = Optional.of("Hello");
// 转换为Stream
Stream<String> stream = opt.stream();
// 在Stream中使用
List<String> list = Stream.of(
Optional.of("A"),
Optional.empty(),
Optional.of("B")
).flatMap(Optional::stream).collect(Collectors.toList());
// [A, B]最佳实践
1. 不要用Optional作为字段
java
// 不推荐
public class User {
private Optional<String> name; // 不推荐
}
// 推荐
public class User {
private String name; // 可以为null
}2. 不要用Optional作为方法参数
java
// 不推荐
public void setName(Optional<String> name) { }
// 推荐
public void setName(String name) { }
public void setName(String name, String defaultValue) { }3. 用于返回值
java
// 推荐:明确表示可能返回空
public Optional<User> findById(Integer id) {
return Optional.ofNullable(userMap.get(id));
}4. 避免直接调用get()
java
Optional<String> opt = Optional.ofNullable(getString());
// 不推荐
if (opt.isPresent()) {
String value = opt.get(); // 多余的检查
}
// 推荐
opt.ifPresent(value -> process(value));
String value = opt.orElse("default");5. 选择合适的orElse方法
java
// orElse - 默认值已确定
String value1 = opt.orElse("default");
// orElseGet - 默认值需要计算
String value2 = opt.orElseGet(() -> expensiveComputation());
// orElseThrow - 需要抛出异常
String value3 = opt.orElseThrow(() -> new NotFoundException());Optional vs null
| 场景 | null | Optional |
|---|---|---|
| 语义 | 不明确 | 明确表示可能为空 |
| 类型安全 | 运行时NPE | 编译时检查 |
| 链式调用 | 需要大量if | 流畅的链式调用 |
| 性能 | 无开销 | 有轻微开销 |
| 序列化 | 支持 | 不支持 |