Java 8 到 17 新特性详解——Lambda、Stream、Optional、Record、密封类

📅 2026/6/30 5:27:52
Java 8 到 17 新特性详解——Lambda、Stream、Optional、Record、密封类
Java 8 是 Java 历史上最重要的版本引入的函数式编程彻底改变了写代码的方式。而 Java 9-17 也带来了很多实用的新特性这些在面试和日常开发中越来越常见。一、Java 8 核心新特性1. Lambda 表达式// 旧写法匿名内部类button.addActionListener(newActionListener(){OverridepublicvoidactionPerformed(ActionEvente){System.out.println(点击);}});// Lambda 写法button.addActionListener(e-System.out.println(点击));// 多行写法button.addActionListener(e-{System.out.println(点击);System.out.println(执行后续操作);});本质Lambda 是函数式接口的匿名实现。函数式接口就是只有一个抽象方法的接口FunctionalInterface。2. Stream 流ListStringnamesArrays.asList(张三,李四,王五,赵六,张三);// 传统写法过滤 去重 遍历ListStringresultnewArrayList();for(Stringname:names){if(name.startsWith(张)){if(!result.contains(name)){result.add(name);}}}for(Stringname:result){System.out.println(name);}// Stream 写法一行搞定names.stream().filter(name-name.startsWith(张)).distinct().forEach(System.out::println);常用的 Stream 操作ListUserusersgetUserList();// 1. 过滤filterusers.stream().filter(u-u.getAge()18).collect(Collectors.toList());// 2. 映射map提取某个字段ListStringnamesusers.stream().map(User::getName).collect(Collectors.toList());// 3. 排序sortedusers.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());// 4. 分组groupingByMapString,ListUserbyCityusers.stream().collect(Collectors.groupingBy(User::getCity));// 5. 聚合reduce求和inttotalAgeusers.stream().map(User::getAge).reduce(0,Integer::sum);// 6. 判断anyMatch/allMatch/noneMatchbooleanhasAdultusers.stream().anyMatch(u-u.getAge()18);booleanallAdultusers.stream().allMatch(u-u.getAge()18);// 7. 去重distinctListIntegeragesusers.stream().map(User::getAge).distinct().collect(Collectors.toList());// 8. 分页skip limitListUserpageusers.stream().skip(10)// 跳过前10条.limit(10)// 取10条.collect(Collectors.toList());Stream 注意事项stream 只能消费一次用完不能重复使用中间操作filter、map是惰性的遇到终端操作collect、forEach才执行并行流parallelStream()小心线程安全问题3. Optional——告别空指针// 以前每次都要判空UseruseruserService.findById(id);if(user!null){Stringnameuser.getName();if(name!null){System.out.println(name.toUpperCase());}}// Optional 写法Optional.ofNullable(userService.findById(id)).map(User::getName).map(String::toUpperCase).ifPresent(System.out::println);常用方法// 创建OptionalStringoptOptional.of(value);// 非空值传 null 抛异常OptionalStringoptOptional.ofNullable(nullable);// 可空值OptionalStringoptOptional.empty();// 空// 消费opt.ifPresent(val-System.out.println(val));// 有值则执行opt.ifPresentOrElse(val-{// 有值或无值各做不同事// 有值},()-{// 无值});// 取值安全Stringresultopt.orElse(默认值);// 有值返回无值返回默认Stringresultopt.orElseGet(()-computeDefault());// 延迟计算默认值Stringresultopt.orElseThrow(()-newRuntimeException(值不存在));// 转换OptionalStringupperopt.map(String::toUpperCase);OptionalIntegerlenopt.flatMap(val-Optional.of(val.length()));// 过滤OptionalStringfilteredopt.filter(val-val.startsWith(A));原则Optional 主要用于返回值不要用作参数或字段类型。二、Java 9-11 新特性1. 集合工厂方法Java 9// 以前写一堆 addListStringlistnewArrayList();list.add(a);list.add(b);list.add(c);// Java 9 以后一行搞定ListStringlistList.of(a,b,c);SetIntegersetSet.of(1,2,3);MapString,IntegermapMap.of(key1,1,key2,2);// 注意返回的是不可变集合不能增删改2. var 局部变量类型推断Java 10// 以前MapString,ListUseruserMapnewHashMap();// Java 10varuserMapnewHashMapString,ListUser();varlistList.of(a,b,c);varstreamlist.stream().filter(s-s.startsWith(a));// 注意var 只能用在局部变量不能用在成员变量、方法参数、返回值3. 增强的 try-with-resourcesJava 9// 以前资源必须在 try 里创建try(InputStreaminnewFileInputStream(file.txt)){in.read();}// Java 9可以用 final 或 effectively final 的变量InputStreaminnewFileInputStream(file.txt);try(in){in.read();}4. 字符串增强Java 11Stringstr Hello World ;str.isBlank();// true如果全是空白字符str.strip();// Hello World去除首尾空白支持全角空格str.stripLeading();// Hello World str.stripTrailing();// Hello Worldstr.repeat(3);// Hello World Hello World Hello World a\nb\nc.lines()// StreamString 按行分割.forEach(System.out::println);三、Java 14-17 新特性1. Record——数据载体Java 14 预览Java 16 正式以前写一个 POJO 类要写一堆 getter/setter/toString/equals/hashCode// 以前publicclassUserDTO{privateLongid;privateStringname;privateIntegerage;publicUserDTO(Longid,Stringname,Integerage){this.idid;this.namename;this.ageage;}// getter/setter/toString/equals/hashCode 几十行代码...}// Record一行搞定publicrecordUserDTO(Longid,Stringname,Integerage){}// 使用varusernewUserDTO(1L,张三,25);user.id();// 注意不是 getId()是 id()user.name();// name()user.toString();// UserDTO[id1, name张三, age25]Record 特点自动生成构造方法、getter注意命名风格没有 get 前缀、equals、hashCode、toString实例是不可变的字段都是 final 的适合做 DTO、VO、查询参数等纯数据载体2. 密封类——Sealed ClassJava 15 预览Java 17 正式控制哪些类可以继承它// 允许 Dog 和 Cat 继承其他类不允许publicsealedabstractclassAnimalpermitsDog,Cat{publicabstractvoidsound();}// 允许继承publicfinalclassDogextendsAnimal{Overridepublicvoidsound(){System.out.println(汪汪);}}// 允许继承publicfinalclassCatextendsAnimal{Overridepublicvoidsound(){System.out.println(喵喵);}}// ❌ 编译错误Parrot 不在 permits 列表中// public class Parrot extends Animal {}使用场景枚举类不够用、但继承又想严格控制时。比如统一的支付结果类型、订单状态等。3. 模式匹配——instanceof 增强Java 16 正式// 以前if(objinstanceofString){Stringstr(String)obj;System.out.println(str.length());}// Java 16if(objinstanceofStringstr){System.out.println(str.length());}4. 文本块Java 13 预览Java 15 正式// 以前拼接 HTML 很痛苦Stringhtmlhtml\n body\n pHello/p\n /body\n/html;// 文本块Stringhtml html body pHello/p /body /html ;5. Switch 表达式Java 14 正式// 以前Stringresult;switch(day){caseMONDAY:caseFRIDAY:result工作日;break;caseSATURDAY:caseSUNDAY:result休息日;break;default:result未知;}// Switch 表达式简洁多了Stringresultswitch(day){caseMONDAY,FRIDAY-工作日;caseSATURDAY,SUNDAY-休息日;default-未知;};// 带代码块Stringresultswitch(day){caseMONDAY-{System.out.println(周一);yield工作日;// 用 yield 返回值}caseSATURDAY,SUNDAY-休息日;default-未知;};四、版本升级建议从 Java 8 到 Java 17你的代码基本不需要大改 - Lambda、Stream、Optional 这些老写法完全兼容 - 新的语法Record、Sealed想用就用不用也不影响 - 最大的收益是性能和安全性提升GC、TLS、加密算法生产建议新项目直接用Java 17LTS 版本支持到 2029 年老项目从 Java 8 升级到 11 再到 17逐版本测试注意SpringBoot 2.x 最高支持 Java 17SpringBoot 3.x 要求 Java 17 觉得有用的话点赞 关注【张老师技术栈】吧每周更新 Java/Python/爬虫 实战干货不让你白来。