JDK11相比JDK1.8有哪些新特性

这篇具有很好参考价值的文章主要介绍了JDK11相比JDK1.8有哪些新特性。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Java 11 相比 Java 8 引入了许多新的语言特性和 API,下面是一些主要的特性:

  1. HTTP Client API:Java 11 中引入了一个全新的原生 HTTP 客户端 API,用于替代老旧的 HttpURLConnection API。

  2. 动态类文件常量:Java 11 引入了动态类文件常量,可以在不加载类的情况下,将常量加入到已有的类定义中。

  3. 单元测试优化:Java 11 改善了单元测试的执行体验,引入了 @BeforeEach 和 @AfterEach 注解,简化了测试用例中的重复代码。

  4. Stream API增强:Java 11 增加了一些新的 Stream API 操作,例如 takeWhile() 和 dropWhile() 等方法。

  5. 本地变量类型推断增强:在 Java 10 中,引入了 var 关键字,可以让编译器推断出变量的类型。Java 11 进一步扩展了这个特性,在 Lambda 表达式、匿名内部类、方法引用等场景下也可使用 var 定义局部变量。

  6. ZGC:Java 11 引入了一个新的垃圾收集器 ZGC,它是一个高吞吐、低延迟的垃圾收集器,适用于大型内存应用程序。

除此之外,Java 11 还引入了其他一些小的改进,例如更好的 Unicode 支持、标准化 HTTP/2 客户端、废弃 Nashorn JavaScript 引擎等等。

垃圾收集器 ZGC

垃圾收集器 ZGC(Z Garbage Collector),它是一款可伸缩的、低停顿的垃圾收集器,专为大内存应用程序设计。下面是对 ZGC 的详细介绍:

  1. 低停顿:ZGC 的最大特点就是低停顿,即无论堆大小如何,暂停时间都不会超过 10ms。这是通过将垃圾收集任务分成小块,并与应用程序线程一起执行来实现的。

  2. 可伸缩:ZGC 是一款可伸缩的垃圾收集器,它能够处理从几百兆字节到几个太字节的堆。它可以自动调整线程数和内存使用量,以最大化吞吐量并尽可能减小延迟。

  3. 分代:ZGC 具有分代特性,它将 Java 对象分为几个年龄段,根据不同的年龄段进行垃圾收集。这种分代方式可以减少垃圾回收的工作量,提高垃圾回收效率。

  4. 关注全局吞吐量:与其他低延迟垃圾收集器不同,ZGC 关注的是全局吞吐量,而不是单个垃圾收集操作的延迟。这意味着,在任何给定时间内,ZGC 都会尽可能多地收集垃圾。

  5. 空间回收:ZGC 采用分布式的空间回收方式,它将堆空间分成多个区域,并同时进行垃圾回收和内存压缩操作,以最小化空间浪费和碎片。

ZGC运作过程

ZGC的运作过程大致可划分为以下四个大的阶段:

jdk1.8和jdk11区别,java,java,jvm,开发语言

 

  1. 并发标记(Concurrent Mark):与G1一样,并发标记是遍历对象图做可达性分析的阶段,它的初始标记 (Mark Start)和最终标记(Mark End)也会出现短暂的停顿,与G1不同的是, ZGC的标记是在指针上而不是在对象 上进行的, 标记阶段会更新染色指针中的Marked 0、 Marked 1标志位。
  2. 并发预备重分配(Concurrent Prepare for Relocate):这个阶段需要根据特定的查询条件统计得出本次收 集过程要清理哪些Region,将这些Region组成重分配集(Relocation Set)。ZGC每次回收都会扫描所有的 Region,用范围更大的扫描成本换取省去G1中记忆集的维护成本。
  3. 并发重分配(Concurrent Relocate):重分配是ZGC执行过程中的核心阶段,这个过程要把重分配集中的存 活对象复制到新的Region上,并为重分配集中的每个Region维护一个转发表(Forward Table),记录从旧对象 到新对象的转向关系。ZGC收集器能仅从引用上就明确得知一个对象是否处于重分配集之中,如果用户线程此时并 发访问了位于重分配集中的对象,这次访问将会被预置的内存屏障(读屏障)所截获,然后立即根据Region上的转发 表记录将访问转发到新复制的对象上,并同时修正更新该引用的值,使其直接指向新对象,ZGC将这种行为称为指 针的“自愈”(Self-Healing)能力。 ZGC的颜色指针因为“自愈”(Self‐Healing)能力,所以只有第一次访问旧对象会变慢, 一旦重分配集中某个Region的存活对象都复制完毕 后,这个Region就可以立即释放用于新对象的分配,但是转发表还得留着不能释放掉, 因为可能还有访问在使用这个转发表。
  4. 并发重映射(Concurrent Remap):重映射所做的就是修正整个堆中指向重分配集中旧对象的所有引用,但 是ZGC中对象引用存在“自愈”功能,所以这个重映射操作并不是很迫切。ZGC很巧妙地把并发重映射阶段要做的 工作,合并到了下一次垃圾收集循环中的并发标记阶段里去完成,反正它们都是要遍历所有对象的,这样合并就节 省了一次遍历对象图的开销。一旦所有指针都被修正之后, 原来记录新旧对象关系的转发表就可以释放掉了。

总之,ZGC 是一款非常强大的垃圾收集器,它通过低停顿、可伸缩、分代、关注全局吞吐量和分布式空间回收等特性,实现了高效、健壮的垃圾收集。如果你有大内存应用程序的需求,那么 ZGC 就是一个值得尝试的选择。

HTTP Client API

全新的 HTTP Client API,用于替代老旧的 HttpURLConnection API。相对于 HttpURLConnection,Java 11 中的 HTTP Client API 具有更好的设计、更好的性能、更好的可读性。

下面是一些 Java 11 HTTP Client API 的主要特点:

  1. 异步非阻塞:Java 11 中的 HTTP Client API 默认是异步非阻塞的,可以让应用程序在发送请求时不被阻塞。

  2. 响应流:HTTP Client API 支持从响应中获取流,这意味着在处理大文件或流式数据时,不必等待整个响应读取完毕。

  3. WebSocket 支持:Java 11 中的 HTTP Client API 也支持 WebSocket,可以与服务器交互并传递消息。

  4. HTTP/2 支持:HTTP Client API 支持 HTTP/2 协议,同时也支持老旧的 HTTP/1.1 协议。

  5. Cookie 管理:HTTP Client API 提供了一个简单的 cookie 管理器,用于处理与请求和响应相关的 cookie。

下面是一个使用 Java 11 HTTP Client API 发送 GET 请求的示例代码:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Example {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://example.com"))
                .build();
        HttpResponse<String> response =
                client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}

下面是一个使用 Java 11 HTTP Client API 发送 POST 请求的示例代码:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class Example {
    public static void main(String[] args) throws IOException, InterruptedException {
        // 创建 HttpClient 实例
        HttpClient client = HttpClient.newHttpClient();

        // 构造请求体内容
        String requestBody = "username=" + URLEncoder.encode("testuser", StandardCharsets.UTF_8) +
                "&password=" + URLEncoder.encode("testpassword", StandardCharsets.UTF_8);

        // 创建 POST 请求
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://example.com/login"))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        // 发送请求并获取响应
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        // 输出响应内容
        System.out.println(response.body());
    }
}

这个示例代码通过构建带有请求体的 POST 请求,向远程服务发送数据,并获取响应结果。在本例中,我们使用 application/x-www-form-urlencoded 格式发送请求,将用户名和密码作为请求体的一部分发送给服务器。根据实际情况,可以更改请求头和请求体的格式来适应不同的场景。

 动态类文件常量

动态类文件常量(Dynamic Constants),它允许在不修改类定义的情况下,将常量添加到已有的类定义中。实现方式是通过 javac 编译器在编译时创建一个常量属性,并在运行时读取该属性。

动态类文件常量的主要特点:

  1. 可以通过引入常量值的方式来扩展类定义,无需修改现有代码;
  2. 常量的值可以在运行时计算,这意味着它可以是任何合法的 Java 表达式;
  3. 常量是只读的,无法在运行时修改。

使用示例:

public class Example {
    // 使用 dynamic 声明常量,在编译时将其添加到 class 文件的常量池中
    private static final String myConst = dynamic("Hello, world!");

    public static void main(String[] args) {
        System.out.println(myConst);
    }

    // 定义 dynamic 方法,用于返回常量
    private static String dynamic(String s) {
        return s.toUpperCase();
    }
}

在这个示例中,我们使用 dynamic 方法声明了一个字符串常量 myConst,并将其值设置为 'Hello, world!' 的大写形式。由于这是一个动态常量,因此它的值只能在运行时计算,而不能在编译时确定。运行程序后,输出将是 "HELLO, WORLD!"

需要注意的是,动态类文件常量应该被谨慎使用,因为它会增加类文件的大小,可能会导致更大的启动时间和内存占用。

单元测试优化

Java 11 改善了单元测试的执行体验,引入了 @BeforeEach 和 @AfterEach 注解,简化了测试用例中的重复代码。

单元测试的改进,其中最突出的改进是对 assert 方法的增强。具体来说,Java 11 引入了一个新的关键字 var,可以在 assert 语句中使用。

下面是一个简单的示例:

int num = 5;
assert var result = num > 0;

 

在这个示例中,我们使用 var 关键字声明了一个变量 result,并将它和断言语句结合起来。如果 num 大于 0,则断言成功,程序继续执行;否则,程序会抛出一个 AssertionError

这种改进的主要优点是它可以使我们在 assert 语句中更灵活地使用本地变量。在以前的版本中,我们必须将变量声明和初始化都放在断言语句之外,这会导致代码冗长和混乱。

除此之外,Java 11 还增强了 JUnit5 中的测试框架,具体来说,JUnit5 引入了以下一些新功能:

  1. @DisplayName 注解:可以为测试用例添加一个自定义的名称;
  2. @Nested 注解:可以嵌套其他测试类;
  3. @Tag 注解:可以为测试用例添加一个自定义的标签,方便分类和过滤测试用例;
  4. 改进了测试生命周期方法(BeforeAll、AfterAll、BeforeEach、AfterEach)的可见性。

这些新功能进一步提高了单元测试的可读性、可维护性和可扩展性,使得单元测试在软件开发中的重要性更加突出。

@BeforeEach@AfterEach 是 JUnit5 测试框架中的两个测试生命周期注解,它们分别用于在每个测试方法执行之前和之后运行一些代码。

具体来说,@BeforeEach 注解可以用于标记一个方法,在每个测试方法执行之前都会运行这个方法。通常情况下,我们可以在这个方法中做一些准备工作,比如初始化测试数据、建立测试环境等。这样可以保证每个测试方法在执行之前都拥有一个相同的状态,避免了测试互相干扰的情况发生。

下面是一个简单的示例:

public class MyTest {
    
    @BeforeEach
    void init() {
        // 这里可以进行一些测试准备工作
    }
    
    @Test
    void testMethod1() {
        // 测试方法1
    }
    
    @Test
    void testMethod2() {
        // 测试方法2
    }
    
    @AfterEach
    void cleanup() {
        // 这里可以进行一些测试清理工作
    }
}

在这个示例中,我们定义了一个测试类 MyTest,并使用 @BeforeEach@AfterEach 注解定义了两个方法 init()cleanup()。在每个测试方法执行之前和之后,JUnit5 都会自动调用这两个方法,以便进行一些准备工作和清理工作。

需要注意的是,@BeforeEach@AfterEach 注解只能用于非静态方法且不能被继承,也就是说,它们只会影响当前测试类中的测试方法,而不会影响父类或子类中的测试方法。

总之,@BeforeEach@AfterEach 注解为我们提供了一个方便的方式,在每个测试方法执行之前和之后运行一些代码,并保证测试方法之间的独立性。

Stream API增强 

Java 11 在 Stream API 中新增了一些方法,其中一些方法是对现有方法的扩展,而另一些方法则是全新的。下面简要介绍几个 Java 11 中新增的 Stream API 方法:

  1. takeWhile() 和 dropWhile() 方法:这两个方法允许从流中获取满足(或不满足)特定条件的元素,并返回一个新的流。takeWhile() 方法获取满足条件的元素,并在遇到第一个不满足条件的元素时停止。dropWhile() 方法则剔除满足条件的元素,并在遇到第一个不满足条件的元素时开始保留元素。

使用示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// 使用 takeWhile() 方法获取满足条件的元素
List<Integer> evenNumbers = numbers.stream()
        .takeWhile(n -> n % 2 == 0)
        .collect(Collectors.toList());
System.out.println(evenNumbers); // 输出 [2]

// 使用 dropWhile() 方法过滤满足条件的元素
List<Integer> oddNumbers = numbers.stream()
        .dropWhile(n -> n % 2 == 0)
        .collect(Collectors.toList());
System.out.println(oddNumbers); // 输出 [1, 3, 4, 5, 6]

2.ofNullable() 方法:这个方法允许我们在创建流时处理可能为空的数据对象,它会将非空元素包装在一个单元素流中,否则返回一个空流。

使用示例:

String name = null;

// 使用 ofNullable() 方法创建一个包含 name 的流
Stream<String> stream = Stream.ofNullable(name);
System.out.println(stream.count()); // 输出 0

3.iterate() 方法增加了一个新的重载方法,它接收谓词函数(Predicate)作为第二个参数,用于定义何时停止迭代。这个方法允许我们按需生成无限流示例。
使用示例:

Stream.iterate(2, n -> n < 100, n -> n * n)
        .forEach(System.out::println);

这段代码将使用 iterate() 方法生成一个无限流,每次平方之后增加两倍,直到达到 100。输出结果将是 2 4 16 256

这些是 Java 11 中新增的 Stream API 方法之一,它们可以大大提高 Stream API 的灵活性和可用性。

本地变量类型推断增强 

Java 11 对 var 关键字进行了改进,主要是使其可以在一些特殊场景下使用,具体如下:

  1. var 可以在 lambda 表达式中使用。在以前的 Java 版本中,如果要声明一个无类型的变量,需要使用匿名内部类或明确指定类型。而在 Java 11 中,我们可以使用 var 关键字来简化这个过程。

      例如,下面的代码展示了如何在 lambda 表达式中使用 var 关键字:

    List<String> list = new ArrayList<>();
    list.add("hello");
    list.add("world");
    
    list.forEach((var s) -> System.out.println(s));
    

    在这个示例中,我们使用了 var 关键字来声明一个无类型的变量 s,并将它用于 forEach() 方法中的 lambda 表达式中。

  2. var 可以在 try-with-resources 语句中使用。在以前的 Java 版本中,如果要在 try-with-resources 语句中使用多个资源,需要显式地为每个资源指定类型。而在 Java 11 中,我们可以使用 var 关键字来简化这个过程。

          例如,下面的代码展示了如何在 try-with-resources 语句中使用 var 关键字:

try (var reader = new BufferedReader(new FileReader("file.txt"));
     var writer = new BufferedWriter(new FileWriter("out.txt"))) {
    // 处理文件读写操作
}

在这个示例中,我们使用了 var 关键字来声明两个无类型的变量 readerwriter,并将它们用于 try-with-resources 语句中。

需要注意的是,虽然 var 关键字可以在一些特殊场景下使用,但是它不应该被滥用。在大多数情况下,我们仍然应该为变量指定明确的类型,以提高代码的可读性和可维护性。文章来源地址https://www.toymoban.com/news/detail-588921.html

到了这里,关于JDK11相比JDK1.8有哪些新特性的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【面试题】JDK1.8新特性Stream详细介绍

    Java 8引入了Stream API,它提供了一种函数式编程的方式来处理集合数据。Stream API提供了丰富的操作方法,可以对集合进行筛选、映射、排序等操作。下面是一些常用的Stream集合操作: 筛选(Filter):使用 filter 方法可以根据指定的条件筛选出集合中符合条件的元素。例如: 上

    2024年02月16日
    浏览(39)
  • Mac安装配置jdk——jdk1.8,jdk11,jdk17

    我们日常工作中可能会在多个项目工程中来回切换,每个项目依赖的jdk版本也可能高低不同,这样会出现jdk版本高低的不兼容,工程代码编译不过,无法本地运行等问题。 那么能不能在一台电脑上装多个版本的jdk呢?多个jdk版本是否可以灵活切换呢? 答案是 可以的! 接下来

    2024年04月28日
    浏览(51)
  • Mac中安装JDK1.8和JDK11双版本并任意切换

    首先区官网下载JDK8和JDK11安装包,安装后打开bash 可以看到两个版本安装成功 然后编辑环境变量 现在在bash中输入jdk8或者jdk11就会切换版本了,输入java -version即可查看,成功!

    2024年01月19日
    浏览(48)
  • 下载的Jenkins只支持jdk11,但是项目是用的jdk1.8,怎么配置多个jdk

    我的Jenkins用的是2.375,支持java-11-openjdk,不支持java-1.8.0-openjdk。在按照官网安装jenkins Jenkins能够正常启动。 现在项目要用jdk1.8,所以为了方便在jenkins中新添加jdk,我在服务器上使用 安装open-1.8.0-openjdk,重启Jenkins,结果报错: 同时,使用命令 显示Jenkins启动使用了java-1.8.0-

    2024年02月02日
    浏览(52)
  • List<Long> 类型数据转为string字符串类型 jdk1.8新特性

    话不多说,直接上代码 这里,我们首先将 ListLong 转换为 StreamLong ,然后使用 map() 方法将每个 Long 类型的元素转换为字符串类型,再使用 Collectors.joining() 方法将所有字符串连接起来并用逗号和空格分隔。 需要注意的是, Collectors.joining() 方法返回的是一个字符串类型的结果,

    2024年02月13日
    浏览(53)
  • Java中jdk1.8和jdk17相互切换

    之前做Java项目时一直用的是jdk1.8,现在想下载另一个jdk版本17,并且在之后的使用中可以进行相互切换,我将jdk切换时所遇到的问题记录下来并分享出来供大家参考。 环境变量配置如下: 步骤1 步骤2 (注:@MAVEN_HOME%bin;是配置maven时的环境变量,如果没有安装maven就不用管)

    2024年02月03日
    浏览(62)
  • JDK1.8新特性(部分)【Lambda表达式、函数式接口】--学习JavaEE的day41

    day41 JDK1.8新特性简介 速度更快 - 优化底层源码,比如HashMap、ConcurrentHashMap 代码更少 - 添加新的语法Lambda表达式 强大的Stream API 便于并行 最大化减少空指针异常 - Optional Lambda表达式 简介 Lambda是一个匿名函数(方法), 允许把函数作为一个方法的参数 。利用Lambda表达式可以写出

    2024年04月25日
    浏览(36)
  • java jdk1.8下载与安装

    官网下载地址:Java Downloads | Oracle 打开官网链接,下滑至Java 8模块,选取自己电脑适合的版本点击下载 1.找到我们下载的安装包,双击运行 2.点击下一步 3.点击更改,修改安装目录   4.选择合适的安装位置,点击确定   5.点击下一步   6.弹出jre的安装选项,点击更改,修改

    2024年02月08日
    浏览(52)
  • 【Java基础】JDK8.0(JDK1.8)版本的下载与安装

    JDK(Java SE Development Kits)是Java程序员使用的开发环境,包含JRE和开发工具集。 JRE(Java Runtime Environment) :是Java程序的运行时环境,包含JVM和运行时所需要的核心类库。 官网地址:https://www.oracle.com/cn/java/technologies/javase/javase8u211-later-archive-downloads.html 链接:https://pan.baidu.com/

    2024年02月13日
    浏览(66)
  • java jdk1.8.0_221 安装步骤

    一、下载jdk Oracle JDK下载官网https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html下载jdk1.8.0_221. 需要注册账号登陆才能下载。 下载完成,双击jdk-8u221-windows-x64.exe,进行安装。 二、安装jdk 安装前准备工作,D盘新建文件夹JAVA,在JAVA文件夹中新建两个文件夹:jdk和

    2024年02月06日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包