当前位置: 首页 > 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.jsqmd.com/news/999087/

相关文章:

  • Navicat Mac版无限试用重置工具:3种简单方法实现永久免费使用
  • 小学数学错题自动整理的学习工具有哪些?推荐小猿AI——从错题整理到夯实巩固一步到位 - Top品牌推荐官
  • 毕业证丢失去哪里补办?一文教你轻松搞定! - 慧办好
  • 从零实现 RESTful TodoList:吃透接口思想与 RESTful 设计规范
  • ETS2LA:欧洲卡车模拟2智能驾驶辅助系统完全指南
  • C#写的Windows任务管理器源码包,带x86/x64双架构可执行文件
  • 2026自贡建筑材料检测权威机构排行 TOP 建材检测 + 见证取样 + 主体结构检测 附电话地址 - 中检检测集团
  • THPX信号源:从公开信息出发,观察市场覆盖与外汇行情信息呈现
  • 2026岳阳建筑材料检测权威机构排行 TOP 建材检测 + 见证取样 + 主体结构检测 附电话地址 - 中检检测集团
  • 指纹浏览器:MediaDevices 枚举指纹的伪装策略
  • MATLAB中RGB与HSL双向转换的轻量函数集(含向量化实现)
  • 广东力衡包装有限公司,国内礼盒定制公司,布局广东佛山,服务全国市场 - 十大品牌榜
  • 2026阳泉商户及市民高频选择的 5 家食品检测第三方机构实地测评整理 - 科信检测
  • PyTorch版ECG信号处理与分类工具集:含滤波、节律识别模型及CinC2022训练支持
  • 2026年 IT运维公司推荐榜单:专业服务商精选,企业数字化与系统稳定运维实力派之选 - 品牌发掘
  • 创业团队消息队列选型:从 Kafka 到 NATS 的成本收益分析
  • 2026年6月深圳黄金回收靠谱门店 安全变现避坑全指南 - 奢侈品回收测评
  • 从voxblox到nvblox:手把手教你用GPU加速搞定机器人路径规划中的ESDF地图
  • MoneyPrinterTurbo安装说明(小白版)
  • MPC5567微控制器:汽车与工业控制领域的经典架构与实战解析
  • 《元创力》纪实录·卷宗2.2同一本账:当赢与输成为同一块试金石
  • 2026中山本地人认可的 5 家户外广告设施检测机构实地测评汇总+市民高频选择 - 中安检测集团
  • Cline 接入 TokenPony 教程
  • 2026兴安盟本地人认可的 5 家户外广告设施检测机构实地测评汇总+市民高频选择 - 中安检测集团
  • 不止于拼接:讯维自定义拼控如何打造极致可视化体验
  • HiveSQL学习
  • 告别网盘下载限速!九大平台直链下载助手LinkSwift终极指南
  • 2026国内GEO服务商代理推荐:AI搜索时代的源头合作选型与合伙人权益深度解析 - 企业新闻快传
  • 别再只用clock()了!C/C++性能测试:串行并行场景下的三种计时方法实测与避坑
  • StreamFX插件:7个超实用技巧让你的OBS直播效果提升300%