さて、私は長年のOO開発者ですが、これは "newfound"という機能プログラミングの世界に入り込んでいます。これに関連して、私はnull
とthrow
のようにコーディングしようとしています。 Javaの土地にはOption
とEither
のモナドで遊んでいます。 (少なくとも、私はと考えています。彼らはモナドです;私はまだその用語に慣れていませんし、私が正しく使用しているかどうかは...)私はAtlassian Fugueライブラリから出ます。 Functional Javaライブラリーを調べてみましたが、それは私が現時点で準備しているよりはるかに大きくなっています。もしfjが私の必要とすることを実行し、フーガはしない、私はそれのためにすべてです。Fugue/FunctionalJavaを使用してNullからThrowするには?
基本的に、私が達成しようとしていることはこのかなり醜いJavaコードと同等です:Either
モナドを使用して、
InputObject input = blah();
try {
final String message = getMessage(input);
if (message != null) {
try {
final ProcessedMessage processedMessage = processMessage(message);
if (processedMessage != null) {
try {
final ProcessedDetails details = getDetails(notificationDetails);
if (details != null) {
try {
awesomeStuff(details);
} catch (AwesomeStuffException ase) {
doSomethingWithAwesomeStuffException(ase);
}
}
} catch (GetDetailsException gde) {
doSomethingWithGetDetailsException(gde);
}
}
} catch (ProcessMessageException pme) {
doSomethingWithProcessMessageException(pme);
}
}
} catch (GetMessageException gme) {
doSomethingWithGetMessageException(gme);
}
単純に、私はこのような何かを行うことができるように期待していた。
getMessage(input).fold(this::doSomethingWithGetMessageException, this::processMessage)
.fold(this::doSomethingWithProcessMessageException, this::getDetails)
.fold(this::doSomethingWithGetDetailsException, this::awesomeStuff)
.foldLeft(this::doSomethingWithAwesomeStuffException);
...ここで、ロジックishの各メソッドは、適切な例外(恐らくドメイン固有のエラークラスですが、例外は今のところ十分です)を左に、そしてOption<something>
をリグht。 doSomethingWith...
メソッドは、エラーに対してどのようなログ/処理を行ってもかまいません。論理的方法の例は、次のようになります。
Either<GetMessageException, Option<String>> getMessage(final InputObject input) {
if (input == null) {
return Either.left(new GetMessageException("Input was null");
}
try {
return Either.right(loadMessage(input));
} catch (Exception ex) {
return Either.left(new GetMessageException(ex));
}
}
他の方法も同様に定義されます。好ましくはではなくで、パラメータとしてOption
を取ります。以前のメソッドがOption.none
を返した場合、このメソッドは単に呼び出されません。
私が実際にこれをテストするのを妨げたジェネリック型のコンパイラエラーのネストを除いて、論理的には、私がとにかくほしいと思うようには見えません。最初のEither.left値が返された後でopを返しますが、もっと見ると、Either.leftの結果を次の呼び出しに渡してさらに続行しようとしていると推測しています。
私はwas
種類のオプションを使用して、ちょうど私の目標を達成することができ:
ProcessedMessage processMessage(final String message) {
try {
return doProcessing(message);
} catch (Exception ex) {
final GetMessageException gme = new GetMessageException(ex);
doSomethingWithGetMessageException(gme);
return null;
}
}
:元のブロックと同じロジックを達成するために、残念ながら
getMessage(input).map(this::processMessage)
.map(this::getDetails)
.map(this::awesomeStuff);
を、ロジック・メソッドはこれに同様に実現されるだろう
は結果をOption
に持ち上げますので、ここでnull
を返しても問題ありません。残念ながら、私は依然として呼び出し元からのエラー状態を隠しています(さらに悪いIMOの場合はnull
を使用してエラーを示しています)、doProcessingが潜在的に妥当な理由でnull
を返すかどうかは何も言いません。
だから、基本的に、私は以前のgetMessage例の線に沿ってメソッドのシグネチャを持つようにようをいただきたい -
Either<GetMessageException, Option<String>> getMessage(final InputObject input)
私は、戻り値を確認することができるという考えが好きで、時を知っています一見 "この方法は失敗するか、そこにあるかもしれないし、そうでないかもしれない何かを返すでしょう。「しかし、私はFPにあまりにも新たなんだとどのようにこれについて行くには見当もつかない。
そして、私の理解を(おそらく欠陥はあるが)、私は(ただし
getMessage(input).fold(this::doSomethingWithGetMessageException, this::processMessage)
.fold(this::doSomethingWithProcessMessageException, this::getDetails)
.fold(this::doSomethingWithGetDetailsException, this::awesomeStuff)
.foldLeft(this::doSomethingWithAwesomeStuffException);
に似た何かを行うことができるということですすなわち
doSomethingWithXException
メソッドを呼び出して、停止(Either.left後の任意の時点で
- 停止処理が処理されること)は、異なる方法と可能性ists(関連する関数がオプションを返す場合はOption.none()ではありません)。
awesomeStuff
への呼び出しが失敗した場合は、doSomethingWithAwesomeStuffException
とコールしてください。他の方法が失敗した場合は、届きません。
私は妥当でさえしようとしていますか?私は、いくつかの可能性はあると確信していますが、これをJavaの構文に挑戦するのはあまりにも複雑で、たとえそれらのライブラリ(または私が気づいていない他のライブラリ)を使用していてもかまいません。
私はこのコードが最初は奇妙だと思います。ヌル結果と例外を混在させています.2つの異なるアプローチを扱うのは非常に難しいです。そしてif-conditionを逆にすると、ネストされたブロックを避けることができます。コードを読みやすくします。それとも単なる学問的な例ですか? – kan
ところで、トライモードがあります。https://github.com/jasongoodwin/better-java-monads/blob/master/src/main/java/com/jasongoodwin/monads/Try.java – kan
ほとんど学業だけです。私はモナド様式のコードを書こうとし始めましたが、それがうまくいかなかったときに、「普通の」Javaで実装する方法を簡単に書きました。 「実世界」のJavaでは、例外をログに記録して人生を進む単一のキャッチブロックがあると思います。 – MCory