1. 序章

JDKが提供するFunctionalInterfaces は、チェックされた例外を処理するために適切に準備されていません。 この問題について詳しく知りたい場合は、この記事を確認してください。

この記事では、機能的なJavaライブラリVavrを使用してこのような問題を克服するさまざまな方法を見ていきます。

Vavrとその設定方法の詳細については、この記事をご覧ください。

2. CheckedFunctionを使用する

Vavrは、チェックされた例外をスローする機能を持つ機能インターフェイスを提供します。 これらの関数は、 CheckedFunction0 CheckedFunction1 など、CheckedFunction8まで続きます。 関数名の末尾にある0、1、…8 は、関数の入力引数の数を示します。

例を見てみましょう:

static Integer readFromFile(Integer integer) throws IOException {
    // logic to read from file which throws IOException
}

IOException を処理せずに、ラムダ式内で上記のメソッドを使用できます。

List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);

CheckedFunction1<Integer, Integer> readFunction = i -> readFromFile(i);
integers.stream()
 .map(readFunction.unchecked());

ご覧のとおり、標準の try-catch またはラッパーメソッドがなくても、ラムダ式内で例外スローメソッドを呼び出すことができます。

Stream APIでこの機能を使用する場合は注意が必要です。例外として、操作がすぐに終了し、残りのストリームが破棄されるためです。

3. ヘルパーメソッドの使用

APIクラスは、前のセクションの例のショートカットメソッドを提供します。

List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);

integers.stream()
  .map(API.unchecked(i -> readFromFile(i)));

4. リフティングの使用

IOException を適切に処理するために、ラムダ式内に標準のtry-catchブロックを導入できます。 ただし、ラムダ式の簡潔さは失われます。 Vavrの持ち上げは私たちの救助に来ます。

リフティングは関数型プログラミングの概念です。 結果としてOptionを返す全体関数に部分関数を持ち上げることができます。

部分関数は、ドメイン全体に対して定義される関数全体ではなく、ドメインのサブセットに対してのみ定義される関数です。 部分関数がサポート範囲外の入力で呼び出された場合、通常は例外がスローされます。

前のセクションの例を書き直してみましょう。

List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
 
integers.stream()
  .map(CheckedFunction1.lift(i -> readFromFile(i)))
  .map(k -> k.getOrElse(-1));

解除された関数の結果はOptionであり、例外の場合の結果はOption.Noneになることに注意してください。 メソッドgetOrElse()は、Option.Noneの場合に返す代替値を取ります。

5. を使用するを試す

前のセクションのメソッドlift()は、プログラムの突然の終了の問題を解決しますが、実際には例外を飲み込みます。 その結果、私たちのメソッドの消費者は、何がデフォルト値になったのかを知りません。 別の方法は、Tryコンテナを使用することです。

Try は、例外をスローする可能性のある操作を囲むことができる特別なコンテナーです。 この場合、結果の Try オブジェクトは、 Failure を表し、例外をラップします。

Tryを使用するコードを見てみましょう。

List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
integers.stream()
  .map(CheckedFunction1.liftTry(i -> readFromFile(i)))
  .flatMap(Value::toJavaStream)
  .forEach(i -> processValidValue(i));

Try コンテナとその使用方法の詳細については、この記事を確認してください。

6. 結論

このクイック記事では、Vavrライブラリの機能を使用して、ラムダ式の例外を処理しながら問題を回避する方法を示しました。

これらの機能により、例外をエレガントに処理できますが、細心の注意を払って使用する必要があります。 これらのアプローチのいくつかでは、メソッドのコンシューマーは、明示的に宣言されていなくても、予期しないチェックされた例外に驚かれる可能性があります。

この記事のすべての例の完全なソースコードは、Githubにあります。