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

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

来源: 责编: 时间:2024-05-16 09:09:13 235观看
导读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)共同发展,两者之间有相当多的交互dBA28资讯网——每日最新资讯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的值,然后可以在包含的代码块中使用该值。dBA28资讯网——每日最新资讯28at.com

1.2 模式匹配与Records

Records (JEP 395)是数据的透明载体。接收record类实例的代码通常将使用内置的组件访问器方法提取数据,称为组件。例如,我们可以使用类型模式来测试值是否是record类Point的实例,如果是,则从值中提取x和y组件:dBA28资讯网——每日最新资讯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的方法,如果是这样我们还可以像下面这样操作:dBA28资讯网——每日最新资讯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模式。它将提取组件的局部变量声明移至模式本身,并在值与模式匹配时通过调用访问器方法初始化这些变量。dBA28资讯网——每日最新资讯28at.com

1.3 嵌套record模式

有如下定义dBA28资讯网——每日最新资讯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) {}

如果要提取左上角点的颜色,我们可以这样写:dBA28资讯网——每日最新资讯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) ;}

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

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

如果你希望访问具体的颜色值,record模式还支持嵌套,如下示例:dBA28资讯网——每日最新资讯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 嵌套模式无法匹配情况

在下面这情况下是无法进行匹配的dBA28资讯网——每日最新资讯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 模式的所有内容。dBA28资讯网——每日最新资讯28at.com

2. switch模式匹配

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

先来看下如下这段代码dBA28资讯网——每日最新资讯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 模式以后就可以简化这样了dBA28资讯网——每日最新资讯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个问题dBA28资讯网——每日最新资讯28at.com

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

从Java 21开始,我们可以如下处理上面的if.. else dBA28资讯网——每日最新资讯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子句。dBA28资讯网——每日最新资讯28at.com

2.1 switch与null值

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

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

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

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

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

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

以上代码是Java 21之前,从Java 21起,我们可以如下:dBA28资讯网——每日最新资讯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情况。dBA28资讯网——每日最新资讯28at.com

2.2 switch条件判断

在case中还可以添加if...else判断dBA28资讯网——每日最新资讯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子句dBA28资讯网——每日最新资讯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的可读性就更强了。dBA28资讯网——每日最新资讯28at.com

2.3 switch与enum常量

在Java 21之前,switch的case表达式必须是枚举类型,标签必须是枚举常量的简单名称,如下示例:dBA28资讯网——每日最新资讯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之前使用枚举时的标签不能是下面这种写法:dBA28资讯网——每日最新资讯28at.com

case Color.GREEN -> {}

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

3. 虚拟线程

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

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

4. 字符串模版

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

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

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

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

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

在开发中字符串相关的操作是非常非常多的,虽然Java 提供了多种字符串组成机制,但遗憾的是,所有机制都有缺点。dBA28资讯网——每日最新资讯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 平台定义的模板处理器。它通过用表达式的(字符串化)值替换模板中的每个嵌入表达式来执行字符串插值。dBA28资讯网——每日最新资讯28at.com

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

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

Bill Duck

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

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

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

表达式中还可以调用方法dBA28资讯网——每日最新资讯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) ;}

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

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

多行模版字符串dBA28资讯网——每日最新资讯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);}

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

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

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

4.2 FMT 模板处理器

FMT 是 Java 平台定义的另一种模板处理器。FMT 与 STR 类似,它执行插值,但也解释嵌入式表达式左侧的格式规范。格式说明符与 java.util.Formatter 中定义的格式说明符相同。dBA28资讯网——每日最新资讯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 之前的集合类中要获取第一个和最后一个元素,不同的集合操作方式不同或者压根就没有对应的方法。如下示例:dBA28资讯网——每日最新资讯28at.com

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

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

在JDK21中提供了如下3个序列接口:dBA28资讯网——每日最新资讯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个集合都提供了对应的获取第一个和最后一个元素的方法及集合反转方法。上面定义的三个新接口与现有的集合类型层次结构非常吻合,如下图:dBA28资讯网——每日最新资讯28at.com

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

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

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

6. 未命名模式&变量

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

先看下面这个示例dBA28资讯网——每日最新资讯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开始我们可以像下面这样改写:dBA28资讯网——每日最新资讯28at.com

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

标签:
  • 热门焦点
  • 把LangChain跑起来的三个方法

    使用LangChain开发LLM应用时,需要机器进行GLM部署,好多同学第一步就被劝退了,那么如何绕过这个步骤先学习LLM模型的应用,对Langchain进行快速上手?本片讲解3个把LangChain跑起来
  • 微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • iQOO Neo8 Pro即将开售:到手价3099元起 安卓性能最强旗舰

    5月23日,iQOO如期举行了新品发布会,全新的iQOO Neo8系列也正式与大家见面,包含iQOO Neo8和iQOO Neo8 Pro两个版本,其中标准版搭载高通骁龙8+,而Pro版更
  • 英特尔Xe-HP项目终止,将专注Xe-HPC/HPG系列显卡

    据10 月 31 日消息报道,英特尔高级副总裁兼加速计算系统和图形事业部总经理 表示,Xe-HP“ Arctic Sound” 系列服务器 GPU 已经应用于 oneAPI devcloud 云服
  • 苹果MacBook Pro 2021测试:仍不支持平滑滚动

    据10月30日9to5 Mac 消息报道,苹果新的 14 英寸和 16 英寸 MacBook Pro 2021 上市后获得了不错的评价,亮点包括行业领先的性能,令人印象深刻的电池续航,精美丰
  • 三翼鸟智能家居亮相电博会,让用户体验更真实

    2021电博会在青岛国际会展中心开幕中,三翼鸟直接把“家”搬到了现场,成为了展会的一大看点。这也是三翼鸟继9月9日发布了行业首个一站式定制智慧家平台后的
  • 外交部:美方应停止在网络安全问题上不负责任地指责他国

      中国外交部今天(16日)举行例行记者会。会上,有记者问,美国情报官员称,他们正在阻拦来自中国以及其他国家的黑客获取相关科研成果。 中方对此有何评论?对此
  • 利用职权私自解除被封帐号 Meta开除20多名员工

    11月18日消息,据外媒援引知情人士表示,过去一年时间内,Facebook母公司Meta解雇或处罚了20多名员工以及合同工,指控这些人通过内部系统以不当方式重置用户帐号,其
Top