32 Optional与新API 目录 32 Optional与新API1. Optional类1.1 为什么需要Optional1.2 创建Optional1.3 常用方法2. Optional最佳实践2.1 ✅ 推荐用法2.2 ❌ 避免用法2.3 使用场景对比3. 记录类Record3.1 什么是Record3.2 Record特性3.3 Record限制3.4 使用场景4. 密封类Sealed4.1 什么是密封类4.2 修饰符说明4.3 配合switch模式匹配4.4 接口密封5. var局部变量5.1 基本用法5.2 使用限制5.3 最佳实践6. 其他新API6.1 String 新方法6.2 集合新方法6.3 InputStream 新方法6.4 HttpClient (Java 11)7. 总结 参考资料 32 Optional与新API 更新于 2026年6月 | ✍️ 原创文章转载请注明出处1. Optional类1.1 为什么需要Optional// 传统写法层层null检查publicStringgetCity(Useruser){if(user!null){Addressaddruser.getAddress();if(addr!null){Citycityaddr.getCity();if(city!null){returncity.getName();}}}returnUnknown;}// Optional写法publicStringgetCity(Useruser){returnOptional.ofNullable(user).map(User::getAddress).map(Address::getCity).map(City::getName).orElse(Unknown);}1.2 创建Optional方法说明使用场景Optional.of(value)非null值确定不为null时Optional.ofNullable(value)可能为null不确定时Optional.empty()空Optional表示无值// ❌ 错误传null会抛NPEOptionalStringoptOptional.of(null);// ✅ 正确允许nullOptionalStringoptOptional.ofNullable(null);// Optional.empty()// ✅ 正确非null值OptionalStringoptOptional.ofNullable(Hello);// Optional[Hello]1.3 常用方法OptionalStringoptOptional.ofNullable(getName());// 获取值opt.get();// 直接获取为空抛NoSuchElementExceptionopt.orElse(default);// 为空返回默认值opt.orElseGet(()-generateDefault());// 为空执行Supplieropt.orElseThrow(()-newRuntimeException(name is null));// 为空抛异常// 判断opt.isPresent();// 是否有值opt.isEmpty();// 是否为空 (Java 11)// 消费opt.ifPresent(name-System.out.println(name));opt.ifPresentOrElse(name-System.out.println(Name: name),()-System.out.println(Name is null));// 转换opt.map(String::toUpperCase);// 转换值opt.flatMap(s-Optional.of(s.toUpperCase()));// 转换为Optional// 过滤opt.filter(s-s.length()3);// 满足条件保留否则empty2. Optional最佳实践2.1 ✅ 推荐用法// 1. 方法返回值publicOptionalUserfindById(Longid){returnOptional.ofNullable(userMapper.selectById(id));}// 2. 链式调用StringresultOptional.ofNullable(user).map(User::getAddress).map(Address::getCity).map(City::getName).orElse(Unknown);// 3. Stream中使用ListStringnamesusers.stream().map(User::getName).flatMap(Optional::stream)// Java 9.collect(Collectors.toList());// 4. or() 方法 (Java 9)OptionalStringresultopt1.or(()-opt2).or(()-opt3);2.2 ❌ 避免用法// ❌ 1. 不要用于方法参数publicvoidprocess(OptionalStringname){}// 错误用法// ❌ 2. 不要用于字段publicclassUser{privateOptionalStringname;// 错误用法}// ❌ 3. 不要用于集合OptionalListStringlist;// 应该用空集合代替// ❌ 4. 不要直接get()不检查opt.get();// 可能抛异常用orElse代替2.3 使用场景对比场景推荐方式方法可能返回无值返回OptionalT变量可能为null使用Optional.ofNullable()链式调用可能中断map()orElse()参数可能为空直接用null null检查集合可能为空返回空集合不用Optional3. 记录类Record3.1 什么是RecordRecord 是 Java 16 正式引入的不可变数据类自动生成构造器、getter、equals、hashCode、toString。// 传统写法50行publicclassPoint{privatefinalintx;privatefinalinty;publicPoint(intx,inty){this.xx;this.yy;}publicintgetX(){returnx;}publicintgetY(){returny;}Overridepublicbooleanequals(Objecto){if(thiso)returntrue;if(onull||getClass()!o.getClass())returnfalse;Pointpoint(Point)o;returnxpoint.xypoint.y;}OverridepublicinthashCode(){returnObjects.hash(x,y);}OverridepublicStringtoString(){returnPoint{xx, yy};}}// Record写法1行publicrecordPoint(intx,inty){}3.2 Record特性publicrecordUser(Stringname,intage,Stringemail){// 紧凑构造器参数校验publicUser{if(age0)thrownewIllegalArgumentException(年龄不能为负);if(!email.contains())thrownewIllegalArgumentException(邮箱格式错误);}// 自定义方法publicStringdisplay(){returnname (age);}// 静态字段和方法publicstaticUserUNKNOWNnewUser(Unknown,0,);publicstaticUserof(Stringname){returnnewUser(name,0,);}}3.3 Record限制限制说明不能继承其他类隐式继承java.lang.Record不能被继承隐式final字段都是final不可变不能有实例字段只能有record header中声明的字段可以实现接口✅ 允许可以有静态字段/方法✅ 允许3.4 使用场景// DTO/VOpublicrecordUserDTO(Longid,Stringname,Stringemail){}// 方法返回多个值publicrecordPairA,B(Afirst,Bsecond){}// Map的KeypublicrecordCacheKey(Stringprefix,Longid){}// 事件对象publicrecordOrderEvent(LongorderId,Stringtype,LocalDateTimetime){}4. 密封类Sealed4.1 什么是密封类密封类限制哪些类可以继承/实现它配合switch模式匹配使用。// Java 17 正式特性publicsealedclassShapepermitsCircle,Rectangle,Triangle{// ...}publicfinalclassCircleextendsShape{privatefinaldoubleradius;// ...}publicfinalclassRectangleextendsShape{privatefinaldoublewidth,height;// ...}publicnon-sealedclassTriangleextendsShape{// non-sealed: 允许任意继承privatefinaldoublea,b,c;// ...}4.2 修饰符说明修饰符含义sealed密封类必须指定permitspermits列出允许的子类final不能被继承non-sealed可以被任意继承开放abstract抽象类4.3 配合switch模式匹配// Java 21 正式特性publicdoublearea(Shapeshape){returnswitch(shape){caseCirclec-Math.PI*c.radius()*c.radius();caseRectangler-r.width()*r.height();caseTrianglet-{doubles(t.a()t.b()t.c())/2;yieldMath.sqrt(s*(s-t.a())*(s-t.b())*(s-t.c()));}// 不需要default编译器知道所有子类};}4.4 接口密封publicsealedinterfaceJsonValuepermitsJsonString,JsonNumber,JsonArray,JsonObject,JsonNull{}publicrecordJsonString(Stringvalue)implementsJsonValue{}publicrecordJsonNumber(doublevalue)implementsJsonValue{}publicrecordJsonArray(ListJsonValuevalues)implementsJsonValue{}publicrecordJsonObject(MapString,JsonValueentries)implementsJsonValue{}publicrecordJsonNull()implementsJsonValue{}5. var局部变量5.1 基本用法// Java 10 引入的局部变量类型推断varlistnewArrayListString();// 推断为 ArrayListStringvarmapMap.of(key,value);// 推断为 MapString, Stringvarstreamlist.stream();// 推断为 StreamString// 等价于ArrayListStringlistnewArrayListString();5.2 使用限制// ✅ 可以用varnameHello;// 局部变量varlistnewArrayList();// 初始化时// ❌ 不能用varx;// 必须初始化varynull;// 无法推断类型varz{1,2,3};// 数组字面量varw()-{};// Lambda// 类字段、方法参数、返回类型都不能用var5.3 最佳实践// ✅ 推荐类型冗长时varentriesmap.entrySet();// 比 SetMap.EntryK,V 简洁variteratorlist.iterator();// ❌ 不推荐类型不明显时varresultprocess();// 返回类型不明确降低可读性// ✅ for循环中使用for(varentry:map.entrySet()){System.out.println(entry.getKey(): entry.getValue());}for(vari0;i10;i){System.out.println(i);}// ✅ try-with-resourcestry(varreadernewBufferedReader(newFileReader(file.txt))){// ...}6. 其他新API6.1 String 新方法// Java 11 .isBlank();// true (Java 11) .isEmpty();// falseHello.strip();// 去除首尾空白含Unicode空白Hello.stripLeading();// 去除首部空白Hello.stripTrailing();// 去除尾部空白Hello.repeat(3);// HelloHelloHelloA\nB\nC.lines();// StreamStringA\nB\nC.lines().count();// 3// Java 12Hello.indent(4);// 每行前加4个空格Hello.transform(s-s!);// 链式转换6.2 集合新方法// Java 9List.of(1,2,3);// 不可变ListSet.of(a,b);// 不可变SetMap.of(k1,v1,k2,v2);// 不可变MapMap.ofEntries(Map.entry(k1,v1),Map.entry(k2,v2));// Java 10List.copyOf(set);// 从其他集合复制Set.copyOf(list);// Java 16List.of(1,2,3).toArray(Integer[]::new);// 指定类型数组6.3 InputStream 新方法// Java 9InputStreamisnewByteArrayInputStream(Hello.getBytes());is.readAllBytes();// 读取所有字节// Java 11PathpathPath.of(file.txt);StringcontentFiles.readString(path);// 读取文件为字符串Files.writeString(path,Hello World);// 写入字符串到文件Path.of(file.txt).toAbsolutePath();// 转绝对路径6.4 HttpClient (Java 11)// 同步请求HttpClientclientHttpClient.newHttpClient();HttpRequestrequestHttpRequest.newBuilder().uri(URI.create(https://api.example.com/data)).header(Accept,application/json).GET().build();HttpResponseStringresponseclient.send(request,HttpResponse.BodyHandlers.ofString());System.out.println(response.statusCode());System.out.println(response.body());// 异步请求client.sendAsync(request,HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).thenAccept(System.out::println);7. 总结特性Java版本用途Optional8优雅处理nullvar10局部变量类型推断String新方法11strip/lines/isBlankHttpClient11HTTP客户端Record16不可变数据类Sealed17限制继承体系switch模式匹配21增强switch 你在项目中用过哪些Java新特性Optional有没有帮你减少NullPointerException 下一篇我们将学习设计模式精讲用Java源码理解经典模式 参考资料Java 官方文档 - OptionalJava 官方文档 - RecordJava 官方文档 - Sealed Classes