Appearance
Optional 类
为什么需要 Optional?
Optional 是 Java 8 引入的容器对象,用于表示值是否存在。
┌─────────────────────────────────────────────────────────────────┐
│ Optional 解决的问题 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ❌ NullPointerException 是 Java 最常见的异常 │
│ ❌ 防御性检查导致代码臃肿 │
│ │
│ ✅ Optional 提供了更优雅的 null 处理方式 │
│ • 明确表示值可能为空 │
│ • 提供函数式操作 │
│ • 避免大量的 if (obj != null) 检查 │
│ │
└─────────────────────────────────────────────────────────────────┘创建 Optional
java
// 创建空 Optional
Optional<String> empty = Optional.empty();
// 创建非空 Optional
Optional<String> present = Optional.of("Hello");
// 创建可空 Optional(推荐)
Optional<String> nullable = Optional.ofNullable(null);
Optional<String> nullable2 = Optional.ofNullable("World");判断与获取
isPresent 与 isEmpty
java
Optional<String> opt = Optional.ofNullable("Hello");
// 判断是否有值
if (opt.isPresent()) {
String value = opt.get();
System.out.println(value);
}
// Java 11+ 推荐写法
if (opt.isEmpty()) {
System.out.println("值为空");
} else {
System.out.println(opt.get());
}get 与 orElse
java
Optional<String> opt = Optional.ofNullable("Hello");
// 直接获取(有值返回值,无值抛异常)
String value = opt.get(); // "Hello"
// orElse - 值存在返回值,不存在返回默认值
String v1 = Optional.ofNullable("Hello").orElse("Default"); // "Hello"
String v2 = Optional.ofNullable(null).orElse("Default"); // "Default"
// orElseGet - 值存在返回值,不存在调用 Supplier 获取
String v3 = Optional.ofNullable(null).orElseGet(() -> "Generated"); // "Generated"
// orElseThrow - 值存在返回值,不存在抛出指定异常
String v4 = Optional.ofNullable(null)
.orElseThrow(() -> new IllegalArgumentException("值不能为空"));ifPresent
java
Optional<String> opt = Optional.ofNullable("Hello");
// 值存在时执行操作
opt.ifPresent(value -> System.out.println("值存在:" + value));
// Java 9+ ifPresentOrElse
opt.ifPresentOrElse(
value -> System.out.println("值存在:" + value),
() -> System.out.println("值为空")
);链式操作
map - 转换值
java
Optional<String> opt = Optional.ofNullable("Hello");
// 值存在时转换
Optional<Integer> len = opt.map(String::length);
// len = Optional.of(5)
// 链式转换
Optional<Integer> result = Optional.ofNullable("Hello")
.map(String::toUpperCase)
.map(String::length);
// result = Optional.of(5)flatMap - 避免嵌套 Optional
java
class User {
private String name;
private Optional<String> email;
public Optional<String> getEmail() {
return email;
}
}
// ❌ 错误:使用 map 会导致嵌套 Optional
Optional<Optional<String>> nested =
Optional.ofNullable(user).map(User::getEmail);
// ✅ 正确:使用 flatMap
Optional<String> email =
Optional.ofNullable(user).flatMap(User::getEmail);filter - 过滤值
java
Optional<Integer> opt = Optional.of(10);
// 值存在且满足条件才返回
Optional<Integer> filtered = opt.filter(n -> n > 5);
// filtered = Optional.of(10)
Optional<Integer> filtered2 = opt.filter(n -> n > 20);
// filtered2 = Optional.empty()实战应用
链式查找
java
class User {
private String name;
private Address address;
public Address getAddress() { return address; }
}
class Address {
private String city;
private Country country;
public Country getCountry() { return country; }
}
class Country {
private String code;
public String getCode() { return code; }
}
// 传统写法:层层判断
public String getCountryCode(User user) {
if (user != null) {
Address addr = user.getAddress();
if (addr != null) {
Country country = addr.getCountry();
if (country != null) {
return country.getCode();
}
}
}
return "UNKNOWN";
}
// Optional 写法:链式调用
public String getCountryCode(User user) {
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCountry)
.map(Country::getCode)
.orElse("UNKNOWN");
}集合中查找
java
List<User> users = Arrays.asList(
new User("Tom", 25),
new User("Jerry", 30),
new User("Mike", 35)
);
// 查找第一个年龄大于30的用户
Optional<User> found = users.stream()
.filter(u -> u.getAge() > 30)
.findFirst();
// 安全获取
String name = users.stream()
.filter(u -> u.getAge() > 30)
.findFirst()
.map(User::getName)
.orElse("Not Found");空值默认值
java
// 简单默认值
String name = Optional.ofNullable(user)
.map(User::getName)
.orElse("Anonymous");
// 复杂默认值
String city = Optional.ofNullable(user)
.flatMap(User::getAddress)
.map(Address::getCity)
.orElseGet(() -> {
// 复杂的默认值计算逻辑
return lookupDefaultCity();
});高级用法
or 方法(Java 9+)
java
// 值不存在时,返回另一个 Optional
Optional<String> opt1 = Optional.ofNullable(null);
Optional<String> opt2 = Optional.ofNullable("Hello");
Optional<String> result = opt1.or(() -> opt2);
// result = Optional.of("Hello")stream 方法(Java 9+)
java
// Optional 转 Stream
Optional<String> opt = Optional.ofNullable("Hello");
long count = opt.stream()
.map(String::toUpperCase)
.count(); // 1
// 过滤集合中的空值
List<String> names = Arrays.asList("Tom", null, "Jerry", null, "Mike");
List<String> validNames = names.stream()
.flatMap(Optional::ofNullable)
.collect(Collectors.toList());
// ["Tom", "Jerry", "Mike"]ifPresentOrElse(Java 9+)
java
Optional<String> opt = Optional.ofNullable("Hello");
opt.ifPresentOrElse(
value -> System.out.println("值: " + value),
() -> System.out.println("值为空")
);常见错误
┌─────────────────────────────────────────────────────────────────┐
│ Optional 使用误区 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ❌ 不要用 Optional 替代方法参数 │
│ void method(Optional<String> param) // 不推荐 │
│ void method(String param) // 推荐,null 可接受 │
│ │
│ ❌ 不要用 Optional 替代字段 │
│ class User { Optional<String> name; } // 不推荐 │
│ class User { String name; } // 推荐 │
│ │
│ ❌ 不要过度使用 Optional │
│ Optional.ofNullable(x).get() // 多此一举 │
│ x // 直接使用即可 │
│ │
│ ✅ 正确场景: │
│ 方法返回值可能为空时 │
│ 链式处理可能为空的值时 │
│ 集合查找结果 │
│ │
└─────────────────────────────────────────────────────────────────┘总结
Optional 核心知识点:
| 方法 | 说明 |
|---|---|
ofNullable() | 创建可空 Optional(推荐) |
isPresent() | 判断是否有值 |
get() | 获取值(无值抛异常) |
orElse() | 获取值或默认值 |
orElseGet() | 获取值或调用 Supplier |
map() | 转换值 |
flatMap() | 转换值(避免嵌套) |
filter() | 过滤值 |
ifPresent() | 值存在时执行 |
⚠️ 易错点提醒:
- 不要用 Optional 作为字段类型
- 不要用 Optional 作为方法参数
- map 和 flatMap 的区别:flatMap 避免嵌套
of(null)会抛 NullPointerException,用ofNullable- Optional 主要用于方法返回值,不适合过度使用