我有点想用JDK17了

大家好呀,我是summo,JDK版本升级的非常快,现在已经到JDK20了。JDK版本虽多,但应用最广泛的还得是JDK8,正所谓“他发任他发,我用Java8”。

其实我也不太想升级JDK版本,感觉投入高,收益小,不过有一次我看到了一些使用JDK17新语法写的代码,让我改变了对升级JDK的看法,因为这些新语法我确实想用!

废话不多说,上代码!

一、JDK17语法新特性

1. 文本块

这个更新非常实用。在没有这个特性之前,编写长文本非常痛苦。虽然IDEA等集成开发工具可以自动处理,但最终效果仍然丑陋,充满拼接符号。现在,通过字符串块,我们可以轻松编写JSON、HTML、SQL等内容,效果更清爽。这个新特性值得五颗星评价,因为它让我们只需关注字符串本身,而无需关心拼接操作。

原来的写法

1/** 2 * 使用JDK8返回HTML文本 3 * 4 * @return 返回HTML文本 5 */ 6public static final String getHtmlJDK8() { 7 return "<html>\n" + 8 " <body>\n" + 9 " <p>Hello, world</p>\n" + 10 " </body>\n" + 11 "</html>"; 12}

新的写法

1/** 2 * 使用JDK17返回HTML文本 3 * 4 * @return 返回HTML文本 5 */ 6public static final String getHtmlJDK17() { 7 return """ 8 <html> 9 <body> 10 <p>Hello, world</p> 11 </body> 12 </html> 13 """; 14}

推荐指数:⭐️⭐️⭐️⭐️⭐️

2. NullPointerException增强

这一功能非常强大且实用,相信每位Java开发者都期待已久。空指针异常(NPE)一直是Java程序员的痛点,因为报错信息无法直观地指出哪个对象为空,只抛出一个NullPointerException和一堆堆栈信息,定位问题耗时且麻烦。尤其在遇到喜欢级联调用的代码时,逐行排查更是令人头疼。如果在测试环境中,可能还需通过远程调试查明空对象,费时费力。为此,阿里的编码规范甚至不允许级联调用,但这并不能彻底解决问题。Java17终于在这方面取得了突破,提供了更详细的空指针异常信息,帮助开发者迅速定位问题源头。

1public static void main(String[] args) { 2 try { 3 //简单的空指针 4 String str = null; 5 str.length(); 6 } catch (Exception e) { 7 e.printStackTrace(); 8 } 9 try { 10 //复杂一点的空指针 11 var arr = List.of(null); 12 String str = (String)arr.get(0); 13 str.length(); 14 } catch (Exception e) { 15 e.printStackTrace(); 16 } 17}

运行结果

推荐指数:⭐️⭐️⭐️⭐️⭐️

3. Records

在Java中,POJO对象(如DO、PO、VO、DTO等)通常包含成员变量及相应的Getter和Setter方法。尽管可以通过工具或IDE生成这些代码,但修改和维护仍然麻烦。Lombok插件为此出现,能够在编译期间自动生成Getter、Setter、hashcode、equals和构造函数等代码,使用起来方便,但对团队有依赖要求。 为此,Java引入了标准解决方案:Records。它通过简洁的语法定义数据类,大大简化了POJO类的编写,如下所示。虽然hashcode和equals方法仍需手动编写,但IDE能够自动生成。这一特性有效解决了模板代码问题,提升了代码整洁度和可维护性。

1package com.summo.jdk17; 2 3/** 4 * 3星 5 * 6 * @param stuId 学生ID 7 * @param stuName 学生名称 8 * @param stuAge 学生年龄 9 * @param stuGender 学生性别 10 * @param stuEmail 学生邮箱 11 */ 12public record StudentRecord(Long stuId, 13 String stuName, 14 int stuAge, 15 String stuGender, 16 String stuEmail) { 17 public StudentRecord { 18 System.out.println("构造函数"); 19 } 20 21 public static void main(String[] args) { 22 StudentRecord record = new StudentRecord(1L, "张三", 16, "男", "xxx@qq.com"); 23 System.out.println(record); 24 } 25}

推荐指数:⭐️⭐️⭐️⭐️

4. 全新的switch表达式

有人可能问了,Java语言不早已支持switch了嘛,有什么好提的?讲真,这次的提升还真有必要好好地来聊一聊了。在Java12的时候就引入了switch表达式,注意这里是表达式,而不是语句,原来的switch是语句。如果不清楚两者的区别的话,最好先去了解一下。主要的差别就是就是表达式有返回值,而语句则没有。再配合模式匹配,以及yield和“->”符号的加入,全新的switch用起来爽到飞起来。

1package com.summo.jdk17; 2 3public class SwitchDemo { 4 /** 5 * 在JDK8中获取switch返回值方式 6 * 7 * @param week 8 * @return 9 */ 10 public int getByJDK8(Week week) { 11 int i = 0; 12 switch (week) { 13 case MONDAY, TUESDAY: 14 i = 1; 15 break; 16 case WEDNESDAY: 17 i = 3; 18 break; 19 case THURSDAY: 20 i = 4; 21 break; 22 case FRIDAY: 23 i = 5; 24 break; 25 case SATURDAY: 26 i = 6; 27 break; 28 case SUNDAY: 29 i = 7; 30 break; 31 default: 32 i = 0; 33 break; 34 } 35 36 return i; 37 } 38 39 /** 40 * 在JDK17中获取switch返回值 41 * 42 * @param week 43 * @return 44 */ 45 public int getByJDK17(Week week) { 46 // 1, 现在的switch变成了表达式,可以返回值了,而且支持yield和->符号来返回值 47 // 2, 再也不用担心漏写了break,而导致出问题了 48 // 3, case后面支持写多个条件 49 return switch (week) { 50 case null -> -1; 51 case MONDAY -> 1; 52 case TUESDAY -> 2; 53 case WEDNESDAY -> 3; 54 case THURSDAY -> {yield 4;} 55 case FRIDAY -> 5; 56 case SATURDAY, SUNDAY -> 6; 57 default -> 0; 58 }; 59 } 60 61 private enum Week { 62 MONDAY, 63 TUESDAY, 64 WEDNESDAY, 65 THURSDAY, 66 FRIDAY, 67 SATURDAY, 68 SUNDAY 69 } 70}

推荐指数:⭐️⭐️⭐️⭐️

5. 私有接口方法

从Java8开始,允许在interface里面添加默认方法,其实当时就有些小困惑,如果一个default方法体很大怎么办,拆到另外的类去写吗?实在有些不太合理,所以在Java17里面,如果一个default方法体很大,那么可以通过新增接口私有方法来进行一个合理的拆分了,为这个小改进点个赞。

1public interface PrivateInterfaceMethod { 2    /** 3     * 接口默认方法 4     */ 5    default void defaultMethod() { 6        privateMethod(); 7    } 8 9    // 接口私有方法,在Java8里面是不被允许的,不信你试试 10    private void privateMethod() { 11    } 12}

推荐指数:⭐️⭐️⭐️

6. 模式匹配

在JDK 17中,模式匹配主要用于instanceof表达式。模式匹配增强了instanceof的语法和功能,使类型检查和类型转换更加简洁和高效。在传统的Java版本中,我们通常使用instanceof结合类型转换来判断对象类型并进行处理,这往往会导致冗长的代码。

原来的写法

1/** 2 * 旧式写法 3 * 4 * @param value 5 */ 6public void matchByJDK8(Object value) { 7 if (value instanceof String) { 8 String v = (String)value; 9 System.out.println("遇到一个String类型" + v.toUpperCase()); 10 } else if (value instanceof Integer) { 11 Integer v = (Integer)value; 12 System.out.println("遇到一个整型类型" + v.longValue()); 13 } 14}

新的写法

1/** 2 * 转换并申请了一个新的变量,极大地方便了代码的编写 3 * 4 * @param value 5 */ 6public void matchByJDK17(Object value) { 7 if (value instanceof String v) { 8 System.out.println("遇到一个String类型" + v.toUpperCase()); 9 } else if (value instanceof Integer v) { 10 System.out.println("遇到一个整型类型" + v.longValue()); 11 } 12}

推荐指数:⭐️⭐️⭐️⭐️

7. 集合类的工厂方法

在Java8的年代,即便创建一个很小的集合,或者固定元素的集合都是比较麻烦的,为了简洁一些,有时我甚至会引入一些依赖。

原来的写法

1Set<String> set = new HashSet<>(); 2set.add("a"); 3set.add("b"); 4set.add("c"

新的写法

1Set<String> set = Set.of("a", "b", "c");

推荐指数:⭐️⭐️⭐️⭐️⭐️

二、其他的新特性

1. 新的String方法

  • repeat:重复生成字符串
  • isBlank:不用在引入第三方库就可以实现字符串判空了
  • strip:去除字符串两边的空格,支持全角和半角,之前的trim只支持半角
  • lines:能根据一段字符串中的终止符提取出行为单位的流
  • indent:给字符串做缩进,接受一个int型的输入
  • transform:接受一个转换函数,实现字符串的转换

2. Stream API的增强

增加takeWhile, dropWhile, ofNullable, iterate以及toList的API,越来越像一些函数式语言了。用法举例如下。

1// takeWhile 顺序返回符合条件的值,直到条件不符合时即终止继续判断, 2// 此外toList方法的加入,也大大减少了节省了代码量,免去了调用collect(Collectors::toList)方法了 3List<Integer> list = Stream.of(2,2,3,4,5,6,7,8,9,10) 4        .takeWhile(i->(i%2==0)).toList(); // 返回2, 2 5 6// dropWhile 顺序去掉符合条件的值,直到条件不符合时即终止继续判断 7List<Integer> list1 = Stream.of(2,2,3,4,5,6,7,8,9,10) 8        .dropWhile(i->(i%2==0)).toList(); //返回3, 4, 5, 6, 7, 8, 9, 10 9 10// ofNullable,支持传入空流,若没有这个且传入一个空流,那么将会抛NPE 11var nullStreamCount = Stream.ofNullable(null).count(); //返回0 12 13// 以下两行都将输出0到9 14Stream.iterate(0, n -> n < 10, n -> n + 1).forEach(x -> System.out.println(x)); 15Stream.iterate(0, n -> n + 1).limit(10).forEach(x -> System.out.println(x));

3. 全新的HttpClient

这个API首次出现在9之中,不过当时并非是一个稳定版本,在Java11中正式得到发布,所以在Java17里面可以放心地进行使用。原来的JDK自带的Http客户端真的非常难用,这也就给了很多像okhttp、restTemplate、Apache的HttpClient和feign这样的第三方库极大的发挥空间,几乎就没有人愿意去用原生的Http客户端的。但现在不一样了,感觉像是新时代的API了。FluentAPI风格,处处充满了现代风格,用起来也非常地方便,再也不用去依赖第三方的包了,就两个字,清爽。

1// 同步请求 2HttpClient client = HttpClient.newBuilder() 3        .version(Version.HTTP_1_1) 4        .followRedirects(Redirect.NORMAL) 5        .connectTimeout(Duration.ofSeconds(20)) 6        .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80))) 7        .authenticator(Authenticator.getDefault()) 8        .build(); 9   HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); 10   System.out.println(response.statusCode()); 11   System.out.println(response.body()); 12// 异步请求 13HttpRequest request = HttpRequest.newBuilder() 14        .uri(URI.create("https://foo.com/")) 15        .timeout(Duration.ofMinutes(2)) 16        .header("Content-Type", "application/json") 17        .POST(BodyPublishers.ofFile(Paths.get("file.json"))) 18        .build(); 19   client.sendAsync(request, BodyHandlers.ofString()) 20        .thenApply(HttpResponse::body) 21        .thenAccept(System.out::println); 22 

4. jshell

在新的JDK版本中,支持直接在命令行下执行java程序,类似于python的交互式REPL。简而言之,使用 JShell,你可以输入代码片段并马上看到运行结果,然后就可以根据需要作出调整,这样在验证一些简单的代码的时候,就可以通过jshell得到快速地验证,非常方便。

5. java命令直接执行java文件

在现在可以直接通过执行“java xxx.java”,即可运行该java文件,无须先执行javac,然后再执行java,是不是又简单了一步。

6. ZGC

在ParallelOldGC、CMS和G1之后,JDK 11引入了全新的ZGC(Z Garbage Collector)。这个名字本身就显得很牛。官方宣称ZGC的垃圾回收停顿时间不超过10ms,能支持高达16TB的堆空间,并且停顿时间不会随着堆的增大而增加。那么,ZGC到底解决了什么问题?Oracle官方介绍它是一个可伸缩的低延迟垃圾回收器,旨在降低停顿时间,尽管这可能会导致吞吐量的降低。不过,通过横向扩展服务器可以解决吞吐量问题。官方已建议ZGC可用于生产环境,这无疑将成为未来的主流垃圾回收器。要了解更多,请参阅官方文档。

三、小结一下

作为程序员,持续学习和充电非常重要。随着Java8即将停止免费官方支持,越来越多的项目将转向Java17,包括大名鼎鼎的Spring Boot 3.0,它在2022年1月20日发布的第一个里程碑版本(M1)正是基于Java17构建的。该项目依赖的所有组件也将快速升级,未来如果想利用某些新特性,在Java8下将无法通过编译.,到这时候再换就真的晚了... ...

点赞
收藏

评论区

加载中...

相关推荐

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手把手教你从Apk中取出算法

一、目标李老板:奋飞呀,我最近从Apk里面跟踪到一个算法,代码清晰,但是我不会java,把他翻译成python貌似挺费劲的,有没有轻松省力的方法呀?奋飞:有的呀,给我加工资,我来翻译。某电商Appv10.4.5,升级之后老有小伙伴说他的sign算法变了,其实他就是做了点小动作。sign参数没有动,uuid是明文去做签名,但是抓包请求里面找不到明文uu

Jenkins:批量自动将 Maven 类型 Job 迁移到自由风格类型

为什么要迁移?近期进行Jenkins从1.X到2.X的升级演练Jenkins2最新版本只能在JDK8或JDK11版本下运行,我所使用的JDK版本为JDK8在构建MavenJob,Job配置的JDK版本为JDK7时,构建报错$/usr/local/java/bin/javacp

JDK 从老版本升级到 1.8的问题总结

!(https://oscimg.oschina.net/oscnet/fcd31648309f48f190b88f02b92fa027.png)JDK8升级常见问题JDK8发布很久了,它提供了许多吸引人的新特性,能够提高编程效率。如果是新的项目,使用JDK8当然是最好的选择。但

JDK 17 营销初体验 —— 亚毫秒停顿 ZGC 落地实践 | 京东云技术团队

自2014年发布以来,JDK8一直都是相当热门的JDK版本。其原因就是对底层数据结构、JVM性能以及开发体验做了重大升级,得到了开发人员的认可。但距离JDK8发布已经过去了9年,那么这9年的时间,JDK做了哪些升级?是否有新的重大特性值得我们尝试?能否解决一些我们现在苦恼的问题?带着这份疑问,我们进行了JDK版本的调研与尝试。

JDK11升级JDK17最全实践干货来了 | 京东云技术团队

从JDK11到JDK17,到底带来了哪些特性呢?亚毫秒级的ZGC效果到底怎么样呢?值得我们升级吗?而且升级过程会遇到哪些问题呢?带着这些问题,本篇文章将带来完整的JDK11升级JDK17最全实践。