本文目录导读:

- 基础创建与获取(创建方式)
- 使用 orElse / orElseGet / orElseThrow(核心用法)
- 使用 ifPresent / ifPresentOrElse(消费)
- 使用 map 和 flatMap(转换链式操作)
- 使用 filter(过滤)
- 使用 stream(与 Stream 结合,Java 9+)
- 综合案例:用户地址查询(模拟真实业务)
- 反模式与注意事项(重要!刻意练习避免)
- JDK 版本差异总结
- 核心方法论总结
- 关键原则
Java Optional 是 Java 8 引入的一个容器类,用于优雅地处理可能为空的对象,避免 NullPointerException。
以下是各种场景下的使用案例,从简单到复杂,请认真阅读注释(注:):
基础创建与获取(创建方式)
import java.util.Optional;
public class CreateOptional {
public static void main(String[] args) {
// 1. 创建空的 Optional
Optional<String> emptyOpt = Optional.empty();
// 2. 创建非空的 Optional(传入 null 会抛异常 NPE)
Optional<String> nonEmptyOpt = Optional.of("Hello World");
// 3. 创建允许为 null 的 Optional(推荐)
Optional<String> nullableOpt = Optional.ofNullable(getDataMayBeNull());
System.out.println("emptyOpt 是否存在值: " + emptyOpt.isPresent());
System.out.println("nonEmptyOpt 的值: " + nonEmptyOpt.get());
System.out.println("nullableOpt 的值: " + nullableOpt.orElse("默认值"));
// 注:Optional.of(null) 会直接抛出 NullPointerException
// Optional.of(null); // 异常
}
private static String getDataMayBeNull() {
return null; // 模拟可能返回 null 的情况
}
}
使用 orElse / orElseGet / orElseThrow(核心用法)
import java.util.Optional;
public class OrElseDemo {
public static void main(String[] args) {
String name = null;
// 1. orElse:如果为空,返回默认值(默认值会提前创建)
String result1 = Optional.ofNullable(name)
.orElse("默认值");
System.out.println("orElse结果: " + result1);
// 2. orElseGet:如果为空,通过 Supplier 生成默认值(懒加载)
String result2 = Optional.ofNullable(name)
.orElseGet(() -> "由Supplier生成的默认值");
System.out.println("orElseGet结果: " + result2);
// 3. orElseThrow:如果为空,抛出指定的异常(Java 10+ 可带参数)
try {
Optional.ofNullable(name)
.orElseThrow(() -> new IllegalArgumentException("name 不能为空"));
} catch (Exception e) {
System.out.println("捕获异常: " + e.getMessage());
}
// 4. Java 10 新特性:orElseThrow() 无参,抛出 NoSuchElementException
// Optional.ofNullable(name).orElseThrow();
}
}
使用 ifPresent / ifPresentOrElse(消费)
import java.util.Optional;
public class IfPresentDemo {
public static void main(String[] args) {
String username = "张三";
// 1. ifPresent:值存在时执行动作
Optional.ofNullable(username)
.ifPresent(u -> System.out.println("用户名: " + u));
// 2. ifPresentOrElse(Java 9+):存在时执行动作,否则执行备用动作
Optional.ofNullable(null)
.ifPresentOrElse(
u -> System.out.println("用户名: " + u),
() -> System.out.println("用户名为空,执行备用逻辑")
);
// 3. 传统写法对比(啰嗦且易出错)
if (username != null) {
System.out.println("传统写法用户名: " + username);
}
}
}
使用 map 和 flatMap(转换链式操作)
import java.util.Optional;
public class MapDemo {
public static void main(String[] args) {
Person person = new Person("Alice", new Address("北京", "朝阳区"));
// 1. map:将 Optional 包装的值转换为另一种值
// 场景:获取用户的城市(可能为空)
String city = Optional.ofNullable(person)
.map(Person::getAddress) // 返回 Optional<Address>
.map(Address::getCity) // 返回 Optional<String>
.orElse("未知城市");
System.out.println("城市: " + city);
// 2. flatMap:如果映射结果已经是 Optional,避免嵌套 Optional
// 传统使用 map 会得到 Optional<Optional<String>>
Optional<Optional<String>> nestedOpt = Optional.ofNullable(person)
.map(Person::getAddress)
.map(address -> Optional.ofNullable(address.getStreet()));
// 使用 flatMap 扁平化
String street = Optional.ofNullable(person)
.map(Person::getAddress)
.flatMap(address -> Optional.ofNullable(address.getStreet()))
.orElse("未知街道");
System.out.println("街道: " + street);
// 3. 多个步骤的流水线
String detail = Optional.ofNullable(person)
.map(Person::getAddress)
.map(a -> a.getCity() + "-" + a.getStreet())
.orElse("无地址");
System.out.println("完整地址: " + detail);
// 4. 链式判空(多次转换不会 NPE)
String result = Optional.ofNullable(person)
.map(Person::getAddress) // 若 person 为 null,返回 Optional.empty()
.map(Address::getCity) // 若 address 为 null,返回 Optional.empty()
.map(String::toUpperCase) // 若 city 为 null,返回 Optional.empty()
.orElse("DEFAULT");
System.out.println("链式结果: " + result);
}
}
class Person {
private String name;
private Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
public Address getAddress() {
return address;
}
// getter & setter 省略
}
class Address {
private String city;
private String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
public String getCity() {
return city;
}
public String getStreet() {
return street;
}
}
使用 filter(过滤)
import java.util.Optional;
public class FilterDemo {
public static void main(String[] args) {
Integer score = 85;
// 1. 过滤:分数大于 90 才显示
Optional.ofNullable(score)
.filter(s -> s > 90)
.ifPresentOrElse(
s -> System.out.println("优秀学生成绩: " + s),
() -> System.out.println("成绩未达到90分")
);
// 2. 多条件过滤(使用 && 连接)
Optional.ofNullable(score)
.filter(s -> s >= 60 && s <= 100) // 合格范围
.filter(s -> s > 80) // 又是优秀
.ifPresent(s -> System.out.println("优良成绩: " + s));
// 3. 与 map 组合:过滤然后转换
String grade = Optional.ofNullable(score)
.filter(s -> s >= 0 && s <= 100)
.map(s -> s >= 90 ? "A" : s >= 80 ? "B" : s >= 70 ? "C" : "D")
.orElse("无效成绩");
System.out.println("成绩等级: " + grade);
}
}
使用 stream(与 Stream 结合,Java 9+)
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class StreamCombineDemo {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add(null);
names.add("Bob");
names.add("");
// 1. 过滤掉 null 和空字符串
List<String> validNames = names.stream()
.map(Optional::ofNullable) // 包装成 Optional
.flatMap(Optional::stream) // 扁平化流(空 Optional 自动跳过)
.filter(name -> !name.isEmpty())
.collect(Collectors.toList());
System.out.println("有效名称: " + validNames);
// 2. 使用 Optional 简化 null 判断
List<String> cities = new ArrayList<>();
cities.add("北京");
cities.add(null);
cities.add("上海");
cities.stream()
.map(Optional::ofNullable)
.flatMap(Optional::stream)
.forEach(System.out::println);
// 3. 传统方式对比(大量 if 判断)
for (String name : names) {
if (name != null && !name.isEmpty()) {
System.out.println("传统输出: " + name);
}
}
}
}
综合案例:用户地址查询(模拟真实业务)
import java.util.Optional;
public class UserService {
public static void main(String[] args) {
// 模拟 MySQL 查询结果
User user = findUserById(1); // 可能返回 null
// 业务需求:获取用户所在城市,如果没有用户或地址,打印"未知"
String city = Optional.ofNullable(user)
.map(User::getAddress) // 获取地址
.map(Address2::getCity) // 获取城市
.orElse("未知");
System.out.println("用户所在城市: " + city);
// 业务需求:如果是北京用户,打印欢迎语;否则打印其他
Optional.ofNullable(user)
.map(User::getAddress)
.map(Address2::getCity)
.filter(c -> "北京".equals(c))
.ifPresentOrElse(
c -> System.out.println("欢迎来到北京!"),
() -> System.out.println("您好!")
);
// 业务需求:获取用户的第一个亲戚的名字,否则默认"无亲戚"
String relative = Optional.ofNullable(user)
.map(User::getRelative)
.map(Relative::getName)
.orElse("无亲戚");
System.out.println("亲戚: " + relative);
}
private static User findUserById(int id) {
// 模拟数据库返回 null
return new User(new Address2("上海", "浦东"), new Relative("王五"));
}
}
class User {
private Address2 address;
private Relative relative;
public User(Address2 address, Relative relative) {
this.address = address;
this.relative = relative;
}
public Address2 getAddress() {
return address;
}
public Relative getRelative() {
return relative;
}
}
class Address2 {
private String city;
private String street;
public Address2(String city, String street) {
this.city = city;
this.street = street;
}
public String getCity() {
return city;
}
}
class Relative {
private String name;
public Relative(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
反模式与注意事项(重要!刻意练习避免)
import java.util.Optional;
public class AntiPatternsDemo {
public static void main(String[] args) {
String name = null;
// ❌ 反模式1:调用 get() 不判空(会抛 NoSuchElementException)
// String dangerous = Optional.ofNullable(name).get(); // 异常!
// ✅ 正确做法
String safe = Optional.ofNullable(name).orElse("默认");
// ❌ 反模式2:用 Optional 作为方法参数(不推荐,仍可能传 null)
// void setName(Optional<String> name) { ... } // 不推荐
// ✅ 推荐:方法参数直接传 null 即可,方法内部用 Optional 处理
// void setName(String name) {
// this.name = Optional.ofNullable(name).orElse("默认名");
// }
// ❌ 反模式3:滥用 isPresent() + get() 替代传统 if
if (Optional.ofNullable(name).isPresent()) {
// 仍然存在空值风险,不如直接用 if (name != null)
}
// ✅ 正确:使用 ifPresent 或 map + orElse
Optional.ofNullable(name).ifPresent(n -> System.out.println("名字: " + n));
// ❌ 反模式4:将 Optional 用作集合元素/Map键值
// Map<String, Optional<String>> map = ...; // 不建议
// ✅ 正确:Map 值直接用 null 表示不存在
// Map<String, String> map = new HashMap<>();
}
}
JDK 版本差异总结
// JDK 8: // - Optional.empty(), Optional.of(), Optional.ofNullable() // - get(), orElse(), orElseGet(), orElseThrow() // - ifPresent(), map(), flatMap(), filter() // - isPresent() // // JDK 9+ 新增: // - ifPresentOrElse(consumer, runnable) // - or(Supplier<Optional<T>>) // - stream() // // JDK 10+ 新增: // - orElseThrow() 无参版本(更简洁)
核心方法论总结
| 场景 | 推荐写法 |
|---|---|
| 需要一个默认值 | orElse("默认值") 或 orElseGet(() -> ...) |
| 需要抛异常 | orElseThrow(IllegalArgumentException::new) |
| 有值则消费 | ifPresent(...) 或 ifPresentOrElse(...) |
| 链式获取属性 | map(...).map(...).orElse(...) |
| 过滤条件 | filter(...).orElse(...) |
| 与集合结合 | flatMap(Optional::stream) |
关键原则
- 不要对
get()不加保护地调用 —— 极易抛异常。 - 不要用
Optional作为字段、方法参数、集合元素 —— 会破坏代码可读性和性能。 Optional是给返回类型用的,不是为了替代所有 null 判空。- 优先使用
ifPresent、map、orElse,减少显式条件判断。 - Java 9+ 中,可以用
ifPresentOrElse替代传统if-else。 - 谨慎使用
map返回Optional时,考虑flatMap避免嵌套。
通过以上案例,你应该能熟练用 Optional 写出健壮、简洁、无空指针异常的代码!
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播