Java 11—Java 15特性

Java 11 特性详解

Http Client API
		//创建 httpClient
		HttpClient client = HttpClient.newHttpClient();

		//创建 请求的地址, uri 构建
		HttpRequest request = HttpRequest.newBuilder()
				.uri(URI.create("http://www.baidu.com/"))
				.build();

		//发送异步消息,然后把结果打印 出来
		client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
				.thenApply(HttpResponse::body) //然后应用
				.thenAccept(System.out::println)//然后同意
				.join();
增强 Java 启动器

Java 11 版本中最令人兴奋的功能之一是增强 Java 启动器,

  • 使之能够运行单一文件的 Java 源代码。
  • 此功能允许使用 Java 解释器直接执行 Java 源代码。
  • 源代码在内存中编译,然后由解释器执行。唯一的约束在于所有相关的类必须定义在同一个 Java 文件中。

而在最新的 Java 11 中新增了一个启动方式,即可以在源代码中声明类,例如:如果名为 HelloWorld.java 的文件包含一个名为 hello.World 的类,那么该命令:

$ java HelloWorld.java

也等同于:

$ javac HelloWorld.java
$ java -cp . hello.World
java 11 以及之后,可以直接运行,不会生成 class文件
 ./java .\a\Hello.java
原来运行 java

public class Hello{
	public static void main(String[] args) {
		System.out.println("Hello World");
	}
}
javac Hello.java
java Hello
用于 Lambda 参数的局部变量语法
var s = "Hello Java 11";
System.out.println(s);

Java 10 为局部变量提供隐式定义写法如下:

var x = new Foo();
for (var x : xs) { ... }
try (var x = ...) { ... } catch ...

于是在 Java 11 中将局部变量和 Lambda 表达式的用法进行了统一,并且可以将注释应用于局部变量和 Lambda 表达式:

@Nonnull var x = new Foo();
(@Nonnull var x, @Nullable var y) -> x.process(y)
ZGC:可伸缩低延迟垃圾收集器

ZGC 即 Z Garbage Collector(垃圾收集器或垃圾回收器),

这应该是 Java 11 中最为瞩目的特性,没有之一。

ZGC 是一个可伸缩的、低延迟的垃圾收集器,

  • 使用 configure 参数:--with-jvm-features=zgc 显式启用。
飞行记录器

Java 语言中的飞行记录器类似飞机上的黑盒子,

  • 是一种低开销的事件信息收集框架,
  • 主要用于对应用程序和 JVM 进行故障检查、分析。
  • 飞行记录器记录的主要数据源于应用程序、JVM 和 OS,
  • 这些事件信息保存在单独的事件记录文件中,
  • 故障发生后,能够从事件记录文件中提取出有用信息对故障进行分析。

启用飞行记录器参数如下:

-XX:StartFlightRecording

也可以使用 bin/jcmd 工具启动和配置飞行记录器:

Java 12 新特详解

Switch 表达式扩展(预览功能)
  • Switch 表达式也是作为预览语言功能的第一个语言改动被引入新版 Java 中来的,

  • 预览语言功能的想法是在 2018 年初被引入 Java 中的,

int dayNumber;
 
switch (day) {
 
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        dayNumber = 6;
        break; 
        
    case TUESDAY:
        dayNumber = 7;
        break;
        
    case THURSDAY:
    case SATURDAY:
        dayNumber = 8;
        break;
 
    case WEDNESDAY:
        dayNumber = 9;
        break;
 
    default:
        throw new IllegalStateException("Huh? " + day);
 
}

清单 2. Switch 表达式示例

int dayNumber = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
    default                      -> throw new IllegalStateException("Huh? " + day);
}

Java 13 特性详解

Socket API 重构
  • ava Socket API(java.net.ServerSocket 和 java.net.Socket)

  • 包含允许监听控制服务器和发送数据的套接字对象。

  • 可以使用 ServerSocket 来监听连接请求的端口,一旦连接成功就返回一个 Socket 对象,可以使用该对象读取发送的数据和进行数据写回操作,

  • 而这些类的繁重工作都是依赖于 SocketImpl 的内部实现,服务器的发送和接收两端都基于 SOCKS 进行实现的。

在 Java 13 之前,通过使用 PlainSocketImpl 作为 SocketImpl 的具体实现。

Java 13 中的新底层实现,

  • 引入 NioSocketImpl 的实现用以替换 SocketImpl 的 PlainSocketImpl 实现
Switch 表达式扩展(预览功能)

在 Java 12 之后,关于 Switch 表达式的写法改进为如下:

清单 4. 标签简化形式

private static String getText(int number) {
    String result = switch (number) {
        case 1, 2 -> "one or two";
        case 3 -> "three";
        case 4, 5, 6 -> "four or five or six";
        default -> "unknown";
    };
    return result;
}

而在 Java 13 中,value break 语句不再被编译,而是用 yield 来进行值返回,上述写法被改为如下写法:

清单 5. yield 返回值形式

private static String getText(int number) {
    return switch (number) {
        case 1, 2:
            yield "one or two";
        case 3:
            yield "three";
        case 4, 5, 6:
            yield "four or five or six";
        default:
            yield "unknown";
    };
}
文本块(预览功能)
 String json ="{\n" +
              "   \"name\":\"mkyong\",\n" +
              "   \"age\":38\n" +
              "}\n";

在 Java 13 引入文本块之后,写法为:

清单 7. 多行文本块写法

String html = """
                <html>
                    <body>
                        <p>Hello, World</p>
                    </body>
                </html>
                """;

 String json = """
                {
                    "name":"mkyong",
                    "age":38
                }
                """;

文本块是作为预览功能引入到 Java 13 中的,

LTS(长期支持(Long Term Support))这个词。Java13 不是长期支持

Java 14 特性详解

instanceof 模式匹配(预览阶段)

Java 14 中对 instanceof 的改进,

在以往实际使用中,

  • instanceof 主要用来检查对象的类型,
  • 然后根据类型对目标对象进行类型转换,之后进行不同的处理、实现不同的逻辑,

清单 1. instanceof 传统使用方式

if (person instanceof Student) {
    Student student = (Student) person;
   // other student operations
} else if (person instanceof Teacher) {
    Teacher teacher = (Teacher) person;
    // other teacher operations
}

Java 14 中,对 instanceof 进行模式匹配改进之后,上面示例代码可以改写成:

清单 2. instanceof 模式匹配使用方式

if (person instanceof Student student) {
    student.say();
   // other student operations
} else if (person instanceof Teacher teacher) {
    teacher.say();
    // other teacher operations
}
G1 的 NUMA 可识别内存分配
shoopingcart.buy.book.id = 99;
xception in thread "main" java.lang.NullPointerException: 
        Cannot assign field "book" because "shoopingcart.buy" is null
    at Book.main(Book.java:5)

该改进功能可以通过如下参数开启:

-XX:+ShowCodeDetailsInExceptionMessages

该增强改进特性,不仅适用于属性访问,还适用于方法调用、数组访问和赋值等有可能会导致 NullPointerException 的地方。

Record 类型(预览功能)

在以往开发过程中,被当作数据载体的类对象,在正确声明定义过程中,通常需要编写大量的无实际业务、重复性质的代码,其中包括:构造函数、属性调用、访问以及 equals() 、hashCode()、toString() 等方法,因此在 Java 14 中引入了 Record 类型,其效果有些类似 Lombok 的 @Data 注解、Kotlin 中的 data class,但是又不尽完全相同,它们的共同点都是类的部分或者全部可以直接在类头中定义、描述,并且这个类只用于存储数据而已。对于 Record 类型,具体可以用下面代码来说明:

清单 6. Record 类型定义

public record Person(String name, int age) {
    //静态定义 address
    public static String address;
	//获取name
    public String getName() {
        return name;
    }
}

对上述代码进行编译,然后反编译之后可以看到如下结果:

清单 7. Record 类型反编译结果

public final class Person extends java.lang.Record {
    
    private final java.lang.String name;//定义了name
    private final java.lang.String age;//定义了age
    
	//两个参数的构造
    public Person(java.lang.String name, java.lang.String age) { /* compiled code */ }
    
	//获取name 。原来的方法
    public java.lang.String getName() { /* compiled code */ }
    
	//toString
    public java.lang.String toString() { /* compiled code */ }
	//hashCode
    public final int hashCode() { /* compiled code */ }
	//equals
    public final boolean equals(java.lang.Object o) { /* compiled code */ }
	
    //name
    public java.lang.String name() { /* compiled code */ }
	//age
    public java.lang.String age() { /* compiled code */ }
}

根据反编译结果,可以得出,当用 Record 来声明一个类时,该类将自动拥有下面特征:

  • 拥有一个构造方法
  • 获取成员属性值的方法:name()、age()
  • hashCode() 方法和 euqals() 方法
  • toString() 方法
  • 类对象和属性被 final 关键字修饰,不能被继承,
    • 类的示例属性也都被 final 修饰,
    • 不能再被赋值使用。
  • 还可以在 Record 声明的类中定义静态属性、方法和示例方法。
    • 注意,不能在 Record 声明的类中定义示例字段,
    • 类也不能声明为抽象类等。

另外 Java 14 中为了引入 Record 这种新的类型,在 java.lang.Class 中引入了下面两个新方法:

清单 8. Record 新引入至 Class 中的方法

RecordComponent[] getRecordComponents()
boolean isRecord()

其中 getRecordComponents() 方法返回一组 java.lang.reflect.RecordComponent 对象组成的数组,

java.lang.reflect.RecordComponent也是一个新引入类,该数组的元素与 Record 类中的组件相对应,其顺序与在记录声明中出现的顺序相同,可以从该数组中的每个 RecordComponent 中提取到组件信息,

  • 包括其名称、类型、泛型类型、注释及其访问方法。

而 isRecord() 方法,则返回所在类是否是 Record 类型,如果是,则返回 true。

Switch 表达式(正式版)

之前使用 switch 语句时,在每个分支结束之前,往往都需要加上 break 关键字进行分支跳出,

  • switch 语句一般使用冒号 :来作为语句分支代码的开始,而 switch 表达式则提供了新的分支切换方式,
  • 即 -> 符号右则表达式方法体在执行完分支方法之后,自动结束 switch 分支,同时 -> 右则方法块中可以是表达式、代码块或者是手动抛出的异常。以往的 switch 语句写法如下:

清单 9. Switch 语句

int dayOfWeek;
switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        dayOfWeek = 6;
        break;
    case TUESDAY:
        dayOfWeek = 7;
        break;
    case THURSDAY:
    case SATURDAY:
        dayOfWeek = 8;
        break;
    case WEDNESDAY:
        dayOfWeek = 9;
        break;
    default:
        dayOfWeek = 0;
        break;
}

而现在 Java 14 可以使用 switch 表达式正式版之后,上面语句可以转换为下列写法:

清单 10. Switch 表达式

int dayOfWeek = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
case WEDNESDAY              -> 9;
    default              -> 0;

};
文本块(第二预览版本)

Java 14 在 Java 13 引入的文本块的基础之上,新加入了两个转义符,分别是:\ 和 \s,这两个转义符分别表达涵义如下:

  • \:行终止符,主要用于阻止插入换行符;
  • \s:表示一个空格。可以用来避免末尾的白字符被去掉。

在 Java 13 之前,多行字符串写法为:

清单 11. 多行字符串写法

String literal = "Lorem ipsum dolor sit amet, consectetur adipiscing " +
                 "elit, sed do eiusmod tempor incididunt ut labore " +
                 "et dolore magna aliqua.";

在 Java 14 新引入两个转义符之后,上述内容可以写为:

清单 12. 多行文本块加上转义符的写法

String text = """
              Lorem ipsum dolor sit amet, consectetur adipiscing \
              elit, sed do eiusmod tempor incididunt ut labore \
              et dolore magna aliqua.\
              """;

上述两种写法,text 实际还是只有一行内容。

对于转义符:\s,用法如下,能够保证下列文本每行正好都是六个字符长度

清单 13. 多行文本块加上转义符的写法

String colors = """
             red  \s
            green\s
             blue \s
             """;

同时 Java 14 还对 String 进行了方法扩展:

  • stripIndent() :用于从文本块中

  • Java 14 在 Java 13 引入的文本块的基础之上,新加入了两个转义符,分别是:\ 和 \s,这两个转义符分别表达涵义如下:

    • \:行终止符,主要用于阻止插入换行符;
    • \s:表示一个空格。可以用来避免末尾的白字符被去掉。

    在 Java 13 之前,多行字符串写法为:

    清单 11. 多行字符串写法

    String literal = "Lorem ipsum dolor sit amet, consectetur adipiscing " +
                     "elit, sed do eiusmod tempor incididunt ut labore " +
                     "et dolore magna aliqua.";
    

    在 Java 14 新引入两个转义符之后,上述内容可以写为:

    清单 12. 多行文本块加上转义符的写法

    String text = """
                  Lorem ipsum dolor sit amet, consectetur adipiscing \
                  elit, sed do eiusmod tempor incididunt ut labore \
                  et dolore magna aliqua.\
                  """;
    

    上述两种写法,text 实际还是只有一行内容。

    对于转义符:\s,用法如下,能够保证下列文本每行正好都是六个字符长度:

    清单 13. 多行文本块加上转义符的写法

    String colors = """
                 red  \s
                green\s
                 blue \s
                 """;
    

    Java 14 带来的这两个转义符,能够简化跨多行字符串编码问题,通过转义符,能够避免对换行等特殊字符串进行转移,从而简化代码编写,同时也增强了使用 String 来表达 HTML、XML、SQL 或 JSON 等格式字符串的编码可读性,且易于维护。

    同时 Java 14 还对 String 进行了方法扩展:

    • stripIndent() :用于从文本块中去除空白字符
    • translateEscapes():用于翻译转义字符
    • formatted(Object... args):用于格式化

Java 15 特性详解

Edwards-Curve 数字签名算法 (EdDSA)
  • EdDSA 具有更高的安全性和性能,

  • EdDSA是一种现代的椭圆曲线方案,具有JDK中现有签名方案的优点。

  • EdDSA将只在SunEC提供商中实现。

// example: generate a key pair and sign 。获取keyPair生成器
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
//生成 keyPair
KeyPair kp = kpg.generateKeyPair();

// algorithm is pure Ed25519。获取实例 签名
Signature sig = Signature.getInstance("Ed25519");
//初始化 签名,用 keyPair的私钥
sig.initSign(kp.getPrivate());
//更新
sig.update(msg);
//进行签名
byte[] s = sig.sign();

// example: use KeyFactory to contruct a public key
KeyFactory kf = KeyFactory.getInstance("EdDSA");
boolean xOdd = ...
BigInteger y = ...
NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdPoint(xOdd, y));
PublicKey pubKey = kf.generatePublic(pubSpec);
密封的类和接口(预览)

封闭类(预览特性),可以是封闭类和或者封闭接口,

  • 用来增强 Java 编程语言,
  • 防止其他类或接口扩展或实现它们

因为我们引入了sealed classinterfaces,这些class或者interfaces只允许被指定的类或者interface进行扩展和实现。

使用修饰符sealed,您可以将一个类声明为密封类。密封的类使用reserved关键字permits列出可以直接扩展它的类。子类可以是最终的,非密封的或密封的。

之前我们的代码是这样的。

public class Person { } //人
 
class Teacher extends Person { }//教师

但是我们现在要限制 Person类 只能被这三个类继承,不能被其他类继承,需要这么做。

// 添加sealed修饰符,permits后面跟上只能被继承的子类名称
public sealed class Person permits Teacher, Worker, Student{ } //人
 
// 子类可以被修饰为 final
final class Teacher extends Person { }//教师
 
// 子类可以被修饰为 non-sealed,此时 Worker类就成了普通类,谁都可以继承它
non-sealed class Worker extends Person { }  //工人
// 任何类都可以继承Worker
class AnyClass extends Worker{}
 
//子类可以被修饰为 sealed,同上
sealed class Student extends Person permits MiddleSchoolStudent,GraduateStudent{ } //学生
 
final class MiddleSchoolStudent extends Student { }  //中学生

很强很实用的一个特性,可以限制类的层次结构。

隐藏类

隐藏类是为框架(frameworks)所设计的,隐藏类不能直接被其他类的字节码使用,只能在运行时生成类并通过反射间接使用它们。

  • 隐藏类天生为框架设计的,在运行时生成内部的class。
  • 隐藏类只能通过反射访问,不能直接被其他类的字节码访问。
  • 隐藏类可以独立于其他类加载、卸载,这可以减少框架的内存占用。

比如在JDK8中引入的lambda表达式,JVM并不会在编译的时候将lambda表达式转换成为专门的类,而是在运行时将相应的字节码动态生成相应的类对象。

instanceof 自动匹配模式

模式匹配(第二次预览),第一次预览是 JDK 14 中提出来的。

Java 14 之前:

if (object instanceof Kid) {
    Kid kid = (Kid) object;
    // ...
} else if (object instanceof Kiddle) {
    Kid kid = (Kid) object;
    // ...
}

Java 14+:

if (object instanceof Kid kid) {
    // ...
} else if (object instanceof Kiddle kiddle) {
    // ...
}

Java 15 并没有对此特性进行调整,继续预览特性,只是为了收集更多的用户反馈,可能还不成熟吧。

垃圾回收器ZGC: 可伸缩低延迟垃圾收集器

ZGC是Java 11引入的新的垃圾收集器(JDK9以后默认的垃圾回收器是G1),

经过了多个实验阶段,自此终于成为正式特性。

  • ZGC是一个重新设计的并发的垃圾回收器,可以极大的提升GC的性能。

  • 支持任意堆大小而保持稳定的低延迟(10ms以内),性能非常可观。

  • 目前默认垃圾回收器仍然是 G1,后续很有可以能将ZGC设为默认垃圾回收器。

之前需要通过-XX:+UnlockExperimentalVMOptions -XX:+UseZGC来启用ZGC,

现在只需要-XX:+UseZGC就可以。

文本块(Text Blocks)

文本块,是一个多行字符串,它可以避免使用大多数转义符号,自动以可预测的方式格式化字符串,并让开发人员在需要时可以控制格式。

Text Blocks首次是在JDK 13中以预览功能出现的,然后在JDK 14中又预览了一次,终于在JDK 15中被确定下来,可放心使用了。

public static void main(String[] args) {
    String query = """
           SELECT * from USER \
           WHERE `id` = 1 \
           ORDER BY `id`, `name`;\
           """;
    System.out.println(query);
}

运行程序,输出(可以看到展示为一行了):

SELECT * from USER WHERE `id` = 1 ORDER BY `id`, `name`;

Java 16 特性详解

与 JDK 15 一样,JDK 16 也将是个短期版本,仅提供 6 个月的支持。预计于 2021 年 9 月发布的 JDK 17 将是一个长期支持(LTS)版本,会获得数年的支持。目前的 LTS 版本 JDK 11 则于 2018 年 9 月发布。

Java 17 特性详解

Java 开发工具包 (JDK) 17 将是一个长期支持 (LTS) 版本,预计来自 Oracle 的扩展支持将持续数年。该功能集定于 6 月 10 日冻结,届时 JDK 17 将进入初始阶段。作为 OpenJDK JDK 17 的一部分提交的功能包括:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值