当前位置: 首页 > 图灵资讯 > 技术篇> Java新特性(一)

Java新特性(一)

来源:图灵教育
时间:2023-07-04 10:07:38

JShell

JShell是Java的交互式编程环境,由Java9正式发布,可以像Python一样直接输入表达式,然后输出结果。

  1. 1.启动 JShell

$ JShell|  欢迎使用 JShell -- 版本 17.0.2|  对这个版本有一个大致的了解, 请键入: /help introjshell>

  1. 1.退出JShellll

jshell> /exit|  再见$

  1. 1.帮助命令

jshell> /help

  1. 1.执行简单的命令

jshell> System.out.println("Hello word!");Hello word!jshell> 1+1$2 ==> 2jshell>

  1. 1.打开编辑器

打开编辑器后,以前缓存器中的内容将存在

jshell> /edit

目的:JShell在处理简单的小逻辑并验证简单的小问题时,比IDE更有效率。然而,使用复杂逻辑的验证JShell 也许不是最好的选择。在这个时候,它可以被使用IDE 或者可编译的代码更合适。

代码块(text blocks)

在 JDK 13 以预览版的形式发布。在 JDK 14 改进后的文字块再次以预览版的形式发布。最后,文字块在 JDK 15 正式发布。

目的:主要是为了解决Java中复杂字符串难以书写和阅读的问题,并使用大量的转义字符进行格式化。

文字块由零个或多个内容字符组成,从分隔开始到分隔结束。开始分隔符由三个双引号字符组成 (""") ,随后的零或多个空间,以及由行结束符组成的序列。结束分隔符是由三个双引号字符组成的 (""") 组成的序列。

public class TextBlocksDemo {    public static void main(String[] args) {        String textBlock = """                <!DOCTYPE html>                <html>                    <body>                        <h1>"Hello World!"</h1>                    </body>                </html>                """;        System.out.println(                "Here is the text block:\n" + textBlock);    }}

文本块不再需要特殊字符、开始分离符和结束分离符的格式安排。我们几乎可以直接复制和粘贴我们在代码中看到的文本块和实际要表达的文本,而不需要特殊处理。

注意:

  • •开始分隔符必须单独形成三个双引号字符后面的空格和换行符属于开始分隔符。结束分隔符不能独立行。
  • •结束分隔符只有一个由三个双引号字符组成的序列。结束分隔符前的字符,包括换行符,都是文字块的有效内容。
  • •能够处理 Java 源代码中的缩进空格应删除所有文本内容行和结束分隔符共享的前导空格,以及所有文本内容行的尾部空格。
  • •文字块在编译期处理,并在编译期转换为常数字符串。因此,传统方式声明的字符串与使用文字块声明的字符串内容相同。它们指向相同的内存地址,代表相同的对象。
  • •与字符串相关的API可用于文字块

传统字符串和文字块:

// 使用传统方式声明的字符串和使用文字块声明的字符串,内容相同,指向相同的对象。String testBlock1 = """                this is testBlock!                testBlock!                """;String test = "this is testBlock!\n" +  "testBlock!\n";System.out.println(testBlock1.equals(test)); //true// 与字符串相关的System可用于文字块.out.println("""                this is testBlock!                """.length());   //19

删除前空格的规则:

// 左对齐会吃掉左边所有的空格String textBlock = """... this is testBlock!... this is testBlock!...     this is testBlock!...         this is testBlock!...""";// 没有左对齐,最左边是String textBlock = """...     this is testBlock!...     this is testBlock!...         this is testBlock!...            this is testBlock!...""";// String结束分隔符合最后一行的前空间将被删除 textBlock = """... this is testBlock!... this is testBlock!...     this is testBlock!...         this is testBlock!...""";

尾部保留空格:

// 可以使用\s转义字符保留尾部的空间 textBlock = """... this is testBlock!    \s!!!!... this is testBlock!             \s... this is testBlock!...""";

长段落:

// 使用\可以表示长段落,下一行的内容将合并到当前的展示中,并保留\之前的空格String textBlock = """         this is testBlock!         this is testBlock! this is testBlock! this is testBlock!     \         this is testBlock!         this is testBlock!        """;

档案类(record)

在 JDK 14 以预览版的形式发布。在 JDK 15 改进后的档案类别再次以预览版的形式发布。最后,档案类别在 JDK 16正式发布。

文件类:用于表示不可变数据的透明载体。

实现

使用record实现一个不可变圆,并找出半径:

public record Circle(Double radius) implements Shape {    @Override    public double area() {        return Math.PI * radius * radius;    }}

相当于我们以前用class关键词实现的:

public final class Circle implements Shape {    private final Double radius;    public Circle(Double radius) {        this.radius = radius;    }    @Override    public double area() {        return Math.PI * radius * radius;    }    public Double radius() {        return radius;    }    @Override    public boolean equals(Object o) {        if (this == o) {            return true;        }        if (o == null || getClass() != o.getClass()) {            return false;        }        Circle circle = (Circle) o;        return Objects.equals(radius, circle.radius);    }    @Override    public int hashCode() {        return Objects.hash(radius);    }    @Override    public String toString() {        return String.format("Circle[radius=%f]", radius);    }}

特点
  • •不可变数据
  • •默认继承档案类 java.lang.Record,用户不能再使用extends来指定或定制他的父亲来影响档案行为
  • •档案类似于final修改的类,不能由abstract修改,其他对象不能继承档案类
  • •档案类中申报的所有属性都是不可变的(相当于final修改的属性)
  • •档案不能声明可变变量或支持实例初始化的方法。我们只能使用文件形式的结构方法,以避免额外的初始化对可变性的影响。
  • •档案类不能声明本地(native)方法(native方法使用本地库,可以通过修改本地库中的代码来修改属性值,因此禁止使用native进行修改)。
  • •透明的载体
  • •档案类内置全参结构方法,equals 方法、hashCode 方法、toString 读取不可变数据的方法、方法

  • •如果我们对内置方法不满意,我们也可以重写record对象的构造方法equals 方法、hashCode 方法、toString 方法

注:通常情况下,不建议重写record对象中的内置方法

重写结构方法
  1. 1.常规形式

public Circle(Double radius) {  if (radius<=0) {    throw new IllegalArgumentException();  }  this.radius = radius;}

  1. 1.简化形式

// 可省略参数,省略赋值句,只做参数验证public Circle {  if (radius<=0) {    throw new IllegalArgumentException();  }}

封闭类(sealed classes)

在 JDK 15 以预览版的形式发布。在 JDK 16 改进后的封闭类以预览版的形式再次发布。最后,封闭类在 JDK 17 正式发布。

封闭类:用于限制接口或对象的扩展要求,并将对象的可扩展性放在可预测的范围内(在创建对象时预测其实现类)。

实现

//sealed表示Car是一个封闭的接口,permits表示Car接口只有两个实现AudiCar和Bmwcarpublic。 sealed interface Car permits BmwCar,AudiCar{    String engine();    String tire();}// 要求强制使用final进行修改,否则不会通过public进行编译 record AudiCar() implements Car {    @Override    public String engine() {        // ...    }    @Override    public String tire() {        // ...    }}public record BmwCar() implements Car {    @Override    public String engine() {        // ...    }    @Override    public String tire() {        // ...    }}

sealed声明需要满足:

  • sealed可申明类、抽象类和接口类
  • •被sealed修饰的封闭类必须有相应的实现(许可类)
许可类(permits)

permits声明需要满足:

  • •许可类必须在同一个包或同一个源文件下与封闭类相同
  • •在permits之后,不需要在同一源文件下解释许可类
  • •许可证类可以通过修改符验证是否继续关闭
  • •被final修改对象,继续关闭,关闭可扩展性
  • •被sealed继续修改,进行限制性扩展
  • •被non-sealed修改,关闭封闭,支持扩展
  • •未与封闭类属于同一源文件或未被封闭类permits不能实现或继承封闭对象
  • •因为许可类必须是封闭类的直接扩展,所以许可类不具有传递性(父类定义的许可类不能提供给孙子类)。

Sealed继续修饰许可类:

// NewenergyCar也是一个封闭的public sealed interface Car permits NewEnergyCar {    String engine();    String tire();}// 继续使用sealed进行封闭扩展,然后用permits说明许可类publicic sealed abstract class NewEnergyCar implements Car permits XiaoMiCar {}public final class extends NewEnergyCar {    //...}

non-sealed修饰许可类:

public sealed interface Car permits GasolineCar {    String engine();    String tire();}// 许可类被non-sealed修改封闭,支持扩展publicicc non-sealed class GasolineCar implements Car{    // ...}// 因为GasolineCar被nonn-sealed,因此,支持扩展publiciclicc的扩展icc class ModernCar extends GasolineCar{}