Java Optional 类完整教程
·
Java Optional 类完整教程
一、什么是 Optional?
Optional 是 Java 8 引入的一个容器类,用于包装可能为 null 的对象。
它的核心作用是优雅地处理空值,避免直接操作 null 导致的 NullPointerException,同时让代码意图更清晰。
二、开发思路
- 理解传统 null 处理的问题(嵌套判断繁琐、易抛空指针)
- 掌握 Optional 的创建方式(3 种核心方法)
- 学习 Optional 的常用 API(判断、取值、转换、过滤等)
- 掌握链式调用技巧(简化多层 null 检查)
- 规避常见错误(过度使用 isPresent()、错误使用 of() 等)
三、代码示例与逐行注释
1. 准备测试类
先定义一个简单的实体类,用于后续示例:
// 用户类
class User {
private String name; // 用户名
private Address address; // 地址(可能为null)
// 构造方法
public User(String name, Address address) {
this.name = name;
this.address = address;
}
// getter方法
public String getName() { return name; }
public Address getAddress() { return address; }
}
// 地址类
class Address {
private String city; // 城市(可能为null)
public Address(String city) {
this.city = city;
}
public String getCity() { return city; }
}
2. Optional 的创建方式
Optional 提供 3 种创建实例的方法,适用于不同场景:
import java.util.Optional;
public class OptionalDemo {
public static void main(String[] args) {
// 1. 创建空的Optional(值为null)
Optional<String> emptyOpt = Optional.empty();
// 注意:empty()返回的是一个单例空实例,而非直接new Optional()
// 2. 创建包含非null值的Optional(值绝对不为null时用)
String str = "hello";
Optional<String> nonNullOpt = Optional.of(str);
// 若str为null,of()会直接抛NullPointerException
// Optional<String> nullOpt = Optional.of(null); // 运行时异常
// 3. 创建可能为null值的Optional(值可能为null时用)
String nullableStr = null;
Optional<String> nullableOpt = Optional.ofNullable(nullableStr);
// ofNullable()会自动处理null:若值为null,返回空Optional
}
}
3. 常用 API 详解
(1)判断值是否存在:isPresent() / isEmpty()
public class OptionalApi1 {
public static void main(String[] args) {
Optional<String> opt1 = Optional.of("test");
Optional<String> opt2 = Optional.empty();
// 判断值是否存在(非空)
boolean hasValue1 = opt1.isPresent(); // true
boolean hasValue2 = opt2.isPresent(); // false
// Java 11+:判断值是否不存在(为空)
boolean isEmpty1 = opt1.isEmpty(); // false
boolean isEmpty2 = opt2.isEmpty(); // true
}
}
(2)值存在时执行操作:ifPresent()
public class OptionalApi2 {
public static void main(String[] args) {
Optional<String> opt = Optional.of("hello");
// 若值存在,执行Lambda表达式(参数为非null值)
opt.ifPresent(s -> System.out.println(s.length())); // 输出:5
// 若值不存在,不执行任何操作
Optional.empty().ifPresent(s -> System.out.println(s)); // 无输出
// Java 9+:ifPresentOrElse(存在时执行操作,不存在时执行另一个操作)
opt.ifPresentOrElse(
s -> System.out.println("值为:" + s), // 存在时执行
() -> System.out.println("值不存在") // 不存在时执行
); // 输出:值为:hello
}
}
(3)获取值:get() / orElse() / orElseGet() / orElseThrow()
public class OptionalApi3 {
public static void main(String[] args) {
Optional<String> opt1 = Optional.of("java");
Optional<String> opt2 = Optional.empty();
// 1. get():获取值(仅在确定值存在时使用!)
String val1 = opt1.get(); // "java"
// String val2 = opt2.get(); // 抛NoSuchElementException
// 2. orElse():值不存在时返回默认值(默认值始终会被创建)
String val3 = opt1.orElse("default"); // "java"(用opt1的值)
String val4 = opt2.orElse("default"); // "default"(用默认值)
// 3. orElseGet():值不存在时通过Supplier生成默认值(默认值按需创建)
// 适合默认值创建成本高的场景(如数据库查询)
String val5 = opt1.orElseGet(() -> "生成的默认值"); // "java"
String val6 = opt2.orElseGet(() -> "生成的默认值"); // "生成的默认值"
// 4. orElseThrow():值不存在时抛指定异常
String val7 = opt1.orElseThrow(() -> new RuntimeException("值为空")); // "java"
try {
String val8 = opt2.orElseThrow(() -> new RuntimeException("值为空"));
} catch (RuntimeException e) {
System.out.println(e.getMessage()); // 输出:值为空
}
}
}
(4)转换值:map() / flatMap()
用于对 Optional 中的值进行转换,返回新的 Optional。
public class OptionalApi4 {
public static void main(String[] args) {
// 1. map():将值转换为另一种类型(自动包装为Optional)
Optional<String> strOpt = Optional.of("hello");
// 将字符串转换为它的长度(int)
Optional<Integer> lengthOpt = strOpt.map(s -> s.length());
lengthOpt.ifPresent(len -> System.out.println(len)); // 输出:5
// 2. flatMap():转换后的值本身就是Optional(用于嵌套Optional场景)
User user = new User("张三", new Address("北京"));
Optional<User> userOpt = Optional.of(user);
// 需求:获取用户地址的城市(Address可能为null,city可能为null)
// 用map()会得到Optional<Optional<String>>(不推荐)
Optional<Optional<String>> cityOpt1 = userOpt
.map(u -> Optional.ofNullable(u.getAddress())) // 先获取Address的Optional
.map(addrOpt -> addrOpt.map(Address::getCity)); // 再获取city的Optional
// 用flatMap()直接得到Optional<String>(推荐)
Optional<String> cityOpt2 = userOpt
.flatMap(u -> Optional.ofNullable(u.getAddress())) // 展开为Address的Optional
.flatMap(addr -> Optional.ofNullable(addr.getCity())); // 展开为city的Optional
cityOpt2.ifPresent(city -> System.out.println(city)); // 输出:北京
}
}
(5)过滤值:filter()
用于按条件过滤 Optional 中的值,符合条件保留,否则返回空 Optional。
public class OptionalApi5 {
public static void main(String[] args) {
Optional<Integer> numOpt = Optional.of(10);
// 过滤:只保留大于5的数字
Optional<Integer> filteredOpt1 = numOpt.filter(n -> n > 5);
filteredOpt1.ifPresent(n -> System.out.println(n)); // 输出:10
// 过滤:保留小于5的数字(不符合,返回空)
Optional<Integer> filteredOpt2 = numOpt.filter(n -> n < 5);
System.out.println(filteredOpt2.isEmpty()); // 输出:true
}
}
4. 实际开发案例:多层 null 检查简化
传统方式处理多层对象的 null 检查会很繁琐,用 Optional 链式调用可简化:
public class OptionalPractice {
public static void main(String[] args) {
// 场景:获取用户的城市,若任何一环为null,返回"未知城市"
User user1 = new User("李四", new Address("上海")); // 完整数据
User user2 = new User("王五", null); // 地址为null
User user3 = null; // 用户为null
// 传统方式(嵌套if,繁琐)
String city1 = getCityTraditional(user1);
System.out.println(city1); // 上海
// Optional方式(链式调用,简洁)
String city2 = getCityWithOptional(user2);
System.out.println(city2); // 未知城市
String city3 = getCityWithOptional(user3);
System.out.println(city3); // 未知城市
}
// 传统方式获取城市
private static String getCityTraditional(User user) {
if (user != null) {
Address address = user.getAddress();
if (address != null) {
String city = address.getCity();
if (city != null) {
return city;
}
}
}
return "未知城市";
}
// Optional方式获取城市
private static String getCityWithOptional(User user) {
return Optional.ofNullable(user) // 包装user(可能为null)
.flatMap(u -> Optional.ofNullable(u.getAddress())) // 转换为Address的Optional
.flatMap(addr -> Optional.ofNullable(addr.getCity())) // 转换为city的Optional
.orElse("未知城市"); // 任何一环为null则返回默认值
}
}
四、最佳实践与注意事项
- 用 Optional 作为返回值,而非参数:方法参数用 Optional 会增加调用方复杂度,不推荐。
- 避免过度使用 isPresent() + get():这等价于传统的
if (obj != null),失去了 Optional 的优势,应优先用 ifPresent()、orElse() 等。 - of() 和 ofNullable() 选择:确定值非 null 用 of(),可能为 null 用 ofNullable()。
- 链式调用优先:通过 map()、flatMap()、filter() 链式处理,简化代码。
- 不要嵌套 Optional:如
Optional<Optional<String>>,应通过 flatMap() 展开。
五、总结
Optional 是处理 null 的优雅方案,核心价值在于明确表达“值可能不存在”的语义,并通过链式 API 简化空值处理逻辑。合理使用可大幅减少 NullPointerException,提升代码可读性。
更多推荐


所有评论(0)