当前位置: 首页 > news >正文

32 Optional与新API

目录

  • 🟠 32 Optional与新API
    • 1. Optional类
      • 1.1 为什么需要Optional
      • 1.2 创建Optional
      • 1.3 常用方法
    • 2. Optional最佳实践
      • 2.1 ✅ 推荐用法
      • 2.2 ❌ 避免用法
      • 2.3 使用场景对比
    • 3. 记录类Record
      • 3.1 什么是Record
      • 3.2 Record特性
      • 3.3 Record限制
      • 3.4 使用场景
    • 4. 密封类Sealed
      • 4.1 什么是密封类
      • 4.2 修饰符说明
      • 4.3 配合switch模式匹配
      • 4.4 接口密封
    • 5. var局部变量
      • 5.1 基本用法
      • 5.2 使用限制
      • 5.3 最佳实践
    • 6. 其他新API
      • 6.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){Addressaddr=user.getAddress();if(addr!=null){Citycity=addr.getCity();if(city!=null){returncity.getName();}}}return"Unknown";}// 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会抛NPEOptional<String>opt=Optional.of(null);// ✅ 正确:允许nullOptional<String>opt=Optional.ofNullable(null);// Optional.empty()// ✅ 正确:非null值Optional<String>opt=Optional.ofNullable("Hello");// Optional[Hello]

1.3 常用方法

Optional<String>opt=Optional.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);// 满足条件保留,否则empty

2. Optional最佳实践

2.1 ✅ 推荐用法

// 1. 方法返回值publicOptional<User>findById(Longid){returnOptional.ofNullable(userMapper.selectById(id));}// 2. 链式调用Stringresult=Optional.ofNullable(user).map(User::getAddress).map(Address::getCity).map(City::getName).orElse("Unknown");// 3. Stream中使用List<String>names=users.stream().map(User::getName).flatMap(Optional::stream)// Java 9+.collect(Collectors.toList());// 4. or() 方法 (Java 9+)Optional<String>result=opt1.or(()->opt2).or(()->opt3);

2.2 ❌ 避免用法

// ❌ 1. 不要用于方法参数publicvoidprocess(Optional<String>name){}// 错误用法// ❌ 2. 不要用于字段publicclassUser{privateOptional<String>name;// 错误用法}// ❌ 3. 不要用于集合Optional<List<String>>list;// 应该用空集合代替// ❌ 4. 不要直接get()不检查opt.get();// 可能抛异常,用orElse代替

2.3 使用场景对比

场景推荐方式
方法可能返回无值返回Optional<T>
变量可能为null使用Optional.ofNullable()
链式调用可能中断map()+orElse()
参数可能为空直接用null + null检查
集合可能为空返回空集合,不用Optional

3. 记录类Record

3.1 什么是Record

Record 是 Java 16 正式引入的不可变数据类,自动生成构造器、getter、equals、hashCode、toString。

// 传统写法(50+行)publicclassPoint{privatefinalintx;privatefinalinty;publicPoint(intx,inty){this.x=x;this.y=y;}publicintgetX(){returnx;}publicintgetY(){returny;}@Overridepublicbooleanequals(Objecto){if(this==o)returntrue;if(o==null||getClass()!=o.getClass())returnfalse;Pointpoint=(Point)o;returnx==point.x&&y==point.y;}@OverridepublicinthashCode(){returnObjects.hash(x,y);}@OverridepublicStringtoString(){return"Point{x="+x+", y="+y+"}";}}// Record写法(1行)publicrecordPoint(intx,inty){}

3.2 Record特性

publicrecordUser(Stringname,intage,Stringemail){// 紧凑构造器(参数校验)publicUser{if(age<0)thrownewIllegalArgumentException("年龄不能为负");if(!email.contains("@"))thrownewIllegalArgumentException("邮箱格式错误");}// 自定义方法publicStringdisplay(){returnname+" ("+age+")";}// 静态字段和方法publicstaticUserUNKNOWN=newUser("Unknown",0,"");publicstaticUserof(Stringname){returnnewUser(name,0,"");}}

3.3 Record限制

限制说明
不能继承其他类隐式继承java.lang.Record
不能被继承隐式final
字段都是final不可变
不能有实例字段只能有record header中声明的字段
可以实现接口✅ 允许
可以有静态字段/方法✅ 允许

3.4 使用场景

// DTO/VOpublicrecordUserDTO(Longid,Stringname,Stringemail){}// 方法返回多个值publicrecordPair<A,B>(Afirst,Bsecond){}// Map的KeypublicrecordCacheKey(Stringprefix,Longid){}// 事件对象publicrecordOrderEvent(LongorderId,Stringtype,LocalDateTimetime){}

4. 密封类Sealed

4.1 什么是密封类

密封类限制哪些类可以继承/实现它,配合switch模式匹配使用。

// Java 17 正式特性publicsealedclassShapepermitsCircle,Rectangle,Triangle{// ...}publicfinalclassCircleextendsShape{privatefinaldoubleradius;// ...}publicfinalclassRectangleextendsShape{privatefinaldoublewidth,height;// ...}publicnon-sealedclassTriangleextendsShape{// non-sealed: 允许任意继承privatefinaldoublea,b,c;// ...}

4.2 修饰符说明

修饰符含义
sealed密封类,必须指定permits
permits列出允许的子类
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(List<JsonValue>values)implementsJsonValue{}publicrecordJsonObject(Map<String,JsonValue>entries)implementsJsonValue{}publicrecordJsonNull()implementsJsonValue{}

5. var局部变量

5.1 基本用法

// Java 10 引入的局部变量类型推断varlist=newArrayList<String>();// 推断为 ArrayList<String>varmap=Map.of("key","value");// 推断为 Map<String, String>varstream=list.stream();// 推断为 Stream<String>// 等价于ArrayList<String>list=newArrayList<String>();

5.2 使用限制

// ✅ 可以用varname="Hello";// 局部变量varlist=newArrayList<>();// 初始化时// ❌ 不能用varx;// 必须初始化vary=null;// 无法推断类型varz={1,2,3};// 数组字面量varw=()->{};// Lambda// 类字段、方法参数、返回类型都不能用var

5.3 最佳实践

// ✅ 推荐:类型冗长时varentries=map.entrySet();// 比 Set<Map.Entry<K,V>> 简洁variterator=list.iterator();// ❌ 不推荐:类型不明显时varresult=process();// 返回类型不明确,降低可读性// ✅ for循环中使用for(varentry:map.entrySet()){System.out.println(entry.getKey()+": "+entry.getValue());}for(vari=0;i<10;i++){System.out.println(i);}// ✅ try-with-resourcestry(varreader=newBufferedReader(newFileReader("file.txt"))){// ...}

6. 其他新API

6.1 String 新方法

// Java 11+" ".isBlank();// true (Java 11)" ".isEmpty();// false"Hello".strip();// 去除首尾空白(含Unicode空白)"Hello".stripLeading();// 去除首部空白"Hello".stripTrailing();// 去除尾部空白"Hello".repeat(3);// "HelloHelloHello""A\nB\nC".lines();// Stream<String>"A\nB\nC".lines().count();// 3// Java 12+"Hello".indent(4);// 每行前加4个空格"Hello".transform(s->s+"!");// 链式转换

6.2 集合新方法

// Java 9+List.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 10+List.copyOf(set);// 从其他集合复制Set.copyOf(list);// Java 16+List.of(1,2,3).toArray(Integer[]::new);// 指定类型数组

6.3 InputStream 新方法

// Java 9+InputStreamis=newByteArrayInputStream("Hello".getBytes());is.readAllBytes();// 读取所有字节// Java 11+Pathpath=Path.of("file.txt");Stringcontent=Files.readString(path);// 读取文件为字符串Files.writeString(path,"Hello World");// 写入字符串到文件Path.of("file.txt").toAbsolutePath();// 转绝对路径

6.4 HttpClient (Java 11+)

// 同步请求HttpClientclient=HttpClient.newHttpClient();HttpRequestrequest=HttpRequest.newBuilder().uri(URI.create("https://api.example.com/data")).header("Accept","application/json").GET().build();HttpResponse<String>response=client.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优雅处理null
var10局部变量类型推断
String新方法11strip/lines/isBlank
HttpClient11HTTP客户端
Record16不可变数据类
Sealed17限制继承体系
switch模式匹配21增强switch

💬 你在项目中用过哪些Java新特性?Optional有没有帮你减少NullPointerException?

📌 下一篇我们将学习设计模式精讲,用Java源码理解经典模式!


📚 参考资料

  • Java 官方文档 - Optional
  • Java 官方文档 - Record
  • Java 官方文档 - Sealed Classes
http://www.cnnetsun.cn/news/2889961.html

相关文章:

  • Windows Cleaner:专治C盘爆红的Windows系统优化神器
  • 告别绘图困扰:5分钟掌握免费在线图表工具,让代码秒变精美图表
  • 5分钟掌握QQ音乐格式转换:Mac用户的终极解密工具指南
  • # 本地缓存突发雪崩?海归IT留学生一键改写随机过期时间防线「蒸汽求职分享」
  • ARM7微控制器MAC71x4架构解析:eDMA与智能外设协同设计实战
  • Sub-1 GHz无线MCU KW0x:远距离低功耗物联网连接的核心技术解析
  • 太和智慧养老系统 - 开启养老信息化新时代 #06121259
  • CSS 逻辑属性与容器查询:现代响应式布局的工程实践
  • 拆解随身Wi-Fi核心硬件:看懂小设备里的大科技
  • 终极指南:如何为欧洲卡车模拟2安装智能自动驾驶插件
  • 2026年GEO优化系统推荐:5款产品横评与选型避坑指南
  • 汽车电子核心:MPC5604P MCU架构解析与电机控制实战
  • MPC8360E通信处理器:异构架构与QUICC Engine硬件加速深度解析
  • 计算机毕业设计之django招聘信息分析与求职系统app
  • Onekey Steam Depot清单下载工具:三步搞定Steam游戏清单的终极教程
  • 吉他面板工艺怎么看?附主流入门吉他参数对比
  • 3分钟解锁Beyond Compare 5完整功能的终极指南:告别评估限制
  • 3分钟快速上手Glass浏览器:解锁Windows桌面浮动透明浏览体验 [特殊字符]
  • 老旧电视重获新生:MyTV-Android开源直播解决方案终极指南
  • VC6环境下可直接运行的水库动态规划调度计算程序(含源码与完整工程)
  • C++(倍增法)
  • 园世骨传导运动耳机:重塑运动听音的科学与艺术
  • AI专著撰写指南:10分钟上手AI工具,快速生成20万字专著书稿
  • 高压BMS参考设计解析:ASIL D安全架构与ETPL通信实战
  • i.MX 6SLL嵌入式处理器:低功耗应用处理器架构解析与实战设计指南
  • 3步实现Python自动化剪映:告别重复剪辑的终极方案
  • Windows 11任务栏拖放功能终极修复指南:3分钟恢复高效工作流
  • 一场 ACBC 赛事,依托 APAxpo 平台实现职业弯道超车
  • DownKyi:解锁B站视频下载的5个专业级技巧,让离线观看更简单
  • 高性能NFC控制器PN7220:从原理到支付终端设计的实战指南