当前位置:首页 > 科技  > 软件

要不要升级?Java 21强大的新特性,代码量减半

来源: 责编: 时间:2024-05-16 09:09:13 80观看
导读1. record模式Record模式由 JEP 405 作为预览功能提出,并在 JDK 19 中发布,JEP 432 进行了第二次预览,并在 JDK 20 中发布。该功能与用于switch的模式匹配(JEP 441)共同发展,两者之间有相当多的交互1.1 instanceof类型模式O

1. record模式

Record模式由 JEP 405 作为预览功能提出,并在 JDK 19 中发布,JEP 432 进行了第二次预览,并在 JDK 20 中发布。该功能与用于switch的模式匹配(JEP 441)共同发展,两者之间有相当多的交互jBU28资讯网——每日最新资讯28at.com

1.1 instanceof类型模式

Object obj = "Pack" ;// Java 16之前if (obj instanceof String) {    String s = (String) obj ;    System.out.println("强转为String") ;}// 自Java 16起if (obj instanceof String s) {    System.out.println("简便多了") ;}

在上面的代码中从java16开始,运行时obj的值是String的实例,则obj与类型模式String s匹配。如果模式匹配,则表达式的实例为true,并且模式变量s初始化为obj转换为String的值,然后可以在包含的代码块中使用该值。jBU28资讯网——每日最新资讯28at.com

1.2 模式匹配与Records

Records (JEP 395)是数据的透明载体。接收record类实例的代码通常将使用内置的组件访问器方法提取数据,称为组件。例如,我们可以使用类型模式来测试值是否是record类Point的实例,如果是,则从值中提取x和y组件:jBU28资讯网——每日最新资讯28at.com

// 自Java 16起public record Point(int x, int y) {}public static void main(String[] args) {  Object obj = new Point(10, 20);  if (obj instanceof Point p) {    int x = p.x();    int y = p.y();    System.out.println(x + y);  }}

上面的代码看着与1.1中介绍的没撒区别就是类型模式,在上面的代码中我们仅仅是访问了record类x与y的方法,如果是这样我们还可以像下面这样操作:jBU28资讯网——每日最新资讯28at.com

Object obj = new Point(10, 20) ;// 自java 21起if (obj instanceof Point(int x, int y)) {  System.out.println(x + y) ;}

这里的Point(int x, int y) 是一个record模式。它将提取组件的局部变量声明移至模式本身,并在值与模式匹配时通过调用访问器方法初始化这些变量。jBU28资讯网——每日最新资讯28at.com

1.3 嵌套record模式

有如下定义jBU28资讯网——每日最新资讯28at.com

public record Point(int x, int y) {}enum Color { RED, GREEN, BLUE }record ColoredPoint(Point p, Color c) {}record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}

如果要提取左上角点的颜色,我们可以这样写:jBU28资讯网——每日最新资讯28at.com

Object r = new Rectangle(    new ColoredPoint(new Point(0, 0), Color.RED),     new ColoredPoint(new Point(100, 100), Color.BLUE)  ) ;// 从java 21起  if (r instanceof Rectangle(ColoredPoint ul, ColoredPoint lr)) {  System.out.printf("%s, %s%n", ul, lr) ;}

输出结果jBU28资讯网——每日最新资讯28at.com

ColoredPoint[p=Point[x=0, y=0], c=RED], ColoredPoint[p=Point[x=100, y=100], c=BLUE]

如果你希望访问具体的颜色值,record模式还支持嵌套,如下示例:jBU28资讯网——每日最新资讯28at.com

// 从java 21起if (r instanceof Rectangle(    ColoredPoint(Point(int x, int y), Color c1),     ColoredPoint lr  )) {  System.out.printf("x = %d, y = %d%n", x, y) ;}

1.4 嵌套模式无法匹配情况

在下面这情况下是无法进行匹配的jBU28资讯网——每日最新资讯28at.com

public record Pair(Object x, Object y) {}Pair p = new Pair(42, 42);if (p instanceof Pair(String s, String t)) {  System.out.println(s + ", " + t);} else {  System.out.println("Not a pair of strings") ;}

以上是关于record 模式的所有内容。jBU28资讯网——每日最新资讯28at.com

2. switch模式匹配

该功能最初由 JEP 406(JDK 17)提出,后经 JEP 420(JDK 18)、427(JDK 19)和 433(JDK 20)改进。它与 "1. record模式 "功能(JEP 440)共同发展。jBU28资讯网——每日最新资讯28at.com

先来看下如下这段代码jBU28资讯网——每日最新资讯28at.com

Object obj = 100L ;if (obj instanceof Integer) {  Integer i = (Integer) obj ;  obj = String.format("int %d", i);} else if (obj instanceof Long) {  Long l = (Long) obj ;  obj = String.format("long %d", l);} else if (obj instanceof String) {  String s = (String) obj ;  obj = String.format("String %s", s);}

有个instanceof 模式以后就可以简化这样了jBU28资讯网——每日最新资讯28at.com

Object obj = 100L ;if (obj instanceof Integer i) {  obj = String.format("int %d", i);} else if (obj instanceof Long l) {  obj = String.format("long %d", l);} else if (obj instanceof String s) {  obj = String.format("String %s", s);}System.out.printf("result obj = %s%n", obj) ;

注意:上面的代码有2个问题jBU28资讯网——每日最新资讯28at.com

  1. 上面的代码有如果没有编译器的作用,那么它的时间复杂度将是O(n)
  2. 隐藏了一个BUG,当if,else没有判断到某个类型时可能会出现问题上面的代码并没有else,因为不强制所以当判断遗漏了某种类型时可能会给程序带来潜在的问题。

从Java 21开始,我们可以如下处理上面的if.. else jBU28资讯网——每日最新资讯28at.com

var ret = switch (obj) {  case Integer i -> String.format("int %d", i);  case Long l    -> String.format("long %d", l);  case String s  -> String.format("String %s", s);  default        -> obj.toString() ;};System.out.printf("result ret = %s%n", ret) ;

在过去我们知道如果switch的每个case没有break或者return,那么它会穿透到下一个case直到遇到break或return。并且在传统的switch中没有default也是可以的。但是在上面的代码中必须要有default子句。jBU28资讯网——每日最新资讯28at.com

2.1 switch与null值

传统上,如果switch表达式值为空,switch 语句和表达式会抛出 NullPointerException,因此必须在 switch 之外进行空判断:jBU28资讯网——每日最新资讯28at.com

String s = null ;switch (s) {  // 如果不清楚这里的语法,你应该先看看java14对switch新语法的介绍  case "a", "b" -> System.out.println("a or b") ;  default -> System.out.println("defualt value") ;}

控制台输出jBU28资讯网——每日最新资讯28at.com

图片图片jBU28资讯网——每日最新资讯28at.com

在上面的代码中在过去,我们要先对s进行null的判断,再进行switch,否则有可能就会出现上面的错误。修改如下:jBU28资讯网——每日最新资讯28at.com

if (s == null) {  return ;}switch (s) {  // TODO}

以上代码是Java 21之前,从Java 21起,我们可以如下:jBU28资讯网——每日最新资讯28at.com

switch (s) {  case null -> System.out.println("oops") ;  case "a", "b" -> System.out.println("a or b") ;  default -> System.out.println("defualt value") ;}

无需单独的if判断是否为null情况。jBU28资讯网——每日最新资讯28at.com

2.2 switch条件判断

在case中还可以添加if...else判断jBU28资讯网——每日最新资讯28at.com

static void fn1(String resp) {  switch (resp) {    case String s -> {      if (s.equalsIgnoreCase("success"))        System.out.println("处理成功");      else if (s.equalsIgnoreCase("failure"))        System.err.println("处理失败");      else        System.out.println("未知结果") ;    }  }}

在case中是使用when子句jBU28资讯网——每日最新资讯28at.com

static void fn2(String resp) {  switch (resp) {    case null -> {}    case String s     when s.equalsIgnoreCase("success") -> {      System.out.println("处理成功");    }    case String s    when s.equalsIgnoreCase("failure") -> {      System.err.println("处理失败");    }    case String s -> {        System.out.println("未知结果") ;    }  }}

这样,switch的可读性就更强了。jBU28资讯网——每日最新资讯28at.com

2.3 switch与enum常量

在Java 21之前,switch的case表达式必须是枚举类型,标签必须是枚举常量的简单名称,如下示例:jBU28资讯网——每日最新资讯28at.com

public enum Color { RED, BLUE, GREEN }public static void fn1(Color c) {  switch (c) {    case RED, BLUE -> System.out.println("我喜欢的颜色") ;    case GREEN -> {      // TODO    }    default -> System.out.println("我讨厌的颜色") ;  }}

上面说的标签必须是枚举常量的简单名称什么意思呢?就是说在java21之前使用枚举时的标签不能是下面这种写法:jBU28资讯网——每日最新资讯28at.com

case Color.GREEN -> {}

而从Java 21起可以使用这种语法。jBU28资讯网——每日最新资讯28at.com

3. 虚拟线程

关于虚拟线程请查看这篇文章:jBU28资讯网——每日最新资讯28at.com

【技术革命】JDK21虚拟线程来袭,让系统的吞吐量翻倍!jBU28资讯网——每日最新资讯28at.com

4. 字符串模版

注:这是一个预览功能jBU28资讯网——每日最新资讯28at.com

jBU28资讯网——每日最新资讯28at.com

编译:javac --enable-preview --source 21 -Xlint:preview Xxx.javajBU28资讯网——每日最新资讯28at.com

运行:java --enable-preview XxxjBU28资讯网——每日最新资讯28at.com

jBU28资讯网——每日最新资讯28at.com

在开发中字符串相关的操作是非常非常多的,虽然Java 提供了多种字符串组成机制,但遗憾的是,所有机制都有缺点。jBU28资讯网——每日最新资讯28at.com

  • 使用+操作符拼接字符串,看着都不好理解
String result = x + " + " + y + " = " + (x + y) ;
  • 冗余的StringBuilder
String s = new StringBuilder().append(x).append(" + ")  .append(y).append(" = ").append(x + y).toString() ;
  • String#format 与 String#formatted将格式字符串与参数分离,避免了类型错配:
int x = 10, y = 20 ;String s = String.format("%2$d + %1$d = %3$d", x, y, x + y);String t = "%2$d + %1$d = %3$d".formatted(x, y, x + y) ;
  • java.text.MessageFormat要求太多,而且格式字符串中使用了不熟悉的语法:
String ret = MessageFormat.format("{0} + {1} = {2}", x, y, x + y) ;

4.1 STR 模板处理器

STR 是 Java 平台定义的模板处理器。它通过用表达式的(字符串化)值替换模板中的每个嵌入表达式来执行字符串插值。jBU28资讯网——每日最新资讯28at.com

String firstName = "Bill" ;String lastName  = "Duck" ;String fullName  = STR."/{firstName} /{lastName}" ;System.out.println(fullName) ;

输出结果jBU28资讯网——每日最新资讯28at.com

Bill Duck

注:STR 是一个公共静态最终字段,会自动导入到每个 Java 源文件中。jBU28资讯网——每日最新资讯28at.com

表达式还可以执行相应的操作,如下:jBU28资讯网——每日最新资讯28at.com

int x = 10, y = 20 ;String result = STR."/{x} + /{y} = /{x + y}" ;System.out.println(result) ;// 10 + 20 = 30

表达式中还可以调用方法jBU28资讯网——每日最新资讯28at.com

static String getName() {  return "张三" ;}static record Req(String date, String time) {}static void fn5() {  String s = STR."我的名字是 /{getName()} ";  System.out.println(s) ;  Req req = new Req("2000-01-01", "23:59:59") ;  String t = STR."Access at /{req.date} /{req.time}";  System.out.println(t) ;}

输出结果jBU28资讯网——每日最新资讯28at.com

我的名字是 张三Access at 2000-01-01 23:59:59

多行模版字符串jBU28资讯网——每日最新资讯28at.com

static void fn6() {  String name    = "张三";  String phone   = "1899999999";  String address = "xxxooo";  String json = STR."""  {    "name":    "/{name}",    "phone":   "/{phone}",    "address": "/{address}"  }  """;  System.out.println(json);}

输出结果jBU28资讯网——每日最新资讯28at.com

{   "name": "张三",   "phone": "1899999999",   "address": "xxxooo"}

以上是基于STR模版处理器的内容,接下来介绍另外一个。jBU28资讯网——每日最新资讯28at.com

4.2 FMT 模板处理器

FMT 是 Java 平台定义的另一种模板处理器。FMT 与 STR 类似,它执行插值,但也解释嵌入式表达式左侧的格式规范。格式说明符与 java.util.Formatter 中定义的格式说明符相同。jBU28资讯网——每日最新资讯28at.com

record Rectangle(String name, double width, double height) {  double area() {    return width * height;  }}public static void main(String[] args) {  Rectangle[] zone = new Rectangle[] {    new Rectangle("Alfa", 17.8, 31.4),    new Rectangle("Bravo", 9.6, 12.4),  };  String s = FMT."""    Description     Width    Height     Area    %-12s/{zone[0].name}  %7.2f/{zone[0].width}  %7.2f/{zone[0].height}     %7.2f/{zone[0].area()}    %-12s/{zone[1].name}  %7.2f/{zone[1].width}  %7.2f/{zone[1].height}     %7.2f/{zone[1].area()}    /{" ".repeat(28)} Total %7.2f/{zone[0].area() + zone[1].area() + zone[2].area()}  """;  System.out.println(s) ;}

5. 序列集合

在Java21 之前的集合类中要获取第一个和最后一个元素,不同的集合操作方式不同或者压根就没有对应的方法。如下示例:jBU28资讯网——每日最新资讯28at.com

图片图片jBU28资讯网——每日最新资讯28at.com

在说遍历集合,正向时(从第一个到最后一个)操作方法基本一致。但是反向时遍历时每个集合就又不相同了。jBU28资讯网——每日最新资讯28at.com

在JDK21中提供了如下3个序列接口:jBU28资讯网——每日最新资讯28at.com

  • SequencedCollection
public interface SequencedCollection<E> extends Collection<E> {  SequencedCollection<E> reversed() ;  default void addFirst(E e) ;  default void addLast(E e) ;  default E getFirst() ;  default E getLast() ;  default E removeFirst() ;  default E removeLast() ;}
  • SequencedSet
public interface SequencedSet<E> extends SequencedCollection<E>, Set<E> {  SequencedSet<E> reversed();}
  • SequencedMap
public interface SequencedMap<K, V> extends Map<K, V> {  SequencedMap<K, V> reversed() ;  default Map.Entry<K,V> firstEntry() ;  default Map.Entry<K,V> lastEntry() ;  default Map.Entry<K,V> pollFirstEntry() ;  default Map.Entry<K,V> pollLastEntry() ;  default V putFirst(K k, V v) ;  default V putLast(K k, V v) ;  // other}

以上3个集合都提供了对应的获取第一个和最后一个元素的方法及集合反转方法。上面定义的三个新接口与现有的集合类型层次结构非常吻合,如下图:jBU28资讯网——每日最新资讯28at.com

图片图片jBU28资讯网——每日最新资讯28at.com

对现有的类和接口进行了如下调整:jBU28资讯网——每日最新资讯28at.com

  • List 现在将 SequencedCollection 作为其直接超接口、
  • Deque 现在将 SequencedCollection 作为其直接超接口、
  • LinkedHashSet 进一步实现了 SequencedSet、
  • SortedSet 现在将 SequencedSet 作为其直接超接口、
  • LinkedHashMap 进一步实现了 SequencedMap,而
  • SortedMap 现在将 SequencedMap 作为其直接超接口。

6. 未命名模式&变量

注:这是一个预览功能jBU28资讯网——每日最新资讯28at.com

先看下面这个示例jBU28资讯网——每日最新资讯28at.com

public record Point(int x, int y) {}enum Color { RED, GREEN, BLUE }record ColoredPoint(Point p, Color c) {}record Rectangle(ColoredPoint cp) {}  Object obj = new Rectangle(    new ColoredPoint(new Point(10, 10), Color.RED)  ) ;if (obj instanceof Rectangle(ColoredPoint(Point(int x, int y), Color c))) {  System.out.printf("x = %d, y = %d%n", x, y) ;}

在上面的if判断中,对于Color c变量并没有使用,从Java 21开始我们可以像下面这样改写:jBU28资讯网——每日最新资讯28at.com

if (obj instanceof Rectangle(ColoredPoint(Point(int x, int y), _))) {  System.out.printf("x = %d, y = %d%n", x, y) ;}

使用一个 "_" 下划线代替即可。jBU28资讯网——每日最新资讯28at.com

未使用的变量jBU28资讯网——每日最新资讯28at.com

int[] arr = {1, 2, 3, 4, 5} ;int total = 0 ;for (var a : arr) {  total++ ;}

在这个示例中,变量a并没有使用,所以从Java 21开始可以改写如下:jBU28资讯网——每日最新资讯28at.com

for (var _ : arr) {  total++ ;}

对于这样没有使用的变量,我们可以用一个 "_" 下划线代替。其它示例:jBU28资讯网——每日最新资讯28at.com

try {  int a = 1 / 0 ;} catch (Exception _) { // 这里没有用到异常通过可以使用 _}

注:我用的Eclipse没法直接使用,我这里是通过记事本编写,通过命令行编译&运行。jBU28资讯网——每日最新资讯28at.com

7. 未命名的类&Main方法jBU28资讯网——每日最新资讯28at.com

注:这是一个预览功能jBU28资讯网——每日最新资讯28at.com

下面这个代码是学习java的入门代码jBU28资讯网——每日最新资讯28at.com

public class UnnamedClassAndMain { public static void main(String[] args) {   System.out.println("Hello World!!!") ; }}

从Java 21开始,我们可以简化成如下形式了jBU28资讯网——每日最新资讯28at.com

public class UnnamedClassAndMain {  void main() {    System.out.println("Hello World!!!") ;  }}

未命名的类jBU28资讯网——每日最新资讯28at.com

还是拿上面的程序演示,我们还可以继续简化如下形式:jBU28资讯网——每日最新资讯28at.com

void main() {  System.out.println("Hello World!!!") ;}

对,文件中只有一个极简的方法,连类的声明都没有了。你甚至还可以如下,定义方法,方法调用jBU28资讯网——每日最新资讯28at.com

String name = "Pack" ;String getName() {  return name ;}void main() {  System.out.println(getName()) ;}

类文件直接定义方法,声明变量。jBU28资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-88373-0.html要不要升级?Java 21强大的新特性,代码量减半

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Python进阶:掌握15条PEP 8黄金法则

下一篇: Go 事件驱动编程:实现一个简单的事件总线

标签:
  • 热门焦点
  • 鸿蒙OS 4.0公测机型公布:甚至连nova6都支持

    鸿蒙OS 4.0公测机型公布:甚至连nova6都支持

    华为全新的HarmonyOS 4.0操作系统将于今天下午正式登场,官方在发布会之前也已经正式给出了可升级的机型产品,这意味着这些机型会率先支持升级享用。这次的HarmonyOS 4.0支持
  • 对标苹果的灵动岛 华为带来实况窗功能

    对标苹果的灵动岛 华为带来实况窗功能

    继苹果的灵动岛之后,华为也在今天正式推出了“实况窗”功能。据今天鸿蒙OS 4.0的现场演示显示,华为的实况窗可以更高效的展现出实时通知,比如锁屏上就能看到外卖、打车、银行
  • 5月iOS设备性能榜:M1 M2依旧是榜单前五

    5月iOS设备性能榜:M1 M2依旧是榜单前五

    和上个月一样,没有新品发布的iOS设备性能榜的上榜设备并没有什么更替,仅仅只有跑分变化而产生的排名变动,刚刚开始的苹果WWDC2023,推出的产品也依旧是新款Mac Pro、新款Mac Stu
  • 线程通讯的三种方法!通俗易懂

    线程通讯的三种方法!通俗易懂

    线程通信是指多个线程之间通过某种机制进行协调和交互,例如,线程等待和通知机制就是线程通讯的主要手段之一。 在 Java 中,线程等待和通知的实现手段有以下几种方式:Object 类下
  • SpringBoot中使用Cache提升接口性能详解

    SpringBoot中使用Cache提升接口性能详解

    环境:springboot2.3.12.RELEASE + JSR107 + Ehcache + JPASpring 框架从 3.1 开始,对 Spring 应用程序提供了透明式添加缓存的支持。和事务支持一样,抽象缓存允许一致地使用各
  • “又被陈思诚骗了”

    “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • AMD的AI芯片转单给三星可能性不大 与台积电已合作至2nm制程

    AMD的AI芯片转单给三星可能性不大 与台积电已合作至2nm制程

    据 DIGITIMES 消息,英伟达 AI GPU 出货逐季飙升,接下来 AMD MI 300 系列将在第 4 季底量产。而半导体业内人士表示,近日传出 AMD 的 AI 芯片将转单给
  • Android 14发布:首批适配机型公布

    Android 14发布:首批适配机型公布

    5月11日消息,谷歌在今天凌晨举行了I/O大会,本次发布会谷歌带来了自家的AI语言模型PaLM 2、谷歌Pixel Fold折叠屏、谷歌Pixel 7a手机,同时发布了Androi
  • 上海举办人工智能大会活动,建设人工智能新高地

    上海举办人工智能大会活动,建设人工智能新高地

    人工智能大会在上海浦江两岸隆重拉开帷幕,人工智能新技术、新产品、新应用、新理念集中亮相。8月30日晚,作为大会的特色活动之一的上海人工智能发展盛典人工
Top
Baidu
map