Java 常用新语法简介

📅 2026/7/19 9:53:54 👁️ 阅读次数 📝 编程学习
Java 常用新语法简介

参考资料

  1. Java 11 升Java 17 重要特性必读
  2. Java 21新機能まとめ

目录

  • 一. 字符串
    • 1.1 文本块
    • 1.2 String
  • 二. Optional 与 Stream
  • 三. 集合
    • 3.1 `.of()`方法
    • 3.2 SequencedCollection接口
  • 四. Switch表达式
  • 五. instanceof匹配模式
  • 六. 变量
  • 七. Record
  • 八. 虚拟线程
    • 8.1 示例1
    • 8.2 示例2
    • 8.3 示例3

一. 字符串

1.1 文本块

🔷JDK15出现的新语法

  • 文本块,是一个多行字符串,它可以避免使用大多数转义符号,自动以可预测的方式格式化字符串,并让开发人员在需要时可以控制格式。
importjava.text.MessageFormat;// 可以看到,无需添加额外的换行符,看起来也更加直观Stringcontent=""" 下記情報より入館準備作業をお願い致します。 (1)契約者申請日: {0} (2)契約社員名: {1} (3)会社名(BP社員側):{2} ※IDカード作成するためBP社員の顔写真は下記アドレスに置いています。 格納先:\\\\192.168.255.245\\XXX社内情報\\104_IDカード(全社)\\☆☆新規依頼ID写真格納フォルダ☆☆ """;// 邮件中需要用到的参数String[]params={// {0} => 契約者申請日"2023/05/16",// {1} => 契約社員名"贾飞天",// {2} => 会社名(BP社員側)"ZY株式会社"};StringmailContent=MessageFormat.format(content,params);System.out.println(mailContent);/* 下記情報より入館準備作業をお願い致します。 (1)契約者申請日: 2023/05/16 (2)契約社員名: 贾飞天 (3)会社名(BP社員側):ZY株式会社 ※IDカード作成するためBP社員の顔写真は下記アドレスに置いています。 格納先:\\192.168.255.245\XXX社内情報\104_IDカード(全社)\☆☆新規依頼ID写真格納フォルダ☆☆ */
  • 也可以使用.formatted()方法来格式化文本块
  • 下面这种写法,上下两个"""对齐,因此不会产生额外的空格
Stringname="Tom";intage=18;Stringtext=""" name : %s age : %d """.formatted(name,age);System.out.println(text);

1.2 String

🔷JDK11对String增加了新的方法

  • 判断是否为空字符串
" ".isBlank()
  • 按行进行切分
List<String>list="123\n456".lines().toList();System.out.println(list);// [123, 456]
  • 将字符串重负指定的次数
"-".repeat(10)

二. Optional 与 Stream

🔷JDK11对Optional进行了增强

// JDK11之前!optional.isPresent()// JDK11之后optional.isEmpty()

🔷JDK16提供了Stream直接转换为List的方法

// JDK16之前的写法List<String>list1="123\n456".lines().collect(Collectors.toList());// JDK16之后的写法List<String>list2="123\n456".lines().toList();

三. 集合

3.1.of()方法

🔷JDK9之后出现的创建集合的工厂方法,创建的是不可变集合。

List.of(...)Map.of(...)Set.of(...)

3.2 SequencedCollection接口

Java 中很多集合其实都是有顺序(Sequence)的,例如:

  • ArrayList
  • LinkedList
  • Vector
  • ArrayDeque
  • LinkedHashSet
  • TreeSet

但是它们以前没有统一的接口来表示有顺序,Java 21为了解决这个问题,引入了SequencedCollection,这样所有有顺序的集合都有统一的 API。
可以把 SequencedCollection 理解为所有具有确定顺序的集合的统一接口。它最大的价值并不是增加了新的能力,而是把 List、Deque、有序 Set 等原本风格不一致的 API 统一了,让泛型代码更简洁、更一致。

Collection │ └── SequencedCollection │ ├── List ├── Deque └── SortedSet(通过 SequencedSet)
  • 示例如下:
importjava.util.SequencedCollection;SequencedCollection<String>list=newArrayList<>(List.of("A","B","C"));Stringfirst=list.getFirst();Stringlast=list.getLast();list.addFirst("Z");list.addLast("D");list.removeFirst();list.removeLast();

四. Switch表达式

🔷JDK14之后提供的新特性

  • 定义一个枚举类
importjava.util.Arrays;publicenumCategoryType{老师("1"),学生("2"),家属("3"),外派("4"),领导("5"),其他("6");privateStringcode;CategoryType(Stringcode){this.code=code;}publicStringgetCode(){returncode;}publicstaticCategoryTypefromCode(Stringcode){returnArrays.stream(CategoryType.values()).filter(item->item.code.equals(code)).findAny().orElse(null);}}
  • 使用新的Switch表达式
// 成员codeStringtypeCode="1";// 根据成员code获取对应的枚举类对象CategoryTypecategoryType=CategoryType.fromCode(typeCode);Stringresult=switch(categoryType){// 当枚举类的对象为 老师、学生、领导的时候,走这个分支case老师,学生,领导->"学校内部成员, 该成员的身份为: "+categoryType.name();case家属,外派->"学校外部成员, 该成员的身份为: "+categoryType.name();case其他->"其他成员, 该成员的身份为: "+categoryType.name();default->"该成员不存在";};System.out.println(result);// 学校内部成员, 该成员的身份为: 老师
Stringday="MON";Stringresult=switch(day){case"MON"->"工作日";case"SAT","SUN"->"休息日";default->"未知";};System.out.println(result);

五. instanceof匹配模式

🔷JDK16之后提供的新特性

importlombok.Builder;importlombok.Data;@Data@BuilderpublicclassStudent{privateStringname;privateStringage;privateStringaddress;}
// 用过构建者方法创建一个对象,为了测试,将类型指定为Object类型Objectstudent=Student.builder().age("10").address("地球").name("贾飞天").build();// JDK16之前的写法: 判断之后,需要手动进行转换if(studentinstanceofStudent){Studentstu=(Student)student;Stringname=stu.getName();System.out.println("名字是: "+name);// 名字是: 贾飞天}// JDK16之后的写法: 如果通过类型检查之后,可以自动进行类型转换if(studentinstanceofStudentstu){Stringname=stu.getName();System.out.println("名字是: "+name);// 名字是: 贾飞天}/** * if条件中有 && 运算符时,当 instanceof 类型匹配成功,模式局部变量的作用范围也可以相应延长 * 注意: 仅限于 && 运算符, || 运算符时使用会有问题 */if(studentinstanceofStudentstu&&!ObjectUtils.isEmpty(stu.getName())){Stringname=stu.getName();System.out.println("名字是: "+name);// 名字是: 贾飞天}

六. 变量

🔷JDK10之后,使用var关键字的话,编译器自动推断类型。

varname="Tom";varlist1=newArrayList<String>();

七. Record

🔷详情请参考下面这篇文章:

  • Java record类用法简介

八. 虚拟线程

🔷jdk21新增,虚拟线程的目标不是让单个任务执行得更快,而是为了提高系统吞吐量(Throughput),尤其适合I/O密集型任务。

  • 传统线程:创建一个 Java 线程,就会对应创建一个操作系统线程。
JavaThread│ ▼OSThread(操作系统线程)
  • 虚拟线程:JVM 会自动把大量虚拟线程调度到少量真正的操作系统线程上运行。
    • 创建线程几乎没有成本
    • 可以创建几十万甚至几百万个线程
    • 非常适合大量 I/O 操作
VirtualThread│ ▼JVMScheduler│ ▼ 少量OSThreadCarrierThread// 例如:100000VirtualThread│ ▼8OSThread

8.1 示例1

try(var executor=Executors.newVirtualThreadPerTaskExecutor()){IntStream.range(0, 10_000).forEach(i ->{executor.submit(()->{ Thread.sleep(Duration.ofSeconds(1));returni;});});}

8.2 示例2

publicclassOrderService{publicvoidcreateOrder(){checkStock();pay();sendSms();System.out.println("订单完成");}privatevoidcheckStock(){sleep(1000);System.out.println("库存检查完成");}privatevoidpay(){sleep(2000);System.out.println("支付完成");}privatevoidsendSms(){sleep(1000);System.out.println("短信发送完成");}privatevoidsleep(longms){try{Thread.sleep(ms);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}}}publicvoidprocessOrder(intid,OrderServiceservice){System.out.println("开始处理订单:"+id);service.createOrder();System.out.println("订单完成:"+id);}try(ExecutorServiceexecutor=Executors.newVirtualThreadPerTaskExecutor()){OrderServiceservice=newOrderService();for(inti=1;i<=10000;i++){intid=i;executor.submit(()->processOrder(id,service));}}

8.3 示例3

publicStringgetUser()throwsException{Thread.sleep(2000);return"用户信息";}publicStringgetOrder()throwsException{Thread.sleep(2000);return"订单信息";}publicStringgetPoint()throwsException{Thread.sleep(2000);return"积分信息";}try(ExecutorServiceexecutor=Executors.newVirtualThreadPerTaskExecutor()){Future<String>user=executor.submit(()->getUser());Future<String>order=executor.submit(()->getOrder());Future<String>point=executor.submit(()->getPoint());for(inti=1;i<=1000000;i++){StringuserInfo=user.get();StringuserOrder=order.get();StringuserPoint=point.get();System.out.println(userInfo+" "+userOrder+" "+userPoint);}}