我有点想用JDK17了
mhr18 2025-01-05 18:47 17 浏览 0 评论
大家下午好,JDK版本升级的非常快。JDK版本虽多,但应用最广泛的还得是JDK8,正所谓“他发任他发,我用Java8”。
其实我也不太想升级JDK版本,感觉投入高,收益小,不过有一次我看到了一些使用JDK17新语法写的代码,让我改变了对升级JDK的看法,因为这些新语法我确实想用!
废话不多说,上代码!
一、JDK17语法新特性
1. 文本块
这个更新非常实用。在没有这个特性之前,编写长文本非常痛苦。虽然IDEA等集成开发工具可以自动处理,但最终效果仍然丑陋,充满拼接符号。现在,通过字符串块,我们可以轻松编写JSON、HTML、SQL等内容,效果更清爽。这个新特性值得五颗星评价,因为它让我们只需关注字符串本身,而无需关心拼接操作。
原来的写法
/**
* 使用JDK8返回HTML文本
*
* @return 返回HTML文本
*/
public static final String getHtmlJDK8() {
return "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>";
}
新的写法
/**
* 使用JDK17返回HTML文本
*
* @return 返回HTML文本
*/
public static final String getHtmlJDK17() {
return """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
}
推荐指数:??????????
2. NullPointerException增强
这一功能非常强大且实用,相信每位Java开发者都期待已久。空指针异常(NPE)一直是Java程序员的痛点,因为报错信息无法直观地指出哪个对象为空,只抛出一个NullPointerException和一堆堆栈信息,定位问题耗时且麻烦。尤其在遇到喜欢级联调用的代码时,逐行排查更是令人头疼。如果在测试环境中,可能还需通过远程调试查明空对象,费时费力。为此,阿里的编码规范甚至不允许级联调用,但这并不能彻底解决问题。Java17终于在这方面取得了突破,提供了更详细的空指针异常信息,帮助开发者迅速定位问题源头。
public static void main(String[] args) {
try {
//简单的空指针
String str = null;
str.length();
} catch (Exception e) {
e.printStackTrace();
}
try {
//复杂一点的空指针
var arr = List.of(null);
String str = (String)arr.get(0);
str.length();
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果
推荐指数:??????????
3. Records
在Java中,POJO对象(如DO、PO、VO、DTO等)通常包含成员变量及相应的Getter和Setter方法。尽管可以通过工具或IDE生成这些代码,但修改和维护仍然麻烦。Lombok插件为此出现,能够在编译期间自动生成Getter、Setter、hashcode、equals和构造函数等代码,使用起来方便,但对团队有依赖要求。 为此,Java引入了标准解决方案:Records。它通过简洁的语法定义数据类,大大简化了POJO类的编写,如下所示。虽然hashcode和equals方法仍需手动编写,但IDE能够自动生成。这一特性有效解决了模板代码问题,提升了代码整洁度和可维护性。
package com.summo.jdk17;
/**
* 3星
*
* @param stuId 学生ID
* @param stuName 学生名称
* @param stuAge 学生年龄
* @param stuGender 学生性别
* @param stuEmail 学生邮箱
*/
public record StudentRecord(Long stuId,
String stuName,
int stuAge,
String stuGender,
String stuEmail) {
public StudentRecord {
System.out.println("构造函数");
}
public static void main(String[] args) {
StudentRecord record = new StudentRecord(1L, "张三", 16, "男", "xxx@qq.com");
System.out.println(record);
}
}
推荐指数:????????
4. 全新的switch表达式
有人可能问了,Java语言不早已支持switch了嘛,有什么好提的?讲真,这次的提升还真有必要好好地来聊一聊了。在Java12的时候就引入了switch表达式,注意这里是表达式,而不是语句,原来的switch是语句。如果不清楚两者的区别的话,最好先去了解一下。主要的差别就是就是表达式有返回值,而语句则没有。再配合模式匹配,以及yield和“->”符号的加入,全新的switch用起来爽到飞起来。
package com.summo.jdk17;
public class SwitchDemo {
/**
* 在JDK8中获取switch返回值方式
*
* @param week
* @return
*/
public int getByJDK8(Week week) {
int i = 0;
switch (week) {
case MONDAY, TUESDAY:
i = 1;
break;
case WEDNESDAY:
i = 3;
break;
case THURSDAY:
i = 4;
break;
case FRIDAY:
i = 5;
break;
case SATURDAY:
i = 6;
break;
case SUNDAY:
i = 7;
break;
default:
i = 0;
break;
}
return i;
}
/**
* 在JDK17中获取switch返回值
*
* @param week
* @return
*/
public int getByJDK17(Week week) {
// 1, 现在的switch变成了表达式,可以返回值了,而且支持yield和->符号来返回值
// 2, 再也不用担心漏写了break,而导致出问题了
// 3, case后面支持写多个条件
return switch (week) {
case null -> -1;
case MONDAY -> 1;
case TUESDAY -> 2;
case WEDNESDAY -> 3;
case THURSDAY -> {yield 4;}
case FRIDAY -> 5;
case SATURDAY, SUNDAY -> 6;
default -> 0;
};
}
private enum Week {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
}
推荐指数:????????
5. 私有接口方法
从Java8开始,允许在interface里面添加默认方法,其实当时就有些小困惑,如果一个default方法体很大怎么办,拆到另外的类去写吗?实在有些不太合理,所以在Java17里面,如果一个default方法体很大,那么可以通过新增接口私有方法来进行一个合理的拆分了,为这个小改进点个赞。
public interface PrivateInterfaceMethod {
/**
* 接口默认方法
*/
default void defaultMethod() {
privateMethod();
}
// 接口私有方法,在Java8里面是不被允许的,不信你试试
private void privateMethod() {
}
}
推荐指数:??????
6. 模式匹配
在JDK 17中,模式匹配主要用于instanceof表达式。模式匹配增强了instanceof的语法和功能,使类型检查和类型转换更加简洁和高效。在传统的Java版本中,我们通常使用instanceof结合类型转换来判断对象类型并进行处理,这往往会导致冗长的代码。
原来的写法
/**
* 旧式写法
*
* @param value
*/
public void matchByJDK8(Object value) {
if (value instanceof String) {
String v = (String)value;
System.out.println("遇到一个String类型" + v.toUpperCase());
} else if (value instanceof Integer) {
Integer v = (Integer)value;
System.out.println("遇到一个整型类型" + v.longValue());
}
}
新的写法
/**
* 转换并申请了一个新的变量,极大地方便了代码的编写
*
* @param value
*/
public void matchByJDK17(Object value) {
if (value instanceof String v) {
System.out.println("遇到一个String类型" + v.toUpperCase());
} else if (value instanceof Integer v) {
System.out.println("遇到一个整型类型" + v.longValue());
}
}
推荐指数:????????
7. 集合类的工厂方法
在Java8的年代,即便创建一个很小的集合,或者固定元素的集合都是比较麻烦的,为了简洁一些,有时我甚至会引入一些依赖。
原来的写法
Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c"
新的写法
Set<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,越来越像一些函数式语言了。用法举例如下。
// takeWhile 顺序返回符合条件的值,直到条件不符合时即终止继续判断,
// 此外toList方法的加入,也大大减少了节省了代码量,免去了调用collect(Collectors::toList)方法了
List<Integer> list = Stream.of(2,2,3,4,5,6,7,8,9,10)
.takeWhile(i->(i%2==0)).toList(); // 返回2, 2
// dropWhile 顺序去掉符合条件的值,直到条件不符合时即终止继续判断
List<Integer> list1 = Stream.of(2,2,3,4,5,6,7,8,9,10)
.dropWhile(i->(i%2==0)).toList(); //返回3, 4, 5, 6, 7, 8, 9, 10
// ofNullable,支持传入空流,若没有这个且传入一个空流,那么将会抛NPE
var nullStreamCount = Stream.ofNullable(null).count(); //返回0
// 以下两行都将输出0到9
Stream.iterate(0, n -> n < 10, n -> n + 1).forEach(x -> System.out.println(x));
Stream.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风格,处处充满了现代风格,用起来也非常地方便,再也不用去依赖第三方的包了,就两个字,清爽。
// 同步请求
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
.authenticator(Authenticator.getDefault())
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
// 异步请求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://foo.com/"))
.timeout(Duration.ofMinutes(2))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofFile(Paths.get("file.json")))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
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下将无法通过编译.,到这时候再换就真的晚了... ...
学习交流
最后,把我的座右铭送给你:投资自己才是最大的财富。 如果你觉得本文章对你有帮助,点赞,收藏不迷路
公众号:我不是架构师,持续为你输出更多的硬核文章和面试经验。
- 上一篇:内存溢出OutOfMemoryError科普系列一
- 下一篇:Qt之SQL的使用
相关推荐
- MYSQL数据同步(mysql数据同步方式)
-
java开发工程师在实际的开发经常会需要实现两台不同机器上的MySQL数据库的数据同步,要解决这个问题不难,无非就是mysql数据库的数据同步问题。但要看你是一次性的数据同步需求,还是定时数据同步,亦...
- SpringBoot+Redis实现点赞收藏功能+定时同步数据库
-
由于点赞收藏都是高频率的操作,如果因此频繁地写入数据库会造成数据库压力比较大,因此采用redis来统计点赞收藏浏览量,之后定时一次性写入数据库中,缓解数据库地压力。一.大体思路设计redis中的储存结...
- 双11订单洪峰:Codis代理层如何扛住Redis集群搞不定的120万QPS?
-
双11订单洪峰下的技术挑战每年的双11购物节,都是对电商平台技术架构的极限考验。当零点钟声敲响,海量用户瞬间涌入,订单量呈指数级增长,系统需要承受每秒数十万甚至上百万次的请求。作为电商系统的核心组件之...
- 基于spring boot + MybatisPlus 商城管理系统的Java开源商城系统
-
前言Mall4j项目致力于为中小企业打造一个完整、易于维护的开源的电商系统,采用现阶段流行技术实现。后台管理系统包含商品管理、订单管理、运费模板、规格管理、会员管理、运营管理、内容管理、统计报表、权限...
- 商品券后价产品设计方案(显示券后价)
-
如何设计一套高效、准确且稳定的券后价计算系统,是电商产品设计中的关键挑战之一。本文详细介绍了商品券后价的产品设计方案,从背景目标、功能设计、系统实现逻辑到异常处理机制等多个方面进行了全面阐述。一、背景...
- 外观(门面)模式-Java实现(java 门面模式)
-
定义外观模式(FacadePattern),也叫门面模式,原始定义是:为了子系统中的一组接口提供统一的接口。定义一个更高级别的接口,使子系统更易于使用。大大降低应用程序的复杂度,提高了程序的可维护性...
- Mall - 用 SpringBoot 实现一个电商系统
-
目前最为主流的Web开发技术,包括SpringBoot、MyBatis、MongoDB、Kibina、Docker、Vue等,都是开发者十分需要掌握的技术。有没有一个全面而又实际的项目,能把这...
- 腾讯云国际站:哪些工具能实现可视化运维?
-
本文由【云老大】TG@yunlaoda360撰写开源工具Grafana:开源的可视化平台,可与Prometheus、Elasticsearch、MySQL等多种数据源集成,将复杂监控数据转化...
- 系统稳定性保障全流程实战:事前、事中、事后 Java 代码详解
-
在互联网架构中,系统稳定性是生命线。本文基于“事前预防、事中管控、事后复盘”三阶段模型,结合Java实战代码,深度解析如何构建高可用系统,让你的服务稳如磐石!一、事前:未雨绸缪,筑牢防线1.发...
- Java面试题:拆分微服务应该注意哪些地方方,如何拆分?
-
在拆分微服务时,需要综合考虑业务、技术和组织等多方面因素,以下是关键注意事项及拆分策略的详细说明:一、拆分注意事项1.业务边界清晰化单一职责原则:每个服务应专注于单一业务能力,例如订单服务仅处理订单...
- 软件性能调优全攻略:从瓶颈定位到工具应用
-
性能调优是软件测试中的重要环节,旨在提高系统的响应时间、吞吐量、并发能力、资源利用率,并降低系统崩溃或卡顿的风险。通常,性能调优涉及发现性能瓶颈、分析问题根因、优化代码和系统配置等步骤,调优之前需要先...
- Docker Compose实战,多容器协同编排的利器,让开发部署更高效!
-
开篇导读你是否有过这样的经历?启动一个项目,数据库、Redis、Web服务得一个个敲dockerrun?想让别人复现你的开发环境,却得发一堆复杂的启动命令?明明都是容器,为什么不能“一键启动”所...
- 如何设计Agent的记忆系统(agent记忆方法)
-
最近看了一张画Agent记忆分类的图我觉得分类分的还可以,但是太浅了,于是就着它的逻辑,仔细得写了一下在不同的记忆层,该如何设计和选型先从流程,作用,实力和持续时间的这4个维度来解释一下这几种记忆:1...
- 不了解业务和技术术语怎么做好产品和项目?
-
基础技术术语术语分类解释API开发技术应用程序接口,不同系统间数据交互的协议(如支付接口、地图接口)。SDK开发工具软件开发工具包,包含API、文档和示例代码,帮助快速接入服务。RESTfulAPI...
- Docker 架构详解与核心概念实战图解:一文读懂容器的前世今生
-
不懂Docker架构,你只是“用容器的人”;理解了它的底层逻辑,才能成为真正的高手!在学习Docker之前,很多同学可能会陷入一个误区:“反正我用dockerrun就能跑起服务,架构这种...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)