OCJPをSE7からSE11にアップグレードしたときの勉強記録

## この記事について
2016.10に取得した「Oracle Certified Java Programmer, Gold SE 7」をそろそろアップデートしようかなと思い、2022.02に「Upgrade OCJP Java 6, 7 & 8 to Java SE 11 Developer」を受験した時の勉強内容を記録。

## この資格について

Oracleの認定資格のうち、Javaに関する資格「Oracle Certified Java Programmer」は

 - Gold(Professional)
 - Silver(Associate)
 - Bronze

の3段階に分かれている。
海外ではBronzeは存在せず「Silver」「Gold」はそれぞれ「Associate」「Professional」と呼ばれている、そのためBronzeは国際資格ではない。
![javase11_ja.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/6ef3f7c8-8a78-7e6c-d1e7-0dd9d4da94d5.png)

BronzeとSilverは前提条件なし、Goldは2つ前までのバージョンのSilver保持、または3つ前までのバージョンのGoldの保持が前提条件。
![cart_path.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/43587f07-605e-615f-828c-14233965c8fb.png)
参考：[Oracle Java SE 認定資格パス](https://education.oracle.com/ja/oracle-certification-path/product_267)

180分80問で合格ラインはアップグレードの方が少し低く61%、合格率は非公開

![スクリーンショット 2022-02-26 21.09.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/b7d90167-d12d-fca5-05b1-7da8e0808df9.png)

参考：[認定試験一覧 | オラクル認定資格制度 | Oracle University](https://www.oracle.com/jp/education/certification/examlist-172597-ja.html)

アップグレードじゃない方の試験(Java SE 11 Programmer II (1Z0-816-JPN))の方は試験範囲等の詳細が公開されている。
https://www.oracle.com/jp/education/certification/1z0-816-jpn-31705-ja.html

が、アップグレードの方はなぜか404…(下記ページの「試験詳細」のリンク先)
おそらくアップグレードじゃない方と範囲は同じ…はず？
https://education.oracle.com/ja/upgrade-ocp-java-6-7-8-to-java-se-11-developer/pexam_1Z0-817

## バージョンアップについて

バージョンはSE8までは1ずつ上がっていたが、Java9以降、Java自体のバージョンアップが6ヶ月おきというハイペースになったため、認定資格は8の次が11、その次は17の予定らしい。

↓SE9以降Javaのリリースモデルが変わった。
![java_release.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/252656df-da79-bd7f-b51b-5622a40af66d.gif)

現在はGold SE17が「Comming soon」になっている。※2022.02現在
![スクリーンショット 2022-02-13 21.13.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/81ab5d9b-992c-d0fd-d2c3-303831684abe.png)

SE8 Goldの認定試験がリリースされたのが2015秋頃、SE11は2019夏頃ということを考えるとだいたい3〜4年周期で認定資格も新しいバージョンがリリースされるようだ。
![スクリーンショット 2022-02-13 21.18.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/01aa66dc-669c-0507-4aeb-ac384087ed2c.png)

認定パスにもあったように3つ前のバージョンからはバージョンアップが可能なため、取得から10年以上寝かせてもバージョンアップは可能だが、能力の証明としては2つ以上前になるとイメージが悪い、、、
もうすぐSE17もリリースされるようだが、対策本の発売はリリースから半年ほどかかる上、リリース直後は合格ラインが少し辛めになっているため、SE17を待たずにSE11へのアップグレードを行うことにした。

## 勉強開始前の状況
「Oracle Certified Java Programmer, Gold SE 7」取得から5年半程度経っている。
Javaは仕事でたまに読み書きする。ただし、仕事で使っているバージョンはSE8。

## 勉強で使ったもの

**1. 問題集**  
Javaの黒本と呼ばれるやつ、少し探してみたがアップグレード試験対策の本は無さそうなのでGold試験対策の本をKindleで購入。
問題集と言いつつ、解答解説で試験範囲を丁寧に解説してくれている。
OCJP Gold SE7を取得したときもこのシリーズを使って図解など非常にわかりやすかったので、今回もこれをメインの教材に利用。 

[徹底攻略Java SE 11 Gold問題集[1Z0-816]対応](https://amzn.to/3svHwuo)

**2. IntelliJ IDEA CE**
すごく便利なIDE(無償)、いつも開発に使ってるやつ。
問題集で出てきたコードとか実際に書いて動かしてみるのに利用。

[ダウンロード IntelliJ IDEA](https://www.jetbrains.com/ja-jp/idea/download/#section=mac)

## 勉強時間

**約55時間**
「徹底攻略Java SE 11 Gold問題集」の解答/解説を読みながら、気になったところは公式のリファレンスも読みながら実際にコードを書いて動かしてみて、自分なりにノートとしてまとめるのを繰り返した。
最後の総仕上げ問題まで終わった時点で大体50時間ぐらい、あとはノートを見ながら理解の怪しいところをメインに復習して終わり。

## 結果

合格ライン **61%** に対し正解率 **69%**
**80問** 出題なので **55問** 正解？思ったよりわからない問題も多かった。

![2022-02-27 22.52.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/498263b8-daa8-d2d0-f9ec-f64c5882be43.png)

今回の反省点としては、主に下記の3点が大きかった。
・**クラス、インタフェース**の制約についての理解が浅かった。
・**型推論**(`var`)についてほぼ勉強していなかった。※これに関しては問題集でもほぼ触れていなかった、公式の出題範囲にも書かれていないのが不思議
・**モジュールシステム**(特にコマンド)についての理解が浅かった。

今回の出題割合だが、多かった順に
1. **ストリームAPIと関数型インタフェース**：やはりSE8以降の目玉アップデートなので一番出題が多かった。
2. **モジュールシステム**：SE9で追加された機能の目玉？これもそれなりに多かった。
3. **NIO2**：これはSE7の追加機能だが、ファイルIOはよく使うからかそこそこ出た。
4. **型推論(`var`)**：これもSE10で追加されたからかそこそこ出た。

あとは試験範囲に書かれている内容が全体的に少しずつ。

アップグレード試験は初めて受験したので、本当にアップグレードじゃない方(1Z0-816-JPN)と同じ内容が出るのか少し不安だったが、おそらく同じ内容で少し合格ラインがゆるいだけ？
また2、3個先のバージョン(SEのバージョンとしては12~18個先？)がでたらアップグレードしようかなと思います。

## 勉強ノート

### クラスとインタフェース
#### クラスのネスト

|  | 概要 | 特徴 |
|:-:|:-|:-|
| インナークラス | クラスの中に定義したクラス | エンクロージングクラスとインナークラス2つのインスタンス化が必要 |
| staticインナークラス | クラスの中に定義したstaticクラス | インスタンス化は不要、非staticなエンクロージングクラスの中にある場合、エンクロージングクラスのメンバを参照できない |
| ローカルクラス | メソッドの中に定義したクラス | そのクラスを定義したメソッドのローカル変数を扱う場合、先に定義する必要がある。このローカル変数は実質的finalになる。 |
| 匿名クラス | メソッドの中に定義した名前のないクラス | Interfaceの実装やクラスの継承を名前のないクラスとして宣言する。他のメソッドやクラスと共有しない一時的な実装を行いたい場合などに利用する。オーバーライドや独自メソッドの追加ができる。コンストラクタは定義できない。 |
| エンクロージングクラス | ネストしたクラスを囲むクラス |   |

- インナークラスは関連するクラスをまとめたり、カプセル化し、クラス外部から扱えなくするなどの目的で利用する。
- staticインナークラスから非staticなエンクロージングクラスのメンバにはアクセスできない
- 非staticなインナークラスにstaticメンバは定義できない

##### 匿名クラスの初期化子
匿名クラスにコンストラクタは存在しない、代わりに「初期化子」を利用する。
`{}`で処理を囲うとインスタンス生成時に実行される。

```java:Main.java
package com.example;
import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>() {
            {
                super.add("A");
                super.add("B");
            }
        };
    }
}
```

#### インタフェースの制限
インタフェースは通常のクラスと違い、定義できるものが限られる
インタフェースで定義できるもの

- 抽象メソッド
- 定数
- デフォルトメソッド(Java8から)：インタフェースに具体的な処理を持たせる具象メソッド、public前提
- staticメソッド(Java8から)
- privateメソッド(Java9から)：デフォルトメソッドから呼び出すためだけの処理を記述する具象メソッド

インタフェースのstaticメソッドはそれを継承したインタフェースや具象クラスには引き継がれない。

#### その他
- staticメソッドはオーバーライドできない、オーバーライド=インスタンスの動作であり、staticはインスタンスのメソッドではないから。
- 親クラスと実装元インタフェースに同名のメソッドがあった場合、親クラスが優先。
- 「リスコフの置換原則」：SがTの派生型であれば、プログラム内でT型のオブジェクトが使われている箇所は全てS型のオブジェクトで置換可能でなければならない。
- enumのコンストラクタはprivateでなければならない。※省略すると暗黙的にprivateになる。

### 関数型インタフェース

| パッケージ | インタフェース | 戻り値 | メソッド | 概要 |
|:-|:-|:-|:-|:-|
| java.util.function | `Supplier<T>` | T | get() | supplier=供給者、値を取得する |
| java.util.function | `Consumer<T>` | void | accept(T) | consumer=消費社、引数で受け取った値から副作用を起こす |
| java.util.function | `BiConsumer<T, U>` | void | accept(T, U) | 引数が2つ |
| java.util.function | `Predicate<T>` | boolean | `test(T)`<br>`and(Predicate<T>)`<br>`or(Predicate<T>)` | predicate=断定、判定結果を返す |
| java.util.function | `BiPredicate<T, U>` | boolean | `test(T, U)`<br>`and(Predicate<T, U>)`<br>`or(Predicate<T, U>)` | 引数が2つ |
| java.util.function | `Function<T, R>` | R | `apply(T)`<br>`andThen(Function<T, R>)`<br>`compose(Function<T, R>)` | 値を変換する、特定の値を受け取り、異なる型に変換して返す。compose()は逆順 |
| java.util.function | `BiFunction<T, U, R>` | R | `apply(T, R)`<br>`andThen(Function<T, U, R>)`<br>`compose(Function<T, U, R>)` | 引数が2つ |
| java.util.function | `UnaryOperator<T>` | T | apply(T) | operator=演算子、受け取った値から演算した結果を返す |
| java.util.function | `BinaryOperator<T>` | T | apply(T, T) | 引数が2つ |
| java.lang | `Runnable` | void | run() | 戻り値を返さない処理 |
| java.util.concurrent | `Callable<V>` | V | call() | 戻り値を返す処理 |
| java.util | `Comparator<T>` | int | compare(T, T) | 順序付けのため比較、第1引数のほうが小さい場合負数、同じ場合0、大きい場合正数を返す |

### 並列処理

#### 並行処理と並列処理

- 並行処理(concurrent)：処理を切り替えて同時に動いているように見せる。
- 並列処理(parallel)：複数のコアで同時に処理を行う。

#### マルチスレッド

- スタック領域：Javaのメソッドの呼び出し順制御に使われる。
- スレッド：メソッドがスタックに入ったり出たりするのを繰り返す一連の流れ。
- マルチスレッド：スタック領域が同時に複数用意され、スレッドを同時に複数発生させる。

#### スレッドの作成

マルチスレッドに関わるクラスとインタフェース

| パッケージ | クラスorインタフェース | メソッド | 概要 |
|:-|:-|:-|:-|
| java.lang | `Thread`(クラス) | run()<br>start() | マルチスレッドのためのスレッド定義、run()メソッドに処理を記述し、start()メソッドの呼び出しで実行 |
| java.lang | `Runnable`(インタフェース) | run() | Threadクラスのコンストラクタが受け取る関数型インタフェース |


サブスレッドを定義し、

```java:SubThread.java
public class SubThread extends Thread {
    @Override
    public void run() {
        System.out.println("sub");
    }
}
```

メインスレッドの中でサブスレッドを作成

```java:Main.java
public class Main {
    public static void main(String[] args) {
        Thread t = new SubThread();
        t.start();
        System.out.println("main");
    }
}
```

↓匿名クラスとラムダ式に置き換えることもできる。

```java:Main.java
public class Sample {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("sub");
        });
        t.start();
        System.out.println("main");
    }
}
```

#### スレッドプール

- スレッドプール：複数個の空のスレッドを最初から作っておき、タスクが与えられたときに取り出す仕組み。スレッドを使い回すことでスレッドの無駄遣いをなくす。

#### Executorフレームワーク

java.util.concurrent.Executor

| パッケージ | インタフェース | メソッド | 概要 |
|:-|:-|:-|:-|
| java.util.concurrent | `Executor` | `execute()` | `ExecutorService`と`ScheduledExecutorService`の親インタフェース |
| java.util.concurrent | `ExecutorService` | `submit()` | `submit()`で渡された処理をスレッドプールで実行する。 |
| java.util.concurrent | `ScheduledExecutorService` | `schedule()`<br>`scheduleAtFixesRate()`<br>`scheduleWithFixedDelay()` | 一定時間待機したり、一定時間の周期で渡された処理をスレッドプールで実行する。 |
| java.util.concurrent | `Executors` | `newSingleThreadExecutor()`<br>`newFixedThreadPool()` | `ExecutorService`と`ScheduledExecutorService`の実装を返すファクトリメソッドを持つ |

`Executors`の持つファクトリメソッド

| メソッド | 引数 | 概要 |
|:-|:-|:-|
| `newSingleThreadExecutor()` | なし | スレッドを1つプールする`ExecutorService`を作る |
| `newFixedThreadPool()` | int | 引数で指定された数のスレッドをプールする`ExecutorService`を作る |
| `newCachedThreadPool()` | なし | 必要に応じてスレッドを増減させる`ExecutorService`を作る。一度増えたスレッドは60秒間使用されなければ破棄、それ以内であれば再利用される |
| `newSingleThreadScheduledExecutor()` | なし | スレッドを1つプールする`ScheduledExecutorService`を作る |
| `newScheduledThreadPool()` | int | 引数で指定された数のスレッドをプールする`ScheduledExecutorService`を作る |

`ScheduledExecutorService`のメソッド

| メソッド | 引数 | 概要 |
|:-|:-|:-|
| `schedule()` | Runnable, Long, TimeUnit | 処理を一度だけ遅延実行する。TimeUnit単位でLong時間待機後、Runnableを実行 |
| `scheduleAtFixesRate()` | Runnable, Long, Long, TimeUnit | 一定のインターバルで繰り返し実行する。TimeUnit単位でLong時間待機後、Long時間周期でRunnableを実行 |
| `scheduleWithFixedDelay()` | Runnable, Long, Long, TimeUnit | 一定のインターバルで繰り返し実行する、各処理の終了後からインターバルが開始されるので処理時間に関係なく一定のインターバルにできる。TimeUnit単位でLong時間待機後、Runnableを実行 |

#### Future

`ExecutorService`や`ScheduledExecutorService`にタスクを登録するメソッドは`Future`を返す。
並列処理の各結果を受け取りたい場合、`Future`の`List`などで受け取る。
その場合、`Runnable`だと戻り値を返せないので`Callable`を`ExecutorService`の`submit()`などに渡して登録する。

```java:Main.java
public class Sample {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newSingleThreadExecutor();
        // Callableから受け取りたい戻り値の方をFutureのジェネリクスに指定する
        List<Future<Boolean>> futures = new ArrayList<>();

        for (int i = 0; i < 10; i++){
            futures.add(exec.submit(() -> {
                // 戻り値を返しているのでCallable
                return i % 2 == 0;
            }));
        }

        for (Future<Boolean> future : futures) {
            System.out.println(future.get());
        }
    }
}
```

サブスレッドで例外が発生した場合は`Future.get()`メソッドの実行時に検査例外である`java.util.concurrent.ExecutionException`がスローされる。実際に発生した例外を取り出したいときは、`ExecutionException`の`getCause()`メソッドを利用する。

#### 同期化処理

`java.util.concurrent.CyclicBarrier`クラスを利用すると複数のスレッドが特定のポイントまで到達するのを待機させることができる。

- バリアー：複数スレッドの待ち合わせポイント
- バリアーアクション：待ち合わせ後に実行される処理

バリアーの利用例

```java:Main.java
package com.example;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        CyclicBarrier barrier = new CyclicBarrier(5, () -> {
            System.out.println("end");
        });

        for (int i = 0; i < 5; i++) {
            exec.submit(() -> {
                Long id = Thread.currentThread().getId();
                System.out.println(id);
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
}
```

#### 排他制御

`synchronized`キーワードを利用することであるスレッドが処理している間、他のスレッドで同じ処理をさせない「排他制御」ができる。

- `synchronized`メソッド：メソッドの修飾子に`synchronized`を指定
- `synchronized`ブロック：メソッドの中でインスタンスを指定

```java
void someMethod () {
    synchronized (this) {
       doSomething();
    }
}
```

`java.util.concurrent.atomic`パッケージのクラスでも、排他制御ができる。`addAndGet()`や`getAndSet()`などのメソッドを持つ。

| クラス | 概要 |
|:-|:-|
| `AtomicBoolean` | アトミック変数としてboolean型を扱うためのクラス |
| `AtomicInteger` | アトミック変数としてint型を扱うためのクラス |
| `AtomicLong` | アトミック変数としてlong型を扱うためのクラス |
| `AtomicReference` | アトミック変数として参照を扱うためのクラス |

`java.util.concurrent.CopyOnWriteArrayList`クラスはスレッドセーフに処理を行うための`List`クラス。
読み出しの際にコピーを作るため、マルチスレッドで競合しない。

`java.util.concurrent.lock.ReentrantLock`クラスの`lock()`メソッドはそのメソッドを呼び出したスレッドが`unlock()`メソッドを呼び出すまで別のスレッドによる`lock()`メソッドの呼び出しを待機させる。
これにより複数のメソッドにまたがるような処理でも排他制御できる。

#### キャッシュの抑止

マルチスレッドで扱うクラスのフィールドに`volatile`修飾子を付けるとキャッシュされなくなる
これにより並列処理時にどちらかがキャッシュを読み込むことによる不整合をなくせる

### Optional

`Optional`のファクトリメソッド

| メソッド | 概要 |
|:-|:-|
| `static <T> Optional<T> empty()` | 空のOptionalインスタンスを生成 |
| `static <T> Optional<T> of(T value)` | 引数の値からOptionalインスタンスを生成 |
| `static <T> Optional<T> ofNullable(T value)` | 引数の値からOptionalインスタンスを生成、引数の値がnullの場合は空のOptionalインスタンスを生成 |

`Optional`の持つメソッド

| メソッド | 概要 |
|:-|:-|
| `get()` | 空でない場合取得、空の場合`java.util.NoSuchElementException`をスロー |
| `isPresent()` | 空でない場合trueを返す |
| `isEmpty()` | 空の場合trueを返す(Java11で追加) |
| `orElse(V)` | 空でない場合取得、空の場合引数で渡した値を返す |
| `orElseGet(Supplier<T>)` | 空でない場合値を取得、空の場合引数で渡した`Supplier`処理の結果を返す |
| `ifPresent(Consumer<T>)` | 空でない場合、引数で渡した`Consumer`の処理を実行 |
| `ifPresentOrElse(Consumer<T>, Runnable)` | 空でない場合、引数で渡した`Consumer`の処理を実行、空の場合`Runnable`を実行 |
| `map(Function<T>)` | 値に`Function`の処理を実行してOptionalで返す、空の場合新たな空のOptionalインスタンスを生成して返す |
| `flatMap(Function<T>)` | 値に`Function`の処理を実行して返す(Optionalに入れない)、この`Function`はOptionalを返す必要がある。空の場合新たな空のOptionalインスタンスを生成して返す |

### ストリームAPI

- 0個以上の中間操作と1個の終端操作を組み合わせたものが「ストリーム・パイプライン」  
「生成→中間操作...中間操作→終端操作」の流れ
- 実際に処理が実行されるのは終端操作を実行した時
- ストリームAPIはfor文などの繰り返し処理の置き換えではない、コレクションの全要素への処理やグルーピング、統計、抽出などを行いやすくするためのもの。

中間操作(抽出、変換、ソート等)

| メソッド | 概要 |
|:-|:-|
| distinct | 重複を除いたストリームを返す |
| filter | 引数で指定した条件でフィルタリングしたストリームを返す |
| limit | 引数で指定した数に切り詰めたストリームを返す |
| map | 引数で指定した関数を適用した結果のストリームを返す |
| peek | 新しい結果ストリームを生成し、引数で指定した関数を適用して返す |
| skip | 引数で指定した最初のn個を破棄し、残った要素のストリームを返す |
| sorted | 自然順序に従ってソートしたストリームを返す |

終端操作(取得、コレクション変換、統計等)

| メソッド | 概要 |
|:-|:-|
| allMatch | すべて一致すればtrue |
| anyMatch | いずれか一致すればtrue |
| collect | コレクションに変換 |
| count | 要素数を返す |
| findAny | 任意の要素を返す |
| findFirst | 先頭の要素を返す |
| forEach | 繰り返し処理を実行 |
| max | 最大を返す |
| min | 最小を返す |
| noneMatch | 一致するものがなければtrue |
| reduce | 要素を累積的に結合していくリダクション処理を実行する |
| toArray | 配列に変換 |

- コレクションの並列ストリーム取得は`list.parallelStream()`戻り値はStream型
- `IntStream`などプリミティブ型のストリームもある、Streamとはスーパークラスは同じだが互換性はない

#### リダクション操作

- ストリーム内のすべての要素を結合的累積関数により1つにまとめ、その結果を返す操作を「リダクション操作」という。
- ストリームの終端操作`reduce()`や`collect()`がこれにあたる。
- リダクション関数が引数に取るのは`BinaryOperator<T>`で、この時渡す結合的累積関数を「アキュムレータ関数」という。

| 戻り値 | メソッド | 引数 | 概要 |
|:-|:-|:-|:-|
| `Optional<T>` | reduce | `BinaryOperator<T>` | 1つめと2つめの要素に`BinaryOperator`の処理を実行して返す、返された結果と次の要素に`BinaryOperator`の処理を実行して返す、を要素がなくなるまで繰り返す |
| `T` | reduce | `T, BinaryOperator<T>` | 初期値ありの`reduce()`、戻り値が`Optional`じゃない |

```java
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer result = list.stream()
        .reduce(0, (a, b) -> a + b);
```

↑は↓の処理に相当する(実際はストリームなので順次実行ではない)

```java:reduceの例
Integer result = 0;
for (Integer i : nums) {
    result += i;
}
return result;
```

#### ストリームとラムダ式の特性

ラムダ式はラムダ式内部から外部のオブジェクトを変更(副作用を与えること)をしてはいけない。
ラムダ式内部から外部の変数を参照すると参照先の変数は実質的にfinalとして扱われる。
このため、変数の参照そのものを変更しようとするとコンパイルエラーになる。
だが、参照先オブジェクトの持つ値の変更の場合、コンパイラにチェックされないためエラーにならず、副作用を与えることができてしまう。

#### Collectorインタフェース

ストリームの終端操作として`.collect(Collectors.toList())`などはよく使うが、これは`java.util.stream.Collector`インタフェースの実装の一つで、同様に`java.util.stream.Collector`インタフェースを実装すれば、独自の終端操作もできる。この実装を匿名クラスでなく具象クラスとして定義しておけば使い回すこともできる。

#### groupingBy

終端操作の`.groupingBy()`を使うと、グループ化した`Map`の生成ができる。

例1) 奇数と偶数でグルーピング

```java
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
Map<String, List<Integer>> numsByGroup = nums.stream()
        .collect(Collectors.groupingBy(x -> x % 2 == 0 ? "EVEN" : "ODD"));
```

例2) グループ每に合計

```java
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
Map<String, Integer> sumByGroup = nums.stream()
        .collect(Collectors.groupingBy(
                x -> x % 2 == 0 ? "EVEN" : "ODD",
                Collectors.summingInt(x -> x)
        ));
```

例3) グループ毎の要素数をカウント

```java
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
Map<String, Long> countByGroup = nums.stream()
        .collect(Collectors.groupingBy(
                x -> x % 2 == 0 ? "EVEN" : "ODD",
                Collectors.counting()
        ));
```

キーが`Boolean`でいい場合`.partitioningBy()`でもいい

```java
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
Map<String, Integer> countByGroup = nums.stream()
        .collect(Collectors.partitioningBy(x -> x % 2 == 0));
```

#### 処理の順序

`.peek()`を使うとストリームの途中で値の状態を確認することができる。

```java
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
nums.stream()
        .peek(x -> System.out.println("1つめのpeek: " + x))
        .map(x -> x * 2)
        .peek(x -> System.out.println("2つめのpeek: " + x))
        .forEach(System.out::println);
```

```bash:実行結果
1つめのpeek: 1
2つめのpeek: 2
2
1つめのpeek: 2
2つめのpeek: 4
4
1つめのpeek: 3
2つめのpeek: 6
6
1つめのpeek: 4
2つめのpeek: 8
8
1つめのpeek: 5
2つめのpeek: 10
10
```

要素が1つずつ順にストリーム・パイプラインを通っていることがわかる。
ただし`.sorted()`などの要素全体に関わる中間処理が入る場合、その前後で区切られる。

```java
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
nums.stream()
        .peek(x -> System.out.println("1つめのpeek: " + x))
        .map(x -> x * 2)
        .peek(x -> System.out.println("2つめのpeek: " + x))
        .sorted(Integer::compareTo)
        .peek(x -> System.out.println("3つめのpeek: " + x))
        .forEach(System.out::println);
```

```bash:実行結果
1つめのpeek: 1
2つめのpeek: 2
1つめのpeek: 2
2つめのpeek: 4
1つめのpeek: 3
2つめのpeek: 6
1つめのpeek: 4
2つめのpeek: 8
1つめのpeek: 5
2つめのpeek: 10
3つめのpeek: 2
2
3つめのpeek: 4
4
3つめのpeek: 6
6
3つめのpeek: 8
8
3つめのpeek: 10
10
```

### 入出力

#### File

- `java.io.File`クラスはディレクトリやファイルへのパスを表す
- `FileFilter`インタフェースは`listFiles()`などの絞り込みに利用する。`File`を受け取り`boolean`を返す

| メソッド | 戻り値 | 引数 | 概要 |
|:-|:-|:-|:-|
| `exists()` | `boolean` | なし | 存在すればtrue |
| `mkdirs()` | `boolean` | なし | ディレクトリを作成、親ディレクトリもなければ作成 |
| `createNewFile()` | `boolean` | なし | ファイルを作成 |
| `getAbsolutePath()` | `String` | なし | 絶対パスを取得 |
| `list()` | `Strinng[]` | なし | ファイル・ディレクトリの一覧を`String`で取得 |
| `listFiles()` | `File[]` | なし | ファイル・ディレクトリの一覧を取得 |
| `listFiles()` | `File[]` | `FileFilter` | ファイル・ディレクトリの一覧を取得、引数渡したラムダの条件でフィルタリング |
| `isDirectory()` | `boolean` | なし | ディレクトリならtrue |

`File`と`FileFilter`を使ったファイル一覧の出力

```java:Main.java
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        File dir = new File(".");
        // ディレクトリまたは拡張子「.java」
        FileFilter filter = (path) -> path.isDirectory() || path.getName().endsWith(".java");
        Stream.ofNullable(dir.listFiles(filter))
                .forEach(System.out::println);
    }
}
```

#### 入出力ストリーム

- `java.io`クラスの持つ「ストリーム」はデータの入出力を扱う(「ストリームAPI」とは関係ない)
- `BufferedInputStream`や`BufferedReader`は読み込んだデータをバッファに溜め込むことでIOを減らす。それ単体で入力の機能はなく、`FileReader`などと合わせて利用する。
- `FileReader`は1文字ずつ読み込み、終端で-1を返す。`BufferedReader`は1行ずつ読み込み、終端で`null`を返す。

ストリームの基底クラス

| | 文字ストリーム | バイトストリーム |
|:-|:-|:-|
| 入力 | `java.io.Reader` | `java.io.InputStream` |
| 出力 | `java.io.Writer` | `java.io.OutputStream` |

`FileReader`と`BufferedReader`を使ったテキストファイルの読み込み

```java:Main.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("sample.txt");
        BufferedReader reader = new BufferedReader(fr);
        try (reader) {
            reader.lines().forEach(System.out::println);
        }
    }
}
```

- `FileWriter`クラスのコンストラクタは`File`オブジェクトまたはファイルパスの`String`を引数に取る、デフォルトは上書き
- 上書きでなく追記したい場合、第2引数`boolean append`に`true`を渡すと追記モード

`FileWriter`と`BufferedWriter`を利用したテキストファイルの書き込み

```java:Main.java
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        FileWriter out = new FileWriter("output.txt", true);
        BufferedWriter writer = new BufferedWriter(out);
        try (writer) {
            writer.newLine();
            writer.write("Hello!");
            writer.flush();
        }
    }
}
```

- `java.io.Console`はコンソール入出力用のクラス

`java.io.Console`の入力用メソッド

| メソッド | 戻り値 | 引数 | 概要 |
|:-|:-|:-|:-|
| `readLine()` | `String` | なし | 改行までの入力を受け取る |
| `readPassword()` | `char[]` | なし | 改行までの入力を受け取る、入力の際コンソールには表示されない。受け取った値を`println()`で出力はできる |

- `java.util.Scanner`クラスは文字入力ストリームを簡単に扱えるようにしたクラス

#### シリアライズ

- メモリ上にあるインスタンスをストリームとして出力することを「シリアライズ」、ファイルに書き出された情報を元にインスタンスを作り直すことを「デシリアライズ」という。
- シリアライズはデシリアライズ(復元)したときに正しく動作できることを保証しなくてはいけない。
- インスタンスが持っている参照先も含めて複数のインスタンスを1つにまとめるので「シリアライズ(直列化)」
- `java.io.Serializable`はマーカーインタフェース  
※マーカーインタフェース=抽象メソッドを持たず、クラスに何らかの意味を追加するためのインスタンス
- `java.io.ObjectOutputStream`はインスタンスをシリアライズしてファイルに出力するためのクラス
- `transient`や`static`で就職されたフィールドはシリアライズに含まれない
- `serialPersistentFields`フィールドでシリアライズ対象のフィールドを指定することもできる

#### NIO.2

- `java.io.File`クラスはJava1.0からあり、いくつかの課題があった
- 「NIO.2 (JSR 203:More New I/O APIs for the Java Platform」はその課題を解決すべく新しく作られたファイルとパスを扱うためJava7で追加された標準API
- パスとクラスの操作を`java.nio.file.Path`と`java.nio.file.Files` `java.nio.file.File`クラスに分離した。

```java
// parent/child/file.txt
Path path = Paths.get("parent", "child", "file.txt");
File file = path.toFile();
```

```java
File file = new File("file.txt");
Path path = file.toPath();
```

- `java.nio.file.Files`はファイルの読み書きに便利は`static`メソッドを複数もっている。
- `Files.newBufferedReader()`や`Files.newBufferedWriter`は`Path`を引数に渡すことで`BufferedReader`、`BufferedWriter`の生成を簡潔に書ける。

```java:Main.java
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("parent", "child", "file.txt");
        BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.APPEND);
        try (bw) {
            bw.write("Hello!");
            bw.newLine();
        }
    }
}
```

`Files.newBufferedWriter`はオプションとして第2引数に列挙型`java.nio.file.StandardOpenOption`を渡すことができる

| 定数 | 概要 |
|:-|:-|
| `APPEND` | 追記モード |
| `CREATE` | ファイルが存在しない場合新しいファイルを作成 |
| `CREATE_NEW` | 新しいファイルを作成、ファイルが既に存在している場合失敗 |
| `DELETE_ON_CLOSE` | 閉じる時に削除 |
| `READ` | 読み込みアクセス用に開く |


ディレクトリ操作用のストリームAPI`java.nio.file.DirectoryStream`もある

```java:Main.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("parent", "child", "file.txt");
        Files.newDirectoryStream(path)
                .forEach(p -> System.out.println(p.getFileName()));
    }
}
```

#### Path.normalize

`Path`クラスの`nonrmalize()`メソッドは`../`などで表現される冗長なパスを正規化してくれる

`a/b/c/../../c`
↓
`a/c`


#### walkFileTree

- `Files.walkFileTree`はディレクトリを捜査して、詳細な処理をするためのメソッド
- 第2引数に`java.nio.file.FileVisitor`インタフェースの実装クラスを受け取る
- この実装クラスでは4つの抽象メソッドの戻り値として、どのタイミングでどんな振る舞いをさせるかを定義する

`FileVisitor`の抽象メソッド

| 抽象メソッド | タイミング |
|:-|:-|
| `preVisitDirectory` | ディレクトリに入る時 |
| `postVisitDirectory` | ディレクトリから出る時 |
| `visitFile` | ファイルに遭遇した時 |
| `visitFileFailed` | ファイルの処理に失敗した時 |

抽象メソッドの戻り値に指定する定数(`java.nio.file.FileVisitResult`が持つ)

| 定数 | 振る舞い |
|:-|:-|
| `CONTINUE` | 探索を続ける |
| `TERMINATE` | 探索を終了する |

### JDBC(Java DataBase Connectivity)

- JDBCは`java.sql`や`javax.sql`パッケージで提供される。
- 各ベンダーのDBMS製品と連携するための共通のクラスなどが含まれる。

接続文字列

```
jdbc:mysql://localhost:3306/schema;
```

JDBCの構成要素

| 要素 | 概要 |
|:-|:-|
| ドライバ | ベンダが提供する実装クラス、`mysql-connector`など |
| ドライバマネージャ | ドライバを扱うクラス`java.sql.DriverManager`<br>`.getConnection()`に接続文字列を受け取りコネクションを返す |
| コネクション | DBMSとの接続を管理するインタフェース`java.sql.Connection` |

- `Statement`はSQL文を扱うインタフェース
- `PreparedStatement`はパラメータを受け取る、`Statement`はパラメータを受け取らない
- `PreparedStatement`はSQL文を予めコンパイルしておくが、`Statement`はSQL文を文字列のまま扱う
- `PreparedStatement`でステークホルダーを置き換える`.setXXX()`メソッドの第一引数は1オリジン

`PreparedStatement`のメソッド

| メソッド | 概要 |
|:-|:-|
| `execute` | クエリを実行し、`ResultSet`が返ってきたかどうかを`boolean`で返す。<br>結果を取得するには続けて`getResultSet()`または`getUpdateCount()`メソッドを実行する必要がある。 |
| `executeQuery` | `SELECT`結果を返す。 |
| `executeUpdate` | `INSERT`, `UPDATE`, `DELETE`を行い、結果行数の`int`を返す。 |
| `executeBatch` | 複数のSQL文を一度に実行し、更新された数の配列を返す。 |

- `SELECT`の結果`ResultSet`は`.next()`でカーソルを移動し、`.getInt()`や`.getString()`で値を取得する
- カーソルの初期状態は1行目の手前なので、`.next()`の前に`.getXXX()`すると`java.sql.SQLException`が発生する
- `.getXXX()`は引数でカラムを指すインデックスかカラム名、インデックスは1オリジン

- `CallableStatement`はストアド・プロシージャを呼び出す
- `Connection`の`.prepareCall()`で取得する
- `.execute()`で実行する

### コレクション&ジェネリクス

- コレクション=集合、ジェネリクス=汎用
- ジェネリクスはそのクラスが扱うデータの型を実行時に決めさせることで汎用性をもたせる仕組み
- ダイヤモンド演算子`<>`を利用する
- ジェネリクスを利用したクラスを「総称型」という

フィールドとして`Integer`しか扱えないクラス

```java:Item.java
public class Item {
    private Integer value;
    public Item (Integer value) {
        super();
        this.value = value;
    }
    public Integer getValue() {
        return  value;
    }
}
```

↓ジェネリクスを利用することで汎用的な型を扱えるようにできる

```java:Item.java
public class Item<T> {
    private T value;
    public Item (T value) {
        super();
        this.value = value;
    }
    public T getValue() {
        return  value;
    }
}
```

- 総称型は型パラメータを渡さない事もできる、その場合`Object`型の型パラメータを渡した場合と同じ

```java
List<Integer> list = new ArrayList<Integer>();
```

↓型パラメータなしでも`Object`型のListとして動く

```java
List list = new ArrayList();
```

- 型パラメータを指定した場合も内部では`Object`型で扱い、ダウンキャストをおこなっている
- 変数への代入など型が自明になるタイミングでは型を省略する「型推論」が利用できる
  - 変数への代入
  - メソッドの戻り値
  - メソッド呼び出しの引数

```java
package com.example;

import java.util.ArrayList;
import java.util.List;

public class Item {
    public static void main(String[] args) {
        // 変数への代入時は変数宣言に記述しているので自明
        List<String> list = new ArrayList<>();
        // メソッドの引数はメソッドのシグネチャに記述しているので自明
        execute(new ArrayList<>());
    }
    private static List<String> test() {
        // メソッドの戻り値もメソッドのシグネチャに記述しているので自明
        return new ArrayList<>();
    }
    private static void execute(List<String> list) {
        list.forEach(System.out::println);
    }
}
```

#### 変性

参照型をどの型として扱えるようにするかという性質を「変性」という

- サブクラス型の代入を許す「共変性(covariance)」
- サブクラス型の代入を許さない「非変性(invariance)」
- さらにスーパークラス型の代入を許す「反変性(contravariance)」

通常のオブジェクトは「共変」、ジェネリクスは型安全のため「非変」、下記のような書き方はコンパイルエラー

```java
List<Object> list = new ArrayList<Integer>();
```

#### 制約付き型パラメータ

型パラメータに`extends`を宣言することで、特定のクラスが持っているメンバを扱えるようになる

```java
public class A {
    public void hello() {
        System.out.println("hello");
    }
}
```

```java
public class Test<T extends A> {
    public void execute(T t) {
        t.hello();
    }
}
```

↑のコードは`extends`をつけない場合`T`が`hello()`メソッドを持っている保証がないためコンパイルエラー

#### 型パラメータのワイルドカード

- 型パラメータを不定にしたい場合、ワイルドカード「`<?>`」を利用することもできる

```java:Main.java
import java.util.Collection;
import java.util.List;

public class Main6 {
    public static void main(String[] args) {
        List<Integer> a = List.of(1, 2, 3, 4, 5);
        List<String> b = List.of("A", "B", "C");
        printAll(a);
        printAll(b);
    }
    private static void printAll(Collection<?> collection) {
        collection.forEach(System.out::println);
    }
}
```

- ワイルドカードにも型の制約を付けられる

| 種類 | 書き方 | 特徴 |
|:-|:-|:-|
| 非境界ワイルドカード | `<?>` | メソッドの戻り値型はObject型になる<br>メソッドの引数にはnullリテラルしか渡せない |
| 上限境界ワイルドカード | `<? extends X>` | メソッドの引数にはnullリテラルしか渡せない |
| 下限境界ワイルドカード | `<? super X>` | メソッドの戻り値型はObject型になる |

ワイルドカードの制限を決める際の原則

- 戻り値を戻すことを目的とした「Producer」の場合：「`extends`(上限境界)」
- 引数を受け取って利用することを目的とした「Consumer」の場合」：「`super`(下限境界)」

これを「PECS(Producer-Extends and Consumer-Super)」という

#### Listインタフェース

Listは追加した順序を保持する
Listインタフェースの実装クラスとして主に3つ

| クラス | 特徴 |
|:-|:-|
| `ArrayList` | ・配列を利用している<br>・要素数が増えた際はより大きな配列に要素をコピーするので追加が遅い |
| `LinkedList` | ・要素をもたせたオブジェクトを数珠つなぎ(前後への参照を持つ)にしている<br>・ArrayListのようにコピーが不要のため要素の追加が速い<br>・リンクを順にたどるため読み込みのパフォーマンスは低い |
| `Vector` | ・マルチスレッド時に利用中は他スレッドからのアクセスにロックをかけるスレッドセーフなList<br>・パフォーマンスは低い |

#### Queue&Deque

キューとデックは`java.util.Queue`と`java.util.Deque`で実現できる

- キュー(queue)：FIFO
- デック(deque)：両端キュー(double ended queue)

#### Setインタフェース

Setは重複排除、順序保証なし
Setインタフェースの実装クラスとして主に２つ

| クラス | 特徴 |
|:-|:-|
| `HashSet` | 順序を保証しないので速い |
| `TreeSet` | 自然順序または引数の`Comparator`でソート |

#### Map.Entry

`Map`インタフェースはインナーインタフェース`Entry`を持つ
`Entry`は`Map`の１要素を扱うのに利用する

```java:Main.java
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("ONE", 1);
        map.put("TWO", 2);

        map.entrySet().stream().forEach((Map.Entry<String, Integer> entry) -> {
            System.out.println(entry.getKey() + entry.getValue());
        });
    }
}
```

Java8以降は`Map`が`forEach`を持つので↑このコードは↓のように置き換えられる
`Map.forEach()`は内部で`Entry`を取り出している

```java:Main.java
import java.util.HashMap;
import java.util.Map;

public class Main7 {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("ONE", 1);
        map.put("TWO", 2);

        map.forEach((k, v) -> System.out.println(k + v));
    }
}
```

#### Comparable&Comparator

- `java.lang.Comparable`インタフェース：`.compareTo()`メソッドを持つ=この実装クラスは比較可能
- `java.util.Comparator`インタフェース：比較処理`.compare()`メソッドを持つ関数型インタフェース=比較アルゴリズムを引数に取るためのもの

#### オートボクシング&アンボクシング

Java5から可能になったプリミティブ型とラッパークラスを自動変換する仕組み
もともとプリミティブ型はより大きな型への暗黙の型変換があるので、合わせて覚える

| プリミティブ型 | ラッパークラス | 暗黙の型変換が可能な型 | この型で扱われる書き方 |
|:-|:-|:-|:-|
| `boolean` | `Boolean` | なし | `true`,`false` |
| `char` | `Character` | `int`,`long`,`float`,`double` | '1','a' |
| `byte` | `Byte` | `short`,`int`,`long`,`float`,`double` | なし |
| `short` | `Short` | `int`,`long`,`float`,`double` | なし |
| `int` | `Integer` | `long`,`float`,`double` | `1`,`-1` |
| `long` | `Long` | `float`,`double` | `1L`,`-1L` |
| `float` | `Float` | `double` | `1.0F`,`-1.0F` |
| `double` | `Double` | なし | `1.0`,`-1.0` |

アンボクシング後の暗黙の型変換は働くが、更にオートボクシングは働かない

`Integer`
↓アンボクシング
`int`
↓暗黙の型変換
`double`
↓オートボクシング
✖
`Double`




### アノテーション

クラスやフィールド、メソッド、コンストラクタなどに意味を追加するマーカーの役割をする
アノテーションを付与されたクラスを利用するクラスに対して値を渡すこともできる

アノテーションの定義

```java:Test.java
public @interface Test {
    String name();
    int price();
}
```

- アノテーションで値を扱いたい場合抽象メソッドを定義する、この値を「注釈パラメータ」という
- 注釈パラメータはアノテーションの付与時に引数として渡す

```java
@Test(name = "cookie", price = 150)
public class Product {
    private final String name;
    private final int price;

    public Product(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }
}
```

値が1つの場合名前を省略できる

```java:Test.java
public @interface Test {
    int price();
}
```

```java
@Test(150)
public class Product {
    private final String name;
    private final int price;

    public Product(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }
}
```

アノテーション定義でデフォルト値を設定することもできる、デフォルト値なしで引数なしの場合コンパイルエラー

```java:Test.java
public @interface Test {
    String name() default "No name";
    int price() default 100;
}
```

#### JavaSEで事前に定義されているアノテーション

##### @Override

- `@Override`はスーパークラスのオーバーライド元メソッドの変更を検知し、コンパイルエラーにする

##### @Deprecated

- `@Deprecated`はJDKやライブラリのバージョンアップによって利用不可にしたい機能の移行期間に「非推奨」であることを示すために利用する
- このアノテーションがついているクラスやメソッド、フィールドを利用しているとコンパイラが警告を発する
- 注釈パラメータとして削除予定かどうかを指す`boolean`型の`forRemoval`を受け取る、デフォルトは`false`

##### @SuppressWarnings

- `@SuppressWarnings`はコンパイル時の警告を抑制する
- 注釈パラメータに`String`で`"unchecked"`, `"deprecation"`, `"removal"`のいずれかを受け取る

#### メタ・アノテーション

- インスタンスの元となるクラスの定義情報を取得するための「リフレクション」という機能がある
- `java.lang.reflect`パッケージではリフレクションのためのAPIが提供される
- `java.lang.Class`クラスは「クラスリテラル」(`クラス名.class`)でクラスの定義情報を取得できる
- この機能を使いアノテーションから値を取得し、利用する
- この時、アノテーションにもアノテーションを付ける必要がある、これを「メタ・アノテーション」という

```java:Main.java(Productをテストするクラス)
public class Main {
    public static void main(String[] args) {
        Class<Product> productClass = Product.class;
        Test test = productClass.getAnnotation(Test.class);

        Product product = new Product(test.name(), test.price());
        System.out.println(product.getName());
        System.out.println(product.getPrice());
    }
}
```

```java:Product.java(テスト対象クラス)
@Test(name = "cookie", price = 150)
public class Product {
    private final String name;
    private final int price;

    public Product(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }
}
```

```java:Test.java(アノテーション定義)
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

// アノテーション用のメタ・アノテーションRetention
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    String name() default "example";
    int price() default 100;
}
```

##### @Retention

- `Retention`アノテーションは注釈パラメータとして情報の保持期間を指定する`java.lang.annotation.RetentionPolicy`を受け取る

列挙型`RetentionPolicy`の列挙子

| 列挙子 | 概要 |
|:-|:-|
| `SOURCE` | アノテーションに関する情報をコンパイル時に破棄する |
| `CLASS` | アノテーションに関する情報を実行時に破棄する |
| `RUNTIME` | アノテーションに関する情報を実行時まで保持する |

通常の使い方では実行時に必要なので`RUNTIME`を指定する

##### @Target

- `@Target`アノテーションを利用するとアノテーションに対し、付与できる対象を指定することができる
- `@Target`アノテーションは付与できるタイミングを指定する`java.lang.annotation.ElementType`を注釈パラメータとして受け取る
- `@Target`なしの場合すべて対象になる
- 複数指定したい場合注釈パラメータを配列で渡す

列挙型`ElementType`の列挙子

| 列挙子 | 対象 |
|:-|:-|
| `ANNOTATION_TYPE` | アノテーション |
| `CONSTRUCTOR` | コンストラクタ |
| `FIELD` | フィールド |
| `LOCAL_VARIABLE` | ローカル変数 |
| `METHOD` | メソッド |
| `MODULE` | モジュール |
| `PACKAGE` | パッケージ |
| `PARAMETER` | メソッドの引数 |
| `TYPE` | クラス、インタフェース、Enum |
| `TYPE_PARAMETER` | 型パラメータ |
| `TYPE_USE` | 型の仕様 |

### 例外とアサーション

- プログラムが対処できるトラブルは「例外」=`Exception`、プログラムで対処できないトラブルは「エラー」=`Error`
- 独自例外では`Exception`を継承する

#### try-with-resource

- `AutoCloseable`インタフェースまたはサブインタフェース`Closeable`を実装したクラスはtry-with-resourceで自動的に`close`するリソースとして利用することができる
- 宣言はブロックの外でもいいが、実質的`final`でなければいけない(参照の書き換えをしてはいけない)
- `;`区切りで複数のリソースを指定できる
- 宣言の逆順で閉じる
- `catch`, `finally`をつけた場合、`close`→`catch`→`finally`の順で実行される

```java
BufferedReader br = Files.newBufferedReader(path);
BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.APPEND);
try (br; bw) {
    bw.write(br.read());
    bw.newLine();
}
```

- `close()`メソッド内で発生した例外は`catch`ブロックでキャッチされる
- ただし、`try`ブロック内で例外発生し、`close()`メソッド内でも例外発生した場合、`try`ブロック内の例外に隠され抑制される

```java:CloseableImpl(リソースクラス)
public class CloseableImpl implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("close");
        throw new Exception("Exception in close");
    }

    public void exec() throws Exception {
        System.out.println("exec");
        throw new Exception("Exception in exec");
    }
}
```

```java:Main.java(リソースを利用するクラス)
public class Main {
    public static void main(String[] args) {
        CloseableImpl c = new CloseableImpl();
        try (c) {
            c.exec();
        } catch (Exception e) {
            System.out.println("catch");
            System.out.println(e);
        } finally {
            System.out.println("finally");
        }
    }
}
```

↓`main()`の実行結果

```bash:コンソール出力
exec
close
catch
java.lang.Exception: Exception in exec
finally
```

抑制された例外の取得するにはキャッチした例外の`.getSuppressed()`メソッドを呼ぶ必要がある

```java:Main.java(catchブロックの処理を変更)
public class Main {
    public static void main(String[] args) {
        CloseableImpl c = new CloseableImpl();
        try (c) {
            c.exec();
        } catch (Exception e) {
            System.out.println("catch");
            System.out.println(e);
            // .getSuppressed()はThrowableの配列を返す
            for (Throwable t : e.getSuppressed()) {
                System.out.println(t);
            }
        } finally {
            System.out.println("finally");
        }
    }
}
```

↓実行結果

```bash:コンソール出力
exec
close
catch
java.lang.Exception: Exception in exec
java.lang.Exception: Exception in close
finally
```

### ローカライズ

`java.util.Locale`は地域や言語などの「ロケール情報」を扱うクラス
「ロケール情報」は「i18n(internationalization)」を実現するためにあり、地理的・政治的・文化的な特定の地域を表す

ロケールの基本的な使い方
https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Locale.html

デフォルトのロケール取得

```java:Main.java
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        Locale locale = Locale.getDefault();
        System.out.println(locale.getCountry());
        System.out.println(locale.getLanguage());
    }
}
```

いくつかのロケール生成方法

```java
// デフォルト
Locale locale = Locale.getDefault();
// 定数
locale = Locale.JAPAN;
// コンストラクタで生成する場合、第1引数が言語、第２引数が国、第３引数が派生情報
locale = new Locale("ja", "JP", "JP");
// ビルダー
locale = new Locale.Builder()
        .setLanguage("jp")
        .setRegion("JP")
        .build();
// FETF言語タグによるファクトリメソッド
locale = Locale.forLanguageTag("ja-JP-u-ca-japanese-x-lvariant-JP");
```

言語コードの例
https://ja.wikipedia.org/wiki/ISO_639-1%E3%82%B3%E3%83%BC%E3%83%89%E4%B8%80%E8%A6%A7

| 言語 | コード |
|:-|:-:|
| 日本語 | ja |
| 英語 | en |
| ドイツ語 | de |
| 中国語 | zh |
| フランス語 | fr |

国コードの例
https://ja.wikipedia.org/wiki/ISO_3166-1

| 国 | コード |
|:-|:-:|
| 日本 | JP |
| アメリカ | US |
| ドイツ | DE |
| 中国 | CN |
| フランス | FR |

文字列による文字コード、国コードの指定は安全でないので、定数で用意されているものは定数を利用
`Locale.JAPANESE`は日本語、`Locale.JAPAN`は日本語+日本

![2022-02-25 22.06.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/dd464411-db11-e6f7-0090-549e41aeff70.png)

#### プロパティファイル

`java.util.Properties`は実行環境ごとの設定値などを別ファイルとして書き出した際に設定情報を読み出して扱うためのクラス

```java:Main.jp
public class Main {
    public static void main(String[] args) throws IOException {
        // Propertiesのload()メソッドにリーダーを渡す
        Properties prop = new Properties();
        prop.load(new FileReader("default.properties"));

        // PropertiesはforEach()を持っている
        prop.forEach((k, v) -> System.out.println(k + ": " + v));

        // keySet()からはObjectのSetが返される
        Set<Object> keys = prop.keySet();
        for (Object key: keys) {
            // Objectをキーとして取得する際はget()
            System.out.println(key + ": " + prop.get(key));
        }

        // list()はPrintStreamを渡すことで簡単にPropertiesの情報を出力できる
        prop.list(System.out);

        // 文字列から取得する際はgetProperty()
        String logLevel = prop.getProperty("LOG_LEVEL");
        String language = prop.getProperty("LANGUAGE");
    }
}
```

```properties:default.properties
LOG_LEVEL=INFO
LANGUAGE=JP
```

`java.util.ResourceBundle`で読み込むこともできる

```java
// ファイル名は基底名(拡張子なし)で指定
ResourceBundle resource = ResourceBundle.getBundle("default");
System.out.println(resource.getString("LOG_LEVEL"));
System.out.println(resource.getString("LANGUAGE"));
```

`ResourceBundle`はファイル名に言語コードや国コードを含めるとロケールに合わせたプロパティファイルを自動で選択してくれる

```bash:ファイル構成例
.
└── src
    ├── com
    │   └── example
    │       └── Main.java
    ├── default_en_US.properties
    └── default_ja_JP.properties
```

#### 日付フォーマット

Java8から追加された`Date`APIは`java.time.format.DateTimeFormatter`で日付や時刻のフォーマットを指定できる。

```java:Main.java
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws IOException {
        Locale locale = Locale.JAPAN;
        LocalDateTime now = LocalDateTime.now();
        LocalDate today = LocalDate.now();
        System.out.println(
                now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(locale))
        );
        System.out.println(
                now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(locale))
        );
        System.out.println(
                today.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale))
        );
        System.out.println(
                today.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(locale))
        );
        System.out.println(
                today.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(locale))
        );
        System.out.println(
                today.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(locale))
        );
    }
}
```

```bash:実行結果
2022/02/27 1:20:46
2022/02/27 1:20
2022年2月27日日曜日
2022年2月27日
2022/02/27
2022/02/27
```

### モジュール・システム

Java9からパッケージを分類する仕組みとして「モジュール・システム」が導入された
モジュールではパッケージ単位のアクセス制御ができる

モジュール利用のメリット

- 公開されたクラスにしかアクセスできないためセキュリティが高まる
- モジュール間の依存関係を明確化できる
- プラットフォーム間の整合性が向上する
- 柔軟な実行環境を実現できる
- 最適化されたモジュール構成によってパフォーマンスが向上する

モジュールの設定は「module-info.java」に定義する、この設定ファイルによってパッケージ間の依存関係が明確になる

```java:module-info.java
// com.sample.Testモジュールでcom.sample.serviceパッケージのみ公開
module com.sample.Test {
    exports com.sample.service;
}
```

モジュール定義のブロック内にはディレクティブを記述する

| ディレクティブ | 概要 |
|:-|:-|
| `exports` | 公開するパッケージを指定 |
| `requires` | 利用する別のモジュールを指定 |
| `opens` | リフレクションを許可するパッケージを指定<br>「`to モジュール, モジュール`」を付けることで許可先のモジュールを制限できる<br>モジュールのシグネチャにも書ける |
| `uses` | SPIとして利用するインタフェースを指定、SPIの利用側モジュールに記述 |
| `provides` | SPIとなるインタフェースとその実装クラスを指定、SPIの実装側モジュールに記述 |

#### モジュールパス

- モジュール・システムを利用する際の必要なモジュールの配置先、`javac`コマンドや`java`コマンドのオプションとして`--module-path`で指定する
- コンパイラやJVMは指定された場所を検索しに行く
- Java8以前のクラスパスにあたる、Java9以降はモジュールパスの利用を推奨

#### モジュールの種類

| ディレクティブ | 概要 |
|:-|:-|
| 名前付きモジュール | モジュール定義ファイル(module-info.java)でモジュール名が定義されているモジュール |
| 自動モジュール | モジュール定義ファイルを持たないjarファイル |
| 無名モジュール | クラスパス上に配置されたjarファイル、名前付きモジュールから参照できない |

#### モジュール・システムへの移行

既存のアプリケーションをモジュール・システムへ移行する際は適切に依存関係を解決する必要がある

移行には2つの方式がある

| 移行方式 | 概要 |
|:-|:-:|
| ボトムアップ移行 | 依存されている側から順に名前付きモジュールに変換していく方法 |
| トップダウン移行 | 依存されている側のモジュールは一旦自動モジュールにし、依存する側から順に名前付きモジュールに変換していく方法 |

実際の移行は、下記のような流れになる

1. 対象パッケージ内のどのパッケージが利用されているか調る
2. 利用されているパッケージのみ公開するように`module-info.java`にモジュール宣言を追加する
3. jarファイルを再作成する

#### モジュール作成

```bash:ファイル構成
.
├── classes
├── modules
└── src
    ├── client
    │   ├── com
    │   │   └── sample
    │   │       └── client
    │   │           └── Main.java
    │   └── module-info.java
    └── lib
        ├── com
        │   └── sample
        │       └── lib
        │           └── Lib.java
        └── module-info.java
```

↑の構成から実際にモジュールを作成する場合

```bash
# 依存先モジュール「lib」をコンパイル
javac -d classes/lib/ src/lib/module-info.java src/lib/com/sample/lib/Lib.java
# jarファイル作成
jar cvf modules/lib.jar -C classes/lib .
# 依存元モジュール「client」をコンパイル
# 依存先モジュールのjarがある場所を--module-pathで指定
javac --module-path modules -d classes/client/ src/client/module-info.java src/client/com/sample/client/Main.java
# jarファイル作成
jar cvf modules/client.jar -C classes/client .
```

Mainを実行する

```bash
// モジュールから実行する際も--module-pathオプションで場所を指定
java --module-path modules --module Client/com.sample.client.Main
```

#### 依存関係逆転

- 「依存関係逆元の原則(DIP:Dependency Inversion Principle)」とは柔軟なシステムを実現するための設計原則
- アプリケーションのライブラリへの依存を解消するために、アプリケーションが利用する機能をインタフェースにまとめ、それに従ったライブラリを作成する
- このようにインタフェースだけ事前に定義し、それに沿ったライブラリを提供する仕組みを「SPI:Service Provider Interface」という

SPIの利用時の`module-info.java`は↓のように記述する

```java:module-info.java(SPI利用側)
module app {
    exports app;
    uses app.Hello;  // app.HelloインタフェースをSPIとして利用
}
```

```java:module-info.java(SPI実装側)
module lib {
    exports lib;
    requires app;
    provides app.Hello with lib.HelloImpl;  // app.HelloインタフェースをSPIとして実装
}
```

#### ServiceLoader

`java.util.ServiceLoader`クラスはSPIを利用する際にクラスファイルをロードするのに利用する
SPIのインタフェースを指定することでその実装クラスを検索する

```java:Main.java
import java.util.ServiceLoader;

public class Main {
    public static void main(String[] args) {
        // ProductというSPIを利用する場合
        for (Product p : ServiceLoader.load(Product.class)) {
            System.out.println(p.getPrice());
        }
    }
}
```


#### jdeps

`jdeps`コマンドはJDKに含まれており、クラスやモジュールの依存関係を調べるのに利用できる

```bash
jdeps jarファイルのパス
```

`jdeps`のオプション

```bash
$ jdeps -h
使用方法: jdeps <options> <classes...>
<classes>には、.classファイルのパス名、ディレクトリ、JARファイルまたは完全修飾
クラス名を指定できます。使用できるオプションは次のとおりです:
  -dotoutput <dir>                   DOTファイル出力の宛先ディレクトリ
  -s           -summary              依存性のサマリーのみ出力します
  -v           -verbose              クラス・レベルの依存性をすべて出力します
                                     -verbose:class -filter:noneと同等です。
  -verbose:package                   パッケージ・レベルの依存性を出力します
                                     (デフォルトでは、同じパッケージ内の依存性を除く)
  -verbose:class                     クラス・レベルの依存性を出力します
                                     (デフォルトでは、同じパッケージ内の依存性を除く)
  -cp <path>   -classpath <path>     クラス・ファイルを検索する場所を指定します
  -p <pkgname> -package <pkgname>    指定のパッケージ名に一致する依存性を検出します
                                     (複数回指定可能)
  -e <regex>   -regex <regex>        指定のパターンに一致する依存性を検出します
                                     (-pと-eは排他的)
  -f <regex>   -filter <regex>       指定のパターンに一致する依存性をフィルタします
                                     複数回指定された場合、最後のものが使用されます。
  -filter:package                    同じパッケージ内の依存性をフィルタします(デフォルト)
  -filter:archive                    同じアーカイブ内の依存性をフィルタします
  -filter:none                       -filter:packageおよび-filter:archiveのフィルタリングは行われません
                                     -filterオプションで指定したフィルタリングが引き続き適用されます。
  -include <regex>                   パターンに一致するクラスに分析を制限します
                                     このオプションを指定すると、分析対象クラスの
                                     リストがフィルタされます。パターンを依存性に
                                     適用する-pおよび-eと一緒に使用できます
  -P           -profile              プロファイル、またはパッケージを含むファイルを表示します
  -apionly                           分析をAPI、つまり、パブリック・クラスの
                                     パブリック・メンバーおよび保護されたメンバーの
                                     署名における依存性(フィールド・タイプ、メソッド・
                                     パラメータ・タイプ、戻されたタイプ、チェックされた
                                     例外タイプなど)に制限します
  -R           -recursive            すべての依存性を再帰的にトラバースします。
                                     -Rオプションは-filter:noneを意味します。-p、-e、-f
                                     オプションが指定されている場合、一致する依存性のみ
                                     分析されます。
  -jdkinternals                      JDK内部APIのクラスレベルの依存性を検出します。
                                     デフォルトでは、-includeオプションを指定しないと、
                                     -classpathのすべてのクラスと入力ファイルを分析します。
                                     このオプションは-p、-eおよび-sオプションと一緒に使用できません。
                                     警告: JDK内部APIは、次のリリースでアクセスできなくなる可能性が
                                     あります。
  -version                           バージョン情報
```

### セキュアコーディング

セキュアコーディングで重要なトップ10

1. 入力を検証する
1. コンパイラからの警告に注意を払う
1. セキュリティポリシーを実装するよう設計する
1. シンプルにする
1. 拒否をデフォルトにする
1. 最小権限の原則に従う
1. 他のシステムに送信するデータを無害化する
1. 多重防御を実践する
1. 効果的な品質保証テクニックを利用する
1. セキュアコーディング標準を採用する

#### 文字列の正規化

入力の検証のために受け取った文字列にはまず「Unicodeの正規化(normalization)」を行う
`java.text.Normalizer`クラスは文字列正規化のためのクラス

```java
String result = Normalizer.normalize(de, Normalizer.Form.NFKC);
```

#### 整数オーバーフロー対策

数値の演算により、表現可能な範囲を超えることでエラーを発生させる「整数オーバーフロー攻撃」という脅威がある
これにはいくつかの対策方法がある

| 対策方法 | 概要 |
|:-|:-|
| 事前条件テスト | 入力値が演算可能な範囲かどうかを演算の前にチェックする |
| アップキャスト | より大きな数値を扱える型(short→int→long等)に変換する |
| BigIntegerクラスを使う | BigIntegerは動的にメモリを確保するためオーバーフローしない、ただし通常の整数型よりパフォーマンスは落ちる |

#### システムに関する情報を見せない

機密情報はもちろんだが、そうでない情報でも
下記のような情報はデバッグ時や開発時は必要かもしれないが、ユーザにはできるだけ見えないようにし、速やかに削除させることで、OS・ミドルウェアやファイルシステム・アプリケーションの構成から攻撃の手がかりを見つけられることを避ける

- Javaのスタックトレース
- ミドルウェアが出力するOSやミドルウェアのバージョンなどの情報
- ファイルシステムの構成

#### Dos攻撃対策

JVMに負荷をかける方法として

- 大きなファイルやデータを読み込ませる
- ファイルオープンやDBMSへの接続を増やす

などがある、このため

- ファイルを開く処理は対象のファイルサイズをチェックする
- ファイルオープンやDBMSへの接続は例外発生時や一定直でクローズするようにする

などの対策が必要

#### SecurityManager

Java標準のセキュリティ機構として`java.lang.SecurityManager`がある
`SecurityManager`は下記の1文を追加することでJVMに登録され、有効になる

```java
System.setSecurityManager(new SecurityManager());
```

↑の代わりに`java`コマンドのオプションでも有効にできる

```bash
java -Djava.security.manager Main
```

セキュリティポリシーを変更するには`java.security.Policy`クラスと`java.security.Permissions`クラスを利用するか、`.policy`ファイルを作成し`java`コマンドのオプションで指定する

```java:readOnly.policy
// lib.jarのみに権限を付与
grant codeBase "file:/Users/xxx/workspace/project/lib.jar" {
    // "/"ディレクトリへの読み込みを許可
    permission java.io.FilePermission "/" "read";
}
```

```bash
java FileRead -cp .:lib.jar -Djava.security.manager -Djava.security.policy=readOnly.policy
```

ライブラリなどを呼び出す際に呼び出す側の権限に関わらず呼び出された側の権限で実行できるようにする仕組みとして「特権ブロック」がある

`java.security.AccessController`クラスの`doPrivileged`メソッドに`java.security.PrivilegedAction`インタフェースの実装クラスを渡す

#### 可変性

- 可変(Mutable)オブジェクト: フィールドの値が変わる事があるクラス
- 不変(Immutable)オブジェクト: フィールドの値が変わらないクラス

下記のような実装で不変オブジェクトを利用することでセキュリティ強度が高まる

- 継承できないようクラスを`final`にする
- パッケージ外からインスタンス化できないようコンストラクタは修飾子なしか`private`にする
- コンストラクタで受け取ったオブジェクトをそのまま代入しない
- ビルダーを用意する
- `setter`を提供しない
- `getter`はコピーした別の参照を返す

#### シリアライズ・プロキシ

デシリアライズ時はコンストラクタが利用されず、デシリアライズによる不正なインスタンスの生成が行われる可能性がある
デシリアライズによるバグやセキュリティ上の問題を防ぐための手法として「シリアライズ・プロキシ」パターンがある


1. シリアライズ対象のクラスに`static`インナークラスを追加する
1. エンクロージングクラスに`writeReplace`メソッドを追加する
1. `static`インナークラスに`readResolve`メソッドを追加する
1. エンクロージングクラスに`readObject`メソッドを追加する

- シリアライズ時に`writeReplace`メソッドが呼び出されるので、`writeReplace`メソッドには`static`インナークラスのインスタンスを返すよう書いておく
- デシリアライズ時に`readResolve`メソッドが呼び出されるので、エンクロージングクラスのインスタンスを返すように書いておく
- エンクロージングクラスを直接デシリアライズしようとすると`readObject`メソッドが呼ばれるので、例外を創出するように書いておく