Java9について調べたこと

# 概要
そろそろJava10(18.3と言うのかな？)が登場するようなので、9で追加された機能で調べた事と試した事を記載しています。

# 調べたこと
## JShell
JShellが導入されました。
対話形式でコマンドラインからコードを実行する事ができます。
簡単なコードを実行したいときに、クラスファイルを使って実行とかの手間を省くことが出来ます。

![helloworld.jpg](https://qiita-image-store.s3.amazonaws.com/0/206289/024bfada-a1ab-063b-510c-64408dfb59f6.jpeg)

## List.of、Set.of、Map.of
コレクションクラスにファクトリメソッドが追加されました。

```java
List<String> list = List.of("コーヒー牛乳", "いちご牛乳");
Set<String> set = Set.of("れもん牛乳", "めろん牛乳");
Map<String, String> map = Map.of("コーヒー牛乳", "100円", "いちご牛乳", "120円");
```

ofメソッドで生成したコレクションはイミュータブルになります。

## モジュール機能
モジュール機能の導入により、モジュールの公開範囲・依存関係の明確化などが出来るようになりました。
ライブラリなどのpublicメソッドが、使用される事を想定していないクラスで参照されていた・・・
みたいな事も防止する事が出来る。
参考：[Project Jigsaw](https://codezine.jp/article/detail/10524)

### モジュール機能を使わない場合
```text:呼び出される側（jar）のフォルダ構成（1）
gyunyu/
　┗━　src/
　　　　┗━　jp/gr/java_conf/masakado/gyunyu/
　　　　　　　┣━　Coffee.java
　　　　　　　┗━　util/
　　　　　　　　　　┗━　Utility.java
```

```java:Coffee.java
public class Coffee {
	public void print() {
		Utility.output("コーヒー");
	}
}
```

```java.Utility.java
public class Utility {
	public static void output(String name) {
		System.out.println("これは、" + name + "牛乳です。");
	}
}
```

`Utility.output(...)`は、gyunyuプロジェクト内だけで使う事を想定しており、
外部から実行される事を想定していないメソッドです。

上記2ファイルをコンパイルしてgyunyu.jarを作成する。

```
javac -d bin -encoding UTF-8 src\jp\gr\java_conf\masakado\gyunyu\Coffee.java src\jp\gr\java_conf\masakado\gyunyu\util\Utility.java
jar -cvf gyunyu.jar -C bin .
```

```text:呼び出し側のフォルダ構成（1）
sample/
　┣━　src/
　┃　　┗━　jp/gr/java_conf/masakado/sample/
　┃　　　　　┗━　Main.java
　┗━　lib/
　　　　┗━　gyunyu.jar
```

```java:Main.java
import jp.gr.java_conf.masakado.gyunyu.Coffee;
import jp.gr.java_conf.masakado.gyunyu.util.Utility;
public class Main {
	public static void main(String[] args) {
		(new Main()).execute();
	}

	public void execute() {
		Coffee coffee = new Coffee();
		coffee.print();
		Utility.output("想定していない呼び出し：いちご"); //外部から実行される事を想定していないメソッドを参照
	}
}
```

外部から実行される事を想定していない`gyunyu.jar`の`Utility.output(...)`を参照しています。
これをコンパイルして実行すると

```
javac -d bin -cp lib\gyunyu.jar -encoding UTF-8  src\jp\gr\java_conf\masakado\sample\Main.java
java -cp lib\gyunyu.jar;bin jp.gr.java_conf.masakado.sample.Main
```

下記のように表示されます。

![sample01.jpg](https://qiita-image-store.s3.amazonaws.com/0/206289/66d77326-fcae-3f58-542a-b88108f9f33a.jpeg)

### モジュール機能を使った場合
呼び出される側（jar）に`module-info.java`を作成します。

```text:呼び出される側（jar）のフォルダ構成（2）
gyunyu/
　┗━　src/
　　　　┣━　jp/gr/java_conf/masakado/gyunyu/
　　　　┃　　┣━　Coffee.java
　　　　┃　　┗━　util/
　　　　┃　　　　　┗━　Utility.java
　　　　┗━　module-info.java
```

```java:module-info.java
module jp.gr.java_conf.masakado.gyunyu {
	exports jp.gr.java_conf.masakado.gyunyu;
}
```

`exports`　：　外部に公開するパッケージを指定する。


モジュール名がパッケージ名と同じになっていますが、パッケージ名に合わせる必要は無く自由に名前を付ける事ができます。
これをコンパイルしてjarファイルを作成。

```
javac -d bin -encoding UTF-8 src\module-info.java src\jp\gr\java_conf\masakado\gyunyu\Coffee.java src\jp\gr\java_conf\masakado\gyunyu\util\Utility.java
jar -cvf gyunyu.jar -C bin .
```

作成した`gyunyu.jar`をsample/libに配置して`module-info.java`を作成します。

```text:呼び出し側のフォルダ構成（1）
sample/
　┣━　src/
　┃　　┣━　jp/gr/java_conf/masakado/sample/
　┃　　┃　　┗━　Main.java
　┃　　┗━　module-info.java
　┗━　lib/
　　　　┗━　gyunyu.jar
```

```java:module-info.java
module jp.gr.java_conf.masakado.sample {
	requires jp.gr.java_conf.masakado.gyunyu;
}
```

`requires`　：　依存する（使用する）モジュールを指定する。

`-p`オプションで`gyunyu.jar`を指定してコンパイル。

```
javac -d bin -p lib\gyunyu.jar -encoding UTF-8 src\module-info.java src\jp\gr\java_conf\masakado\sample\Main.java
```

下記のようなエラーメッセージが出力され、コンパイルに失敗します。

```
パッケージjp.gr.java_conf.masakado.gyunyu.utilは表示不可です
(パッケージjp.gr.java_conf.masakado.gyunyu.utilはモジュールjp.gr.java_conf.masakado.gyunyuで宣言されていますが、エクスポートされていません)
```

`Main.java`に記載している`Utility.output(...)`を削除するとコンパイルが通るようになります。

### モジュールの情報を表示する

下記のように`-d`オプションを指定してjarコマンドを実行すると、モジュールの情報を参照することができます。

```
jar -d -f lib\gyunyu.jar
```

```
exports jp.gr.java_conf.masakado.gyunyu
requires java.base mandated
contains jp.gr.java_conf.masakado.gyunyu.util
```

`exports`　：　公開されているパッケージ
`requires`　：　依存しているモジュール
`contains`　：　exportsに記載されていないけどjarに含まれているパッケージ

# 最後に
モジュール機能導入により依存関係が分かりやすくなったため、コンパイル上手くいったから実行してみたらJARが足りずにエラーになった・・・
みたいな事が発生する可能性が減ってくるのかなと感じました。
まだモジュール対応しているJARを扱ったことが無いので、私がモジュール機能の恩恵に与れるのは未だ先の話なのかもしれない。