Jdk17的新特性-学习笔记

前言

Jdk半年都会出一个版本出来,而我们主要关注的就是LTS版本,翻译过来就是long  term  support(长期支持版本)现在有两个新的LTS版本1117,那我们肯定是优先选择最新的17版本。一些最新的框架对jdk要求如Spring Framwork 6.x jdk的版本要求为17Spring Boot 3.0开始对jdk最低版本要求为17Kafaka最新版本3.0.0将不再支持jdk8版本等等。总而言之,言而总之,Jdk8将会渐渐淡出主流舞台,今后将是属于jdk17的天下了。

        该篇主要是记录自己学习jdk17新特性的学习笔记,后续方便自己温习,也欢迎各位提出指导和意见。

几个新特性

1.switch语句的增强

jdk17以前的switch语法如下(无法对null类型做匹配)

        String beforeName = "刘邦";
        String beforeAlias;
        switch (beforeName) {
            case "周瑜":
                beforeAlias = "公瑾";
                break;
            case "徐庶":
            case "yz":
                beforeAlias = "元直";
                break;
            case "项羽":
                System.out.println("三国");
                beforeAlias = "西楚霸王";
                break;
            case "刘邦":
                beforeAlias = "汉高祖";
                break;
//            jdk8中,这里不支持对null类型进行匹配
//            case null:
//                System.out.println("beforeName is null");
//                break;
            default:
                beforeAlias = "未知";
        }
        System.out.println("beforeAlias:"+beforeAlias);

jdk17以后的switch语法如下,直接用 ->来代替上面繁琐的赋值操作,且以,来进行多个case条件匹配赋相同的值,除了简单的赋值优化以外,还可以在赋值前进行代码块操作,在{}中进行代码操作,最后通过yield关键字进行赋值。

 String name = "项羽";
        String alias = switch (name) {
            case "周瑜" -> "公瑾";
            case "徐庶","yz" -> "元直";
            case "项羽" -> {
                System.out.println("三国");
                yield "楚霸王";
            }
            case "刘邦" -> "汉高祖";

            default -> "未知";
        };
        System.out.println("alias:" + alias);
jdk17以前,对象类型的匹配只支持  数值字符串常量  的匹配
jdk17以后switch还支持对 对象的   类型    做匹配,如下,还可对null类型做匹配。
 Object o = new Object();
        o = null;
        String str = switch (o) {
            case null -> "o is null";
            case Integer i -> String.format("Integer is %s",i);
            case Long l-> String.format("Long is %s",l);
            case Double d -> String.format("Double is %s",d);
            case String s -> String.format("String is %s",s);
            default -> o.toString();
        };
        System.out.println(str);

2.处理恶心的字符串拼接

jdk17以前字符串拼接方式,看起来是不是很难受,很繁琐,一堆转义符  \t\n的,修改起来也很麻烦,还容易出错。
 String xmlStr = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://services.xxx.com\">\n" +
                "\t\t\t\t   <soapenv:Header>  \n" +
                "\t\t\t\t   \t<check>\n" +
                "\t\t\t\t   \t\t<caller>caller</caller>\n" +
                "\t\t\t\t\t   \t<pwd>pwd</pwd>\n" +
                "\t\t\t\t\t   \t<token>token</token>\n" +
                "\t\t\t\t   \t</check>\n" +
                "\t\t\t\t   </soapenv:Header>\n" +
                "\t\t\t\t   <soapenv:Body>\n" +
                "\t\t\t\t      <ser:configAPI>\n" +
                "\t\t\t\t         <!--Optional:-->\n" +
                "\t\t\t\t         <arg0>id</arg0>\n" +
                "\t\t\t\t         <!--Optional:-->\n" +
                "\t\t\t\t         <arg1>{\"kssj\":\"start\",\"jssj\":\"end\"}</arg1>\n" +
                "\t\t\t\t      </ser:configAPI>\n" +
                "\t\t\t\t   </soapenv:Body>\n" +
                "\t\t\t\t</soapenv:Envelope>";
jdk17以后字符串拼接方式  ————在jdk15中已经提供了一个文本块的方式""" """

jdk17中对jdk15又进行增强,提供了两个 转义符 分别为     \\s
\: 置于行尾,用来将两行强制连接为一行
\s: 单个空白字符

如下的字符串,看起来是不是简洁了许多,更加美观,换行也方便,不易出错。

String xmlStr2 = """
                <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.xxx.com">" +
                   <soapenv:Header>\
                       <check>
                            <caller>%s</caller>\s
                            <pwd>pwd</pwd>
                            <token>%d</token>
                       </check>
                   </soapenv:Header>
                   <soapenv:Body>
                      <ser:configAPI>
                         <!--Optional:-->
                         <arg0>ret</arg0>
                         <!--Optional:-->
                         <arg1>{"kssj":"开始时间","jssj":"结束时间"}</arg1>
                      </ser:configAPI>
                   </soapenv:Body>
                </soapenv:Envelope>
                """;
        //如果要在以上字符串中拼接内容的话,必须要用String的format方法,然后通过占位符替换的方式进行拼接
        System.out.println(String.format(xmlStr2,"1111",1232433));

打印出来的效果如下,加\的地方,两行代码被拼接成同一行了,然后</caller>后面多出了一个可被选中的空白字符。

这个新特性我觉得在平时工作中还是有很大帮助的。


3.instanceof增强

jdk17以前  instanceof使用方式,需要    强转换

Object obj = "1";
        if (obj instanceof Integer) {
            Integer num = (Integer) obj;
            System.out.println(num);
            System.out.println("Integer");
        } else {
            String str = (String) obj;
            System.out.println(str);
            System.out.println("String");
        }

jdk17以后   instanceof 新的使用方式,在jdk14的预览版中就有了,那什么是预览版呢?

所谓预览版,其实也就是在前面的16版本中已经有这个功能了,但是没有正式投入使用,那么在jdk17中也是可以正常使用的。

如下代码中,if括号中的     obj2 instanceof Integer num2,意思是如果obj2对象如果是Integer类型的实例或其子类的话,就直接将obj2对象转化为Integer类型,然后直接赋值给num2,然后sout进行输出。这种写法看起来是不是简便多了,省了不少操作。

Object obj2 = "12121";
        if (obj2 instanceof Integer num2) {
            System.out.println(num2);
            System.out.println("Integer");
        } else if (obj2 instanceof String str2) {
            System.out.println(str2);
            System.out.println("String");
        }

4. 限制子类继承,防止子类变父类(密封类)

几个概念梳理

sealed关键字: 

         可以作用于父类、接口前,表示该类或接口为   密封类或密封接口

permits关键字:

        作用于子类前面,表示限制某个密封类的子类类型必须为哪些类型,只有permits修饰的子类才可以且只能直接继承(不能间接继承)对应的密封类(父类),而其他类不能继承该父类。

说的有点拗口,下面通过代码来解释。

密封类(父类),Animal类

如下 Animal类通过sealed关键字修饰,则Animal类为密封类,在通过permits关键字修饰Cat、Dog类,则只有Cat、Dog类才可以且他们也只能继承Animal类。

public  sealed class Animal permits Cat,Dog {
}

注意事项:Animal类和继承它的子类,必须在同一个包下面,不在同一个包下的子类,不能继承密封类或接口,如下图

既然父类有对应的关键字修饰,那么子类也同样有关键字修饰。

子类关键字相关概念:

        子类或实现类,必须使用  final或 non-sealed  这两个关键字来修饰

         final关键字:修饰子类,则该子类不能再被其它类继承

         non-sealed关键字:修饰子类,子类还可以再被其它类继承

下面通过代码来说明。

子类Cat类

1.经过final关键字修饰的Cat类,无法再被其他类继承

2.Cat类要直接继承    密封类Animal  才可以。

3. 如果Cat类先继承某个类如Test,然后Test类再继承Animal类的话,那么idea会报错提示Cannot inherit from final 'com.xch.entity.Cat'。(这种方式即为间接继承

public final class Cat extends Animal {
}

DuanWeiCat类无法继承Cat类,因为Cat类被 final关键字修饰了

子类Dog类

1.经过non-sealed关键字修饰的Dog类,可以再被其它类继承

public non-sealed class Dog extends Animal{
}

密封类的优点:

        1.更加的安全,可以限制继承的子类,避免不必要的继承

        2.更加的可控,密封类限制了继承范围,只允许在   同一个包   下的类才可以继承,这

            减少了代码的复杂性

这个特性目前我自己还没在工作中用到,但是既然有这个特性出来,那必然有它的用处。

后续的工作中应该也会用到这块功能的地方。


5.jdk有自己的lombok功能(Record类)
 

什么是Record类呢?

        其实所谓的Record类,就是我们平时创建class类时,把class关键字替换成record关键字。简单一句话描述   Record类,类似于  lombok的属性只读对象

        Record类会帮助我们生成    全参的构造方法 和  获取属性方法 (具体后面可以看字节码文件中的内容)

如下代码,Record类声明属性是在 ()中去声明的(就像是在方法中声明参数一样),而不是在{}中去声明属性。

Record类的使用场景:比较简单的一些javaBean,例如坐标轴的  x轴 和  y轴

public record UserRecord(Long userId, String userName) {

//    private Long userId;
//    private String userName;

}

Record类的使用如下:

  public static void main(String[] args) {
        //Record类型的类只提供了 有参构造方法,必须设置全部的属性
        UserRecord userRecord = new UserRecord(1L, "xch");
        Long userId = userRecord.userId();
        String userName = userRecord.userName();
        System.out.println(userId);
        System.out.println(userName);

        UserRecord userRecord2 = new UserRecord(1L, "xch");
        UserRecord userRecord3 = new UserRecord(2L, "xch");

        // Record类的 equals 会比较两个对象的 属性值 是否相同,Record类的equals会对Object类的equals进行重写(包括hashCode方法,toString方法)
        // 如果 属性值 都相同 , true,
        // 如果 属性值有一个不同, false,
        System.out.println(userRecord.equals(userRecord2));
        System.out.println(userRecord.equals(userRecord3));
    }

查看Record类的字节码文件,可以看到Record类已经帮我们生成了    全参的构造方法 和  获取属性的方法


6.优化空指针异常信息

        在我们平时工作时,在服务器中抛出空指针异常的时候,如果程序相对复杂点的话,那是不是排查起来就比较麻烦,你要判断是这里出现空指针异常,还是那里出现空指针异常了,无形中增加了我们的工作量,工作效率也比较低。

现在JDK17中出现了这样的一个新特性,可以快速帮助我们定位出现空指针异常的位置。

下面通过简单的代码加以说明。

如下,定义了一个实体类NullPointer,类中有个属性为name,然后将nullPointer对象赋为null,那么这时候去get属性的值时,就会报空指针异常。

    public static void main(String[] args) {
        NullPointer nullPointer = new NullPointer();
        nullPointer.setName("nullPointer");
        nullPointer = null;
        String name = nullPointer.getName();

        System.out.println(name);
       
    }

报错内容如下:

Exception in thread "main" java.lang.NullPointerException:

        Cannot invoke "com.xch.entity.NullPointer.getName()" because "nullPointer" is null
    at com.xch.Test.NullPointerTest.main(NullPointerTest.java:20)

Process finished with exit code 1

注意看Cannot invoke "com.xch.entity.NullPointer.getName()" because "nullPointer" is null  这行是jdk17中新的报错内容,提示说nullPointer这个对象为null,那我们就可以明确的知道出现空指针的位置是在nullPointer这个对象这里。

        当然我这里只是简单举例只写了.getName()这么一层,如果你的代码是类似于多层的get的话,如school.getStudent().getClass().getName(),这种情况下如果抛出空指针异常,我们借助jdk17的这一新特性,那是不是就可以直接从报错内容中定位空指针异常是发生在school这个对象这里呢,还是在.getStudent()这里呢,还是在.getClass()这里呢等,那这样就大大节省了我们的排查时间,提高了我们的工作效率。这个新特性我觉得对我们的工作帮助是非常大的。


7.ZGC垃圾收集器(垃圾回收不卡顿,添加虚拟机参数  

-XX:+UseZGC

        ZGC在jdk11中就已经诞生了,在jdk15中就已经转正了,然后在jdk17中就已经是非常的成熟的垃圾收集器了,而它的好处就是     程序在进行垃圾回收的时候,不卡顿。

        我们在学习JVM的时候,就会遇到一个STW,即Stop  World,世界都停止了。就是说在触发垃圾回收的时候,JVM的内存将会被冻结,所有的线程都停止运行,发生卡顿。而STW是在垃圾回收的时候触发的,这种情况是不可避免的,所以我们所能做的就是尽量减少停顿的时间。而ZGC的STW的时间是小于10ms的,几乎是感受不到的。

        同时ZGC还有一种优化性能的手段,就是它可以将堆内存设置的很大,可以设置到十几T级别大小,那么就可以大大减少ZGC的次数,从而提高应用的性能。

至此,JDK17的新特性大概有以上几种,下一篇文章将会分享一下我自己在安装多个jdk时如何切花不同jdk版本的方法及遇到的问题。

网址在这:JDK版本切换及注意事项-CSDN博客

  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一章 1.Java 编程语言刚开始 Oak 橡树 办公室外 已被注册 边喝咖啡边讨论名称 2.动态加载类别文档、字符串池(String Pool)等特性为节省内存而设计 3.jdk java development kit java 开发工具集 java se 平台包括jdkjava语言 ,(不知道编程语言是什么?可以这样想 :java 语言 ->类文件(字节码文件)->汇编语言->二进制码) 4.大多数java标准版本平台都会取个代码名称(code name),如Java SE 7 dolphin(海豚) 5.从大到小,包含与被包含:java se:java 语言、jdk(jre(jvmjava se api))。jdk包含了java程序语言、工具程序与jre,jre包括了部署技术、java se api与jvm。 6. 7.Web容器是Servlet/JSP唯一认识的HTTP服务器,是使用Java撰写的应用程序,运行于JVM之上。 8.JVMJava可以跨平台,不同的系统平台有不同的JVM,它们都认识.class文件。Java编译语言将Java代码编译成.class文件(只有一种形式),而C/C++语言将代码编译成01码,不同的操作系统的01码指令不同,这造成了不能跨平台,而Java将这个任务交给JVM,不同操作系统上的JVM将.class文件编译成不同的二进制码。 9.java se development 8uN ,其中N是JDK更新版本号。 10.java安装时要理解这三个东西,安装是否成功输入java 命令测试一下工具是否可用。 11.java安装目录详解https://zhidao.baidu.com/question/181908777.html 12.习题http://blog.csdn.net/u012965373/article/category/1779777 13.第一个Hello World 使用b语言(c语言的前身)写的 第二章 1.java程序中的空格只能是半角空格符或者tab空格符 2.一个.java文档可定义多个类,但是只能有一个公开类,而且主文档名必须与公开类名相同。 3. 4.echo %path% 是系统环境变量附加用户变量,set path="路径” %path%>系统变量>用户变量,只有通过“高级系统设置”方式则可以长久保存。 5.java指令的目的是启动jvm,然后执行指定的执行文件(.class)。windows系统的可执行文件是.exe和.bat ,Linux系统的可执行文件是有执行权限的文档。 6.java -cp/-classpath .;C:\workspace;C:\lib\abc.jar 指定jvm寻找.class文件路径的方法有三种,分别是从当前目录下寻找、某个文件夹下寻找或在链接库的jar文件中寻找。 同样,使用命令行指定classpath的方式优先于从系统读取classpath环境变量。 7.jar文档(java archive)采用的是zip格式压缩。 8. 也就是说执行javac命令时会执行到java命令。javac需要某个路径来编译当前文件,也就是那个java命令需要。所以javac和java都需要指定好所依赖的路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值