1 模块系统

1.1 产生背景

  • 解决越来越臃肿的java运行环境,主要目的在于减少内存的开销,只须必要模块,而非全部jdk模块。
  • 每个公共类都可以被该项目中别的类访问,这样会导致使用了并不想访问的API
  • 本质上来讲,模块的概念是在package外再裹上一层,用模块来管理各个package的暴露和隐藏。使得代码组织上更安全

1.2 具体用用

项目结构如下
在这里插入图片描述

1.2.1 模块提供方

  • 在src目录下添加module-info.java文件
module demo {
	import com.demo;
}

1.2.2 模块需求方

module test {
	requires com.demo;
}

2 JShell命令使用

REPL(Read Eval Print Loop)意为交互式的编程环境。
JShell 是 Java 9 新增的一个交互式的编程环境工具。它允许你无需使用类或者方法包装来执行 Java 语句。它与 Python 的解释器类似,可以直接 输入表达式并查看其执行结果。
在这里插入图片描述

3 多版本兼容 jar 包

新版本java出现的时候,你的库用户需要花费多年时间才会切换到新版本。这就意味着库得去向后兼容你想要支持的最老java版本,很长时间不能使用新版本特性。多版本兼容jar功能能让你创建仅在特定版本的java环境中运行库程序选择使用的class版本
具体使用可参考:https://www.runoob.com/java/java9-multirelease-jar.html

4 语法改进

4.1 私有接口方法

在接口中使用private私有方法。我们可以使用 private 访问修饰符在接口中编写私有方法
在这里插入图片描述

4.2 钻石操作符的使用升级

钻石操作符,是官方给出的说法,其实就是之前版本的泛型操作符,图中的代码在java8中是编译不通过的,但是java9可以,这个主要涉及到匿名子类的时候
在这里插入图片描述

4.3 改进的 try-with-resources

try-with-resources 是 JDK 7 中一个新的异常处理机制,它能够很容易地关闭在 try-catch 语句块中使用的资源。所谓的资源(resource)是指在程序完成后,必须关闭的对象。try-with-resources 语句确保了每个资源在语句结束时关闭。所有实现了 java.lang.AutoCloseable 接口(其中,它包括实现了 java.io.Closeable 的所有对象),可以使用作为资源。
try-with-resources 声明在 JDK 9 已得到改进。如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
 
public class Tester {
   public static void main(String[] args) throws IOException {
      System.out.println(readData("test"));
   } 
   static String readData(String message) throws IOException {
      Reader inputString = new StringReader(message);
      BufferedReader br = new BufferedReader(inputString);
      try (BufferedReader br1 = br) {
         return br1.readLine();
      }
   }
}

以上实例中我们需要在 try 语句块中声明资源 br1,然后才能使用它。
在 Java 9 中,我们不需要声明资源 br1 就可以使用它,并得到相同的结果。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
 
public class Tester {
   public static void main(String[] args) throws IOException {
      System.out.println(readData("test"));
   } 
   static String readData(String message) throws IOException {
      Reader inputString = new StringReader(message);
      BufferedReader br = new BufferedReader(inputString);
      BufferedWritter bw = new BufferedWritter(new StringWritter());
      // 如果有多个资源则通过分号分隔
      try (br; bw) {
         return br.readLine();
      }
   }
}

5 String底层存储结构变化

String的实现底层由char[] 改为byte[],存储效率变高,调用效率同样变高。StringBuffer和StringBuilder同样改变。
JDK9 之前的库的 String 类的实现使用了 char 数组来存放字符串,char 占用16位,即两字节。
这种情况下,如果我们要存储字符 A ,则为 0x00 0x41 ,此时前面的一个字节空间浪费了。但如果保存中文字符则不存在浪费的情况,也就是说如果保存 ISO-8859-1 编码内的字符则浪费,之外的字符则不会浪费。
而 JDK9 后 String 类的实现使用了 byte 数组存放字符串,每个 byte 占用8位,即1字节。
在JDK9的String类中,维护了这样的一个属性coder,它是一个编码格式的标识,使用LATIN1还是UTF-16,这个是在String生成的时候自动的,如果字符串中都是能用LATIN1就能表示的就是0,否则就是UTF-16.

6 集合工厂方法

Java 9 List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。
这些工厂方法可以以更简洁的方式来创建集合。

  • 旧方法创建集合
 public static void main(String []args) {
      Set<String> set = new HashSet<>();
      set.add("A");
      set.add("B");
      set.add("C");
      set = Collections.unmodifiableSet(set);
      System.out.println(set);
      List<String> list = new ArrayList<>();
 
      list.add("A");
      list.add("B");
      list.add("C");
      list = Collections.unmodifiableList(list);
      System.out.println(list);
      Map<String, String> map = new HashMap<>();
 
      map.put("A","Apple");
      map.put("B","Boy");
      map.put("C","Cat");
      map = Collections.unmodifiableMap(map);
      System.out.println(map);
   }
  • 新方法创建集合
   public static void main(String []args) {
      Set<String> set = Set.of("A", "B", "C");      
      System.out.println(set);
      List<String> list = List.of("A", "B", "C");
      System.out.println(list);
      Map<String, String> map = Map.of("A","Apple","B","Boy","C","Cat");
      System.out.println(map);
  
      Map<String, String> map1 = Map.ofEntries (
         new AbstractMap.SimpleEntry<>("A","Apple"),
         new AbstractMap.SimpleEntry<>("B","Boy"),
         new AbstractMap.SimpleEntry<>("C","Cat"));
      System.out.println(map1);
   }

7 改进的 Stream API

java 9 改进的 Stream API 添加了一些便利的方法,使流处理更容易,并使用收集器编写复杂的查询。
Java 9 为 Stream 新增了几个方法:dropWhile、takeWhile、ofNullable,为 iterate 方法新增了一个重载方法。

7.1 takeWhile

有序的 Stream 中,takeWhile 返回从开头开始的尽量多的元素;在无序的 Stream 中,takeWhile 返回从开头开始的符合 Predicate 要求的元素的子集。
测试代码:

   public static void main(String[] args) {
      Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty())
         .forEach(System.out::print);      
   } 

输出:abc

7.2 dropWhile

和 takeWhile 作用相反的,使用一个断言作为参数,直到断言语句第一次返回 false 才返回给定 Stream 的子集。
测试代码:

   public static void main(String[] args) {
      Stream.of("a","b","c","","e","f").dropWhile(s-> !s.isEmpty())
         .forEach(System.out::print);
   } 

输出:ef

7.3 iterate

方法允许使用初始种子值创建顺序(可能是无限)流,并迭代应用指定的下一个方法。 当指定的 hasNext 的 predicate 返回 false 时,迭代停止。
测试代码:

   public static void main(String[] args) {
      IntStream.iterate(3, x -> x < 10, x -> x+ 3).forEach(System.out::println);
   } 

输出:3 6 9

7.4 ofNullable

可以预防 NullPointerExceptions 异常, 可以通过检查流来避免 null 值。如果指定元素为非 null,则获取一个元素并生成单个元素流,元素为 null 则返回一个空流。
测试代码

   public static void main(String[] args) {
      long count = Stream.ofNullable(100).count();
      System.out.println(count);
  
      count = Stream.ofNullable(null).count();
      System.out.println(count);
   } 

输出:1 0

8 改进的 Optional 类

Java 8 中引入,Optional 类的引入很好的解决空指针异常。在 java 9 中, 添加了三个方法来改进它的功能:
stream()
ifPresentOrElse()
or()

8.1 stream

将 Optional 转为一个 Stream,如果该 Optional 中包含值,那么就返回包含这个值的 Stream,否则返回一个空的 Stream(Stream.empty())。
测试代码:

public static void main(String[] args) {
   List<Optional<String>> list = Arrays.asList (
      Optional.empty(), 
      Optional.of("A"), 
      Optional.empty(), 
      Optional.of("B"));
      
      List<String> filteredList = list.stream()
         .flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
         .collect(Collectors.toList());
 
      List<String> filteredListJava9 = list.stream()
         .flatMap(Optional::stream)
         .collect(Collectors.toList());
 
      System.out.println(filteredList);
      System.out.println(filteredListJava9);
   }  

输出:
[A, B]
[A, B]

8.2 ifPresentOrElse

ifPresentOrElse 方法的改进就是有了 else,接受两个参数 Consumer 和 Runnable。
ifPresentOrElse 方法的用途是,如果一个 Optional 包含值,则对其包含的值调用函数 action,即 action.accept(value),这与 ifPresent 一致;与 ifPresent 方法的区别在于,ifPresentOrElse 还有第二个参数 emptyAction —— 如果 Optional 不包含值,那么 ifPresentOrElse 便会调用 emptyAction,即 emptyAction.run()。
测试代码:

   public static void main(String[] args) {
      Optional<Integer> optional = Optional.of(1);
 
      optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> 
         System.out.println("Not Present."));
 
      optional = Optional.empty();
 
      optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> 
         System.out.println("Not Present."));
   }  

输出:
Value: 1
Not Present.

8.3 or

如果值存在,返回 Optional 指定的值,否则返回一个预设的值。
测试代码

   public static void main(String[] args) {
      Optional<String> optional1 = Optional.of("Mahesh");
      Supplier<Optional<String>> supplierString = () -> Optional.of("Not Present");
      optional1 = optional1.or( supplierString);
      optional1.ifPresent( x -> System.out.println("Value: " + x));
      optional1 = Optional.empty();    
      optional1 = optional1.or( supplierString);
      optional1.ifPresent( x -> System.out.println("Value: " + x));  
   }  

输出
Value: Mahesh
Value: Not Present

9 多分辨率图像 API

Java 9 定义多分辨率图像 API,开发者可以很容易的操作和展示不同分辨率的图像了。
以下是多分辨率图像的主要操作方法:

  • Image getResolutionVariant(double destImageWidth, double destImageHeight) − 获取特定分辨率的图像变体-表示一张已知分辨率单位为DPI的特定尺寸大小的逻辑图像,并且这张图像是最佳的变体。。
  • List getResolutionVariants() − 返回可读的分辨率的图像变体列表。

10 HTTP 2 客户端

JDK9之前提供HttpURLConnection API来实现Http访问功能,但是这个类基本很少使用,一般都会选择Apache的Http Client,此次在Java 9的版本中引入了一个新的package:java.net.http,里面提供了对Http访问很好的支持,不仅支持Http1.1而且还支持HTTP2,以及WebSocket,性能比较好
测试代码

    public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
        HttpClient httpClient = HttpClient.newHttpClient();
        HttpResponse httpResponse = httpClient.send(
                HttpRequest
                        .newBuilder(new URI("http://transport.opendata.ch/v1/connections?from=Bern&to=z%C3%BCrich&datetime=2017-09-21T17%3A00")
                        ).GET().build(),
                HttpResponse.BodyHandler.asString()
        );
        int code = httpResponse.statusCode();
        System.out.println(code);
        System.out.println(httpResponse.body().toString());
    }

11 改进的 @Deprecated 注解

注解 @Deprecated 可以标记 Java API 状态,可以是以下几种:

使用它存在风险,可能导致错误
可能在未来版本中不兼容
可能在未来版本中删除
一个更好和更高效的方案已经取代它。
Java 9 中注解增加了两个新元素:since 和 forRemoval。
since: 元素指定已注解的API元素已被弃用的版本。
forRemoval: 元素表示注解的 API 元素在将来的版本中被删除,应该迁移 API。

12 JS引擎升级:Nashorn

Nashorn 项目在 JDK 9 中得到改进,它为 Java 提供轻量级的 Javascript 运行时。Nashorn 项目跟随 Netscape 的 Rhino 项目,目的是为了在 Java 中实现一个高性能但轻量级的 Javascript 运行时。Nashorn 项目使得 Java 应用能够嵌入 Javascript。它在 JDK 8 中为 Java 提供一个 Javascript 引擎。

JDK 9 包含一个用来解析Nashorn 的ECMAScript 语法树的API。这个 API 使得 IDE 和服务端框架不需要依赖 Nashorn 项目的内部实现类,就能够分析 ECMAScript 代码。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐