找回密码
 会员注册
查看: 26|回复: 0

JDK11与JDK8特性差异浅谈

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64104
发表于 2024-10-12 20:34:21 | 显示全部楼层 |阅读模式
JDK11 与 JDK8 特性差异浅谈 2024年01月18日 09:00 420 1.1 基于嵌套的访问控制如果你在一个类中嵌套了多个类,各类中可以直接访问彼此的私有成员。因为 JDK11 开始在 public 、protected 、private 的基础上,JVM 又提供了一种新的访问机制:Nest我们先来看下 JDK11 之前的如下案例:class Outer {  private int outerInt;  class Inner { public void test() {   System.out.println("Outer int = " + outerInt); }  }}在 JDK11 之前 执行编译的最终结果的 class 文件形式如下:class Outer {  private int outerInt; public int access$000() {   return outerInt;  }}class Inner$Outer {  Outer outer;  public void test() {    System.out.println("Outer int = " + outer.access$000());  }}以上方案虽然从逻辑上讲,内部类是与外部类相同的代码实体的一部分,但它被编译为一个单独的类。因此,它需要编译器创建合成桥接方法,以提供对外部类的私有字段的访问。这种方案一个很大的坑是反射的时候会有问题。当使用反射在内部类中访问外部类的私有成员 outerInt 时会报 IllegalAccessError 错误。这个是让人不能理解的,因为反射还是源码级访问的权限。class Outer {  private int outerInt;  class Inner {    public void test() throws Exception {     System.out.println("Outer int = " + outerInt);      // JDK 11 之前,如下代码报出异常:IllegalAccessException      Class c = Outer.class ;      Field f = c.getDeclaredField("outerInt");      f.set(Outer.this, 23);    }  }  public static void main(String[] args) throws Exception {    new Outer().new Inner().test();  }}JDK11 开始,嵌套是一种访问控制上下文,它允许多个 class 同属一个逻辑代码块,但是被编译成多个分散的 class 文件,它们访问彼此的私有成员无需通过编译器添加访问扩展方法,而是可以直接进行访问,如果上述代码可以直接通过反射访问外部类的私有成员,而不会出现权限问题,请看如下代码:class Outer {  private int outerInt;  class Inner {    public void test() throws Exception {      System.out.println("Outer int = " + outerInt);      // JDK 11 之后,如下代码不会出现异常      Class c = Outer.class ;      Field f = c.getDeclaredField("outerInt");      f.set(Outer.this, 23);    }  }  public static void main(String[] args) throws Exception {    new Outer().new Inner().test();  }}1.2 Java 平台级模块系统Java9 的定义功能是一套全新的模块系统。当代码库越来越大,创建复杂,盘根错节的“意大利面条式代码”的几率呈指数级的增⻓。这时候就得面对两个基础的问题:很难真正地对代码进行封装,而系统并没有对不同部分(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到,这样就会导致无意中使用了并不想被公开访问的 API 。此外,类路径本身也存在问题:你如何知晓所有需要的 JAR 都已经有了,或者是不是会有重复的项呢?模块系统把这俩个问题都给解决了。模块化的 JAR 文件都包含一个额外的模块描述器。在这个模块描述器中,对其它模块的依赖是通过 “ requires ” 来表示的。另外“ exports ”语句控制着哪些包是可以被其它模块访问到的。所有不被导出的包默认都封装在模块的里面。Java 平台本身也使用自己的模块系统进行了模块化。通过封装 JDK 的内部类,平台更安全,持续改进也更容易。以下是 Java9 平台级模块系统的优势:代码内聚,容易维护:模块化可以帮助开发人员在构建、维护和改进软件系统(尤其是大型系统)时提高工作效率。降低复杂度:模块化在包之上提供更高层次的聚合,使得代码更易于理解和管理。提供更好的伸缩性和扩展性:模块化使得 JavaSE 程序更加容易轻量级部署,改进了组件间的依赖管理。改进性能和安全性:模块中的包只有在模块显式导出时可供其他模块访问,即使如此,其他模块也无法使用这些包,除非它明确指出它需要其他模块的功能。由于潜在攻击者只可以访问较少的类别,因此提高了平台的安全性。更佳的平台完整性:在 Java9 之前,您可以使用平台中许多不预期供应用使用的类别,通过强封装,这些内部API真正会被封装并隐藏在使用该平台的应用中。可扩展的 Java 平台:现在,平台被模块化为 95 个模块(此数字可能随着 Java 的发展而变化),您可以创建定制运行时,其中仅包含应用所需的模块或目标设备。1.3 JShell(交互式 Java REPL)JDK9 中的 JShell 让 Java 具有交互式编程环境。现在可以从控制台启动 JShell ,并直接启动输入和执行 Java 代码。JShell 的即时反馈使它成为探索 API 和尝试语言特性的好工具。jshell> int a = 5;a ==> 5jshell> int b = 10;b ==> 10jshell> System.out.println("The sum of " + a + " and " + b + " is " + sum);The sum of 5 and 10 is 151.4 根证书颁发认证根证书是一种特殊的证书,它在公开密钥基础设施( PKI )中,起着信任链的起点的角色。根证书是属于根证书颁发机构( CA )的公钥证书,这个机构的角色有如现实世界中的公证行,保证网络世界中电子证书持有人的身份。具体来说,根证书是用来签发其他证书的,它自己的签发者就是它本身。许多应用软件(例如操作系统、网页浏览器)会预先安装可被信任的根证书,这代表用户授权了应用软件代为审核哪些根证书机构属于可靠。OpenJDK 和 OracleJDK 在 JDK9 之前处理根证书方面有所不同,这会影响到它们的构建过程。通过改进根证书的颁发和认证,可以使 OpenJDK 对开发人员更具吸引力,并减少 OpenJDK 和 OracleJDK 构建之间的差异。1.5 私有接口方法JDK8 为我们带来了接口的默认方法。接口现在也可以包含行为,而不仅仅是方法签名。但是,如果在接口上有几个默认方法,代码几乎相同,会发生什么情况?通常,您将重构这些方法,调用一个可复用的私有方法。但默认方法不能是私有的。将复用代码创建为一个默认方法不是一个解决方案,因为该辅助方法会成为公共 API 的一部分。使用 JDK9 ,您可以向接口添加私有辅助方法来解决此问题。如果您使用默认方法开发 API ,那么私有接口方法可能有助于构建其实现。1.6 增强的 try-with-resources这是 JDK9 中引入的一项新特性,称为 " 增强的 try-with-resources "。在 JDK7 中引入的原始 try-with-resources 语句要求您在 try 语句中声明和初始化一个或多个资源。这些资源在 try 代码块结束时自动关闭。然而,在 JDK9 中,如果您已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。例如,以下是 JDK7 的 try-with-resources 语句:try (BufferedReader br = new BufferedReader(new FileReader(path))) {  return br.readLine();}在 JDK9 中,如果 br 已经被声明并初始化,那么你可以这样写:BufferedReader br = new BufferedReader(new FileReader(path));try (br) {  return br.readLine();}在 JDK9 中增强的 try-with-resources 语句中,当 try 代码块执行完毕后,系统会自动调用资源对象的 close() 方法来关闭资源。这就是为什么我们使用 try-with-resources 语句,它可以帮助我们自动管理资源,避免因忘记关闭资源而导致的资源泄露问题。如果你试图再次从 br 读取数据,将会抛出 IOException1.7 实施 ChaCha20 和 Poly1305 加密算法ChaCha20 是一种相对较新的流密码,可以取代旧的、不安全的 R4 流密码。ChaCha20 将与 Poly1305 验证器配对。ChaCha20 和 Poly1305 加密算法在许多场景中都有应用,特别是在需要数据加密和数据完整性验证的场合。以下是一些具体的应用场景:网络通信安全:ChaCha20 和 Poly1305 经常一起使用,形成了被广泛应用的 ChaCha20-Poly1305 加密方案。例如,Google 选择了伯恩斯坦设计的,带 Poly1305 消息认证码的 ChaCha20 ,作为 OpenSSL 中 RC4 的替代品,用以完成互联网的安全通信。Google 最初实现了 HTTPS (TLS/SSL) 流量在 Chrome 浏览器( Android 手机版)与 Google 网站之间的通信。软件性能优化:由于 ChaCha20-Poly1305 在没有硬件加速的情况下,通常比 AES-GCM 有更快的软件性能,因此在需要高性能加密的软件中,ChaCha20-Poly1305 是一个很好的选择。数据完整性验证:Poly1305 可以用作一次性消息认证码,用于验证单个消息的完整性和真实性,隐藏单个消息的内容。1.8 局部变量 var 类型推断在 JDK10 中引入的 var 关键字,允许编译器根据变量的初始赋值来推断出它的类型。这种类型推断可以使代码更简洁,提高代码的可读性。var rs = "itheima";System.out.println(rs);就等于:String rs = "itheima"局部变量推断对于较复杂的类型也有很好的简化作用,如下是对Map集合的遍历方式的简化:public class Demo01 {  public static void main(String[] args) {    Map maps = new HashMap();    // 1.添加元素:添加键值对元素    maps.put("iphoneX" , 1);    maps.put("huawei" , 8);    maps.put("Java" , 1);    /*    Set> entries = maps.entrySet();    for(Map.Entry entry : entries){      String key = entry.getKey();      Integer value = entry.getValue();    }    */    var entries = maps.entrySet();    for(var entry : entries){      String key = entry.getKey();      Integer value = entry.getValue();    }  }}在 JDK11 中,var 关键字可以用于 lambda 表达式的参数。这意味着我们可以在 lambda 表达式的参数上添加注解。例如,我们可以使用 @Deprecated 注解来标记一个参数已经被废弃或不推荐使用。需要注意的是,如果在lambda表达式中使用了 var 来声明参数,那么所有的参数都必须使用 var 来声明。List nums = new ArrayList();Collections.addAll(nums , 9 , 10 , 3 );nums.sort((@Deprecated var o2 , @Deprecated var o1) -> o2 - o1);var 局部变量语法注意事项:不可以直接 var a; ,因为无法推断。类的属性的数据类型不可以使用 var 。var 不同于 js ,类型依然是静态类型,var 不可以在 lambda 表达式中混用。(var a, b) -> a + b1.9 String 新增处理方法如以下所示,JDK11 新增了一些对于 String 的处理方法。// 判断字符串是否为空白System.out.println(" ".isBlank()); // true// 去除首尾空白System.out.println(" itheima ".strip()); // 可以去除全角的空白字符System.out.println(" itheima ".trim()); // 不能去除全角的空白字符// 去除尾部空格System.out.println(" itheima ".stripTrailing());// 去除首部空格System.out.println(" itheima ".stripLeading());// 复制字符串System.out.println( "itheima".repeat( 3 )); // itheimaitheimaitheima// 行数统计System.out.println("A\nB\nC".lines().count()); // 3 ;1.10 集合新增的 API集合( List / Set / Map )都添加了 of 和 copyOf 方法,它们两个都用来创建不可变的集合。// List的增强apiList list = List.of("aa", "bb", "cc", "dd");// Set的增强apiSet set1 = Set.of(100, 30, 20, 15);// Map的增强apiMap map = Map.of("a", 1, "b", 2, "c", 3);使用 of() 方法创建的集合,为不可变集合,不能进行添加、删除、替换、排序等操作, 不然会报 java.lang.UnsupportedOperationException 异常。// 把List集合转换成数组// JDK 11 前的方式Integer[] nums 1 = list.toArray(new Integer[ 0 ]);// JDK 11 开始之后新增方式Integer[] nums 2 = list.toArray(Integer[]::new);takeWhile:从集合开头提取符合条件的元素public void test2() {      List res = Stream.of( 1, 2, 3, 4, 0, 1 )              .takeWhile( n -> n  res = Stream.of( 1, 2, 3, 4, 0, 1 )              .dropWhile( n -> n  optional = Optional.of("java");optional.orElseThrow(); // 返回 "java"Optional.stream():如果值存在,返回一个包含值的 Stream,否则返回一个空的 Stream 。Optional optional = Optional.of("java");optional.stream().count(); // 返回 1Optional.or(Supplier):如果值存在,返回包含的值,否则返回从指定 Supplier 接口生成的值。Optional optional = Optional.ofNullable(null);optional.or(() -> Optional.of("java")).get(); // 返回 "java"1.12 更方便的 IO此前我们需要使用 Paths.get() 。现在,我们像其他类一样使用 of() 。of(String, String...)writeString(Path, CharSequence) 我们可以使用该方法来保存一个 String 字符串。Files.writeString(Path.of("test.txt"), "Hello!!!")readString(Path) 我们可以使用该方法来读取一个 String 字符串。Files.readString(Path.of("test.txt"), StandardCharsets.UTF_8);nullReader() 使用该方法,我们可以得到一个不执行任何操作的 Reader 。nullWriter() 使用该方法,我们可以得到一个不执行任何操作的 Writer 。nullInputStream() 使用该方法,我们可以得到一个不执行任何操作的 InputStream 。nullOutputStream() 使用该方法,我们可以得到一个不执行任何操作的 OutputStream 。InputStream 还终于有了一个非常有用的方法:transferTo ,可以用来将数据直接传输到 OutputStream ,这是在处理原始数据流时非常常见的一种用法,如下示例:try (var is = Demo01.class.getResourceAsStream("dlei.txt");  var os = new FileOutputStream("stream01.txt")) {  is.transferTo(os); // 把输入流中的所有数据直接自动地复制到输出流中}1.13 Java HTTP 客户端从 JDK9 开始引入了一个处理 HTTP 请求的的 HTTP Client API,不过当时一直处于孵化阶段,而在 JDK11 中已经为正式可用状态,作为一个标准API提供在java.net.http供大家使用,该 API 支持同步和异步请求,取代繁琐的 HttpURLConnection 的请求。以下是 HTTP Client 的用法:同步请求:// 1 .创建HttpClient对象。var client = HttpClient.newHttpClient();// 2 .创建请求对象:request,封装请求地址和请求方式get.var request = HttpRequest.newBuilder()   .uri(URI.create("http://api.com:8899/?appkey=10003&format=json"))   .GET().build();// 3 .使用HttpClient对象发起request请求。得到请求响应对象responseHttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());// 4 .得到响应的状态码信息System.out.println(response.statusCode());// 5 .得到响应的数据信息输出System.out.println(response.body());异步请求:// 1 .创建HttpClient对象。var client = HttpClient.newHttpClient();// 2 .创建请求对象:request,封装请求地址和请求方式get.var request = HttpRequest.newBuilder()   .uri(URI.create("http://api.com:8899/?appkey=10003&format=json"))      .GET().build();// 3 .使用HttpClient对象发起request异步请求。得到请求响应对象futureCompletableFuture> future =      client.sendAsync(request, HttpResponse.BodyHandlers.ofString());// 4 .监听future对象的响应结果,并通过join方法进行异步阻塞式等待。future.whenComplete((resp,ex) - > { if(ex != null ){   ex.printStackTrace();  } else{    System.out.println(resp.statusCode());    System.out.println(resp.body());  }}).join();1.14 Unicode10目标:升级现有平台的 API ,支持 Unicode10 ,Unicode10 的标准请参考网站(http://unicode.org/versions/Unicode10.0.0)目前支持最新的 Unicode 的类主要有java.lang 包下的 Character、Stringjava.awt.font 下的相关类java.text 包下的 Bidi、Normalizer 等String 对 Unicode 的示例:System.out.println("\uD83E\uDD93");System.out.println("\uD83E\uDD92");System.out.println("\uD83E\uDDDA");System.out.println("\uD83E\uDDD9");System.out.println("\uD83E\uDDD1");System.out.println("\uD83E\uDDD8");System.out.println("\uD83E\uDD95");System.out.println("\uD83E\uDD2e");1.15 改进 Aarch64 函数改进现有的字符串和数组函数,并在 Aarch64 处理器上为 java.lang.Math 下的 sin 、cos 和 log 函数实现新的内联函数。从而实现专用的 CPU 架构下提高应用程序的性能。代码示例:public static void main(String[] args) {  long startTime = System.nanoTime();  for(int i = 0 ; i 
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 12:29 , Processed in 0.709136 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表