まあ、私の意見では、より機能的なアプローチは、あなたのことを持つ。8それでも:(
あなたはまだそれを提供better-monads libraryを使用することができます残念ながら、JDKで私たちのためにそこではないTry
モナドを使用するようになりますこのようないくつかの実装を思い付くことができます。
public static <Out> Try<Out> tryTimes(int times, TrySupplier<Out> attempt) {
Supplier<Try<Out>> tryAttempt =() -> Try.ofFailable(attempt::get);
return IntStream.range(1, times)
.mapToObj(i -> tryAttempt)
.reduce(tryAttempt, (acc, current) ->() -> acc.get().recoverWith(error -> current.get()))
.get();
}
長い話を短く、この機能にtryAttempt
のと失敗した場合にだけチェーン・コールは、次のCALをrecoverWith
しようlのtryAttempt
。基礎となるスロー障害が発生した場合には、値を返す結果のクライアントコードが成功した場合に.get()
の直接呼び出し(で展開することができTry<T>
を取得するために起こっていると
tryTimes(10,() -> {
// all the logic to do your possibly failing stuff
}
);
:クライアントコードは次のように見えるように起こっています例外)またはライブラリのドキュメントに記載されている他のメソッドを使用します。
希望します。
UPDATE:
これはfilter
、findFirst
とlimit
を使用して機能的な方法でも行うことができ、任意の外部ライブラリなし:
interface ThrowingSupplier<Out> { Out supply() throws Exception; }
public static <Out> Optional<Out> tryTimes(int times, ThrowingSupplier<Out> attempt) {
Supplier<Optional<Out>> catchingSupplier =() -> {
try {
return Optional.ofNullable(attempt.supply());
} catch (Exception e) {
return Optional.empty();
}
};
return Stream.iterate(catchingSupplier, i -> i)
.limit(times)
.map(Supplier::get)
.filter(Optional::isPresent)
.findFirst()
.flatMap(Function.identity());
}
クライアントコードは同じまま。また、式times
回は評価されませんが、最初の正常な試行では停止しますのでご注意ください。
このコードでは何が醜いですか?再試行するには、ループ(または再帰)する必要があります。 (関連:http://stackoverflow.com/questions/34740091/apply-retries-in-a-rxjavaおよびhttp://stackoverflow.com/questions/30989558/java-8-retry-a-method-until-a -comondition-is-intervals-fulfiled-in-intervals) – Tunaki
ええ、私はここではあまりにも扱いにくいかもしれませんが、これはより機能的な、あるいは宣言的な方法で行うことができるかどうかは不思議です。読み込み可能... – Moonlit
醜いのは、特定のタスクのコードを再試行/失敗管理ロジックと競合させることです。これは、リトライロジックを場所全体に複製することを意味します。カットアンドペーストによって、リトライ動作を後で一貫して調整することは事実上不可能です。 –