> For the complete documentation index, see [llms.txt](https://yangsx95.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yangsx95.gitbook.io/notes/programming-language/java/java-te-xing/java9-te-xing.md).

# java9特性

## 语法变更

### 钻石操作符

在Java8中，匿名内部类不支持使用钻石操作符：

```java
Comparator<String> comparator = new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return 0;
    }
};
```

在Java9中，已经支持匿名内部类泛型推断：

```java
Comparator<String> comparator = new Comparator<>() {
    @Override
    public int compare(String s1, String s2) {
        return 0;
    }
};
```

### try 语句升级

```java
InputStreamReader isr = new InputStreamReader(new FileInputStream("d:/aaa.txt"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:/aaa.txt"));
try (isr; osw) {
    isr.read();
} catch(Exception e) {
    e.printStrackTrace();
}
```

### 下划线标识符限制

Java8可以单独使用下划线定义变量，而Java9中则不允许了。

```java
String _  = ""; // Java8 编译通过，Java9报错
```

## API变更

### 接口中的私有方法

Java9中可以在Interface中定义private方法:

```java
public interface MyInterface {

    private int add(){
        // xxx
    }

}
```

### String底层存储结构

String的存储结构由 `char[]` 变为了 `byte[]`

### Stream API新增方法

Stream新增四个API方法：

```java
// takeWhile，从头遍历并取出符合条件的集合元素，当遇到不符合的元素就停止处理
// 从头遍历整型集合中的偶数，当遇到一个奇数时，就退出
list.stream().takeWhile(e -> e % 2 == 0).forEach(System.out::println);

// dropWhile，从头遍历并删除符合条件的集合元素，当遇到不符合的元素就停止处理
// 从头遍历整型集合中的偶数并删除这个偶数，当遇到一个奇数时，就退出
list.stream().dropWhile(e -> e % 2 == 0).forEach(System.out::println);

// ofNullable，允许创建Stream时，创建一个仅有一个null值作为元素的Stream
Stream.of(null); // 报错
Stream.ofNullable(null) // 不报错

// iterate，给定一个种子，指定条件和迭代方式来获取流
// 1.8中已经存在generate和iterate方法
// 随机10个数，然后打印
Stream.generate(Math::radom).limit(10).forEach(System::out::println);
// 生成10个数，从0开始，每个数间隔增加2
Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
// java9提供了对iterate的重载，功能与上一行代码类似
Stream.iterate(0, t -> t < 10, t -> t + 1).forEach(System.out::println);
```

此外，Stream的一些方法实现了与Optional的结合：

```java
Optional<Integer> maxOptional = list.stream().max();

// Optional也可以获取到他的Stream
maxOptional.stream();
```

### InputStream新增API

InputStream新增`transferTo`方法，此方法会创建缓冲区使用while循环将inputStream中的内容拷贝到outputStream中：

```java
InputStream in = new FileInputStream("d:/aaa.txt");
OutputStream out = new FileOutputStream("d:/bbb.txt");
in.transferTo(out);
```

### 创建只读集合的方法

```java
// java9之前
// 使用Arrays.asList
List<Integer> list1 = Arrays.asList(1, 2, 3);
// 使用Collections 将非只读集合变为只读集合
list = Collections.unmodifiableCollection(list);

// java9创建只读集合
List.of(1, 2, 3);
Set.of(1, 2, 3);
Map.of(k1, v1, k2, v2, ...);
```

## JShell

可以运行java片段的shell窗口。支持的主要命令：

1. `/list` 列出执行的所有片段
2. `/imports` 列出已经导入的包
3. `/edit` 编辑所有片段
4. `/open 文件地址` 调用本地的某个java脚本
5. `/exit`

## 模块化

谈到Java9大家往往第一个想到的就是Jigsaw项目（后改名为Modularity）。众所周知，Java已经发展超过20年(95年最初发布)，Java和相关生态在不断丰富的同时也越来越暴露出一些问题:

1. Java运行环境的膨胀和臃肿。**每次JVM启动的时候，至少会有30\~ 60MB的内存加载，主要原因是JVM需要加载rt.jar**,不管其中的类是否被classloader加载，第一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程序运行需要的class)
2. 当代码库越来越大，创建复杂，盘根错节的“意大利面条式代码”的几率呈指数级的增长。不同版本的类库交叉依赖导致让人头疼的问题，这些都阻碍了Java 开发和运行效率的提升。
3. 很难真正地对代码进行封装,而系统并没有对不同部分(也就是JAR文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到，这样就会导致无意中使用了并不想被公开访问的API.

什么是模块化：

1. 模块化是在package外的新的一层，一个src目录只能声明为一个模块
2. 在src根目录建立 `module-info.java`，声明module
3. 模块之间的可访问性是所使用的模块和使用模块之间的双向协议，在该文件中可以声明当前模块的依赖，以及当前模块暴露的包

### IDEA Jdk9 模块化工程

定义service模块：

```java
module service {
    // Service 暴露接口包
    exports com.yangsx95.api;
    
    // 依赖java的sql包
    requires java.sql;
}
```

定义api模块，依赖service模块：

```java
module api {
    // 暴露api包下的所有类，但是不包括子包，比如`com.yangsx95.api.impl`包
    exports com.yangsx95.api;

    // 依赖service模块
    requires service;
}
```

### Maven + Jdk9 模块化工程

Maven 本身对模块化的支持已经非常好了，引入java模块化，主要是对包中的类进一步进行访问权限控制。
