使用Optional(爪哇)
本文最后更新于 2025-03-07,文章超过7天没更新,应该是已完结了~
一、Optional是什么?
你有没有遇到过代码里突然蹦出个“空指针异常”(NullPointerException),然后一脸懵逼地去找哪里出了问题?Java里的Optional就是为了解决这个问题来的。它就像一个“盒子”,专门用来装可能会为空的东西。它逼着你老老实实面对“这个东西可能是空的”这件事,而不是稀里糊涂地用下去,最后程序崩了才后悔。
简单说,Optional是个容器,里面可以装任何东西(比如字符串、数字、对象),也可以啥都不装(null)。它提供了一堆方便的方法,让你操作这个盒子里的东西时更安全。比如,你可以用它的方法检查盒子里有没有货,或者没货时给个默认值,甚至直接报错提醒自己。
而且,Optional还能跟现在流行的“函数式编程”搭上关系。你可以用Lambda表达式或者Stream这些酷炫的东西跟它玩在一起,写出来的代码看起来更简洁,不用老写一堆if (东西 != null)这种烦人的检查。
二、Optional对象的方法
咱们先搭个小场景,假设有两个类:一个是User(用户),一个是UserRepository(用户仓库)。User就是个简单的人,有name(名字)和fullName(全名);UserRepository是个找人的地方,你给它一个名字,它帮你找对应的人,找不到就返回空。
1. 检查盒子里有没有东西:isPresent 和 isEmpty
isPresent:问“盒子里有东西吗?”有就返回true,没有就false。
isEmpty:问“盒子是空的吗?”空就true,不空就false。
例子:
Optional<Object> box = Optional.empty(); // 造一个空盒子
System.out.println(box.isPresent()); // false,啥也没有
System.out.println(box.isEmpty()); // true,确实是空的
2. 怎么造盒子:empty、of、ofNullable
empty():造一个空盒子,啥也不装。
Optional<Object> box = Optional.empty(); // 空的,很干脆
of():装个肯定不为空的东西进去。如果东西是空的(null),它会生气,直接抛异常(NullPointerException)。
String name = "Peter";
Optional<String> box = Optional.of(name); // 装了个"Peter",放心用
ofNullable():装个可能为空的东西。如果是null也没关系,不会发脾气。
String name = null;
Optional<String> box = Optional.ofNullable(name); // 装了个null,没事
3. 怎么拿东西:get、orElse、orElseGet、orElseThrow
get():直接掏盒子里的东西。如果盒子是空的,它会报错(NoSuchElementException),提醒你“没货啊!”。
Optional<String> box = Optional.of("Peter"); String name = box.get(); // 拿到"Peter"
orElse():掏东西,没货就给个备胎。
UserRepository repo = new UserRepository();
Optional<User> user = repo.findUserByName("Peter2"); // 找不到这个人
User backup = user.orElse(new User("Stark", "Tony Stark")); // 用备胎Tony Stark
orElseGet():跟orElse差不多,但更聪明。备胎只有在真没货时才会被造出来,省资源。
User backup = user.orElseGet(() -> new User("Stark", "Tony Stark")); // 没货才造Tony
orElseThrow():没货就发脾气,扔个你指定的异常出来。
user.orElseThrow(() -> new RuntimeException("找不到人!")); // 没货就报错
4. 判断后干活:ifPresent、ifPresentOrElse、filter
ifPresent():盒子里有货就干活,没货就啥也不干,不报错。
Optional<User> user = repo.findUserByName("Peter2");
user.ifPresent(u -> System.out.println(u.getFullName())); // 没货就安静地啥也不干
ifPresentOrElse():有货干这个,没货干那个。
user.ifPresentOrElse( u -> System.out.println(u.getFullName()), // 有货打印全名
() -> System.out.println("找不到人")); // 没货说句话
filter():检查盒子里的东西符不符合条件,符合就留着,不符合就变空盒子。
Optional<User> user = repo.findUserByName("Peter");
Optional<User> filtered = user.filter(u -> u.getFullName().equals("Peter Parker"));
System.out.println(filtered.isPresent()); // true,Peter Parker符合条件
5. 转换东西:map 和 flatMap
假设getFullName返回的是Optional<String>:
public Optional<String> getFullName() { return Optional.ofNullable(fullName); }
map():把盒子里的东西拿出来加工一下,再装回新盒子。没货就不加工。
Optional<User> user = repo.findUserByName("Peter");
Optional<String> fullName = user.map(User::getFullName); // 拿到Optional<Peter Parker>
flatMap():专门对付盒子里还有盒子的情况,把嵌套的盒子压平。--->比map多拆一层
Optional<String> fullName = user.flatMap(User::getFullName); // 直接拿到Peter Parker
区别:map适合简单加工,flatMap适合处理嵌套的Optional。
6. 变成流水线:stream
把Optional变成Stream,方便做流操作。有货就加工,没货就空流水线。
Optional<User> user = repo.findUserByName("Peter");
user.map(User::getName).stream().forEach(System.out::println); // 输出"Peter"
三、啥时候别用Optional?
别用在类的字段里:会占更多内存,还让序列化变麻烦。
别用在方法参数里:会让方法不好懂,用起来也麻烦。
别用在构造器参数里:强迫别人造Optional,还不如多写几个构造器。
别用在集合里:集合本身就能处理空的情况,不需要再包一层。
别老用get():没货就报错,还不如用orElse这种安全的。
- 感谢你赐予我前进的力量