web-dev-qa-db-ja.com

Java 8-条件が満たされるまで(間隔で)メソッドを再試行します

戻り値に関する条件が満たされるまでメソッドを実行できるクラスを作成したい。

これは次のようになります

methodPoller.poll(pollDurationSec, pollIntervalMillis)
            .method(dog.bark())
            .until(dog -> dog.bark().equals("Woof"))
            .execute();

私のメソッドポーラーは次のように見えます()// GuiSimの回答の後に

public class MethodPoller {
    Duration pollDurationSec;
    int pollIntervalMillis;


    public MethodPoller() {
    }

    public MethodPoller poll(Duration pollDurationSec, int pollIntervalMillis) {
        this.pollDurationSec = pollDurationSec;
        this.pollIntervalMillis = pollIntervalMillis;
        return this;
    }

    public <T> MethodPoller method(Supplier<T> supplier) {

        return this;
    }

    public <T> MethodPoller until(Predicate<T> predicate) {

        return this;
    }
}

しかし、私はここからの操作に苦労しています。
条件が満たされるまで、一般的な方法に再試行を実装するにはどうすればよいですか?
ありがとうございます。

16
Bick

はい、これはJava 7で簡単に行うことができ、Java 8。

methodメソッドのパラメーターはJava.util.function.Supplier<T>であり、untilメソッドのパラメーターはJava.util.function.Predicate<T>である必要があります。

次に、メソッド参照またはラムダ式を使用して、次のようにポーラーを作成できます。

myMethodPoller.poll(pollDurationInteger, intervalInMillisecond)
          .method(payment::getStatus)
          .until (paymentStatus -> paymentStatus.getValue().equals("COMPLETED"))
          .execute();

補足として、Java 8を使用する場合、ポーリング時間と間隔を表すために整数の代わりにJava.time.Durationを使用することをお勧めします。

https://github.com/rholder/guava-retrying も検討することをお勧めします。これはおそらく使用できるライブラリです。そうでない場合は、Nice Fluent APIを備えているため、APIの良いインスピレーションになる可能性があります。

編集:質問の更新に続いて、ここに簡単な実装があります。 TODOとして完成させるための一部を残しました。

import Java.time.Duration;
import Java.util.function.Predicate;
import Java.util.function.Supplier;

public class MethodPoller<T> {

    Duration pollDurationSec;
    int pollIntervalMillis;

    private Supplier<T> pollMethod = null;
    private Predicate<T> pollResultPredicate = null;

    public MethodPoller() {
    }

    public MethodPoller<T> poll(Duration pollDurationSec, int pollIntervalMillis) {
        this.pollDurationSec = pollDurationSec;
        this.pollIntervalMillis = pollIntervalMillis;
        return this;
    }

    public MethodPoller<T> method(Supplier<T> supplier) {
        pollMethod = supplier;
        return this;
    }

    public MethodPoller<T> until(Predicate<T> predicate) {
        pollResultPredicate = predicate;
        return this;
    }

    public T execute()
    {
        // TODO: Validate that poll, method and until have been called.

        T result = null;
        boolean pollSucceeded = false;
        // TODO: Add check on poll duration
        // TODO: Use poll interval
        while (!pollSucceeded) {
            result = pollMethod.get();
            pollSucceeded = pollResultPredicate.test(result);
        }

        return result;
    }
}

使用例:

import static org.junit.Assert.assertTrue;
import Java.util.UUID;
import org.junit.Test;

public class MethodPollerTest
{

    @Test
    public void test()
    {
        MethodPoller<String> poller = new MethodPoller<>();
        String uuidThatStartsWithOneTwoThree = poller.method(() -> UUID.randomUUID().toString())
                                                     .until(s -> s.startsWith("123"))
                                                     .execute();
        assertTrue(uuidThatStartsWithOneTwoThree.startsWith("123"));
        System.out.println(uuidThatStartsWithOneTwoThree);
    }
}
22
GuiSim

これを自分で書く代わりに、 Awaitility を使用できますか?

await()
    .atMost(3, SECONDS)
    .until(dog::bark, equalTo("woof"));
15
Kkkev

Failsafe を使用したソリューションは次のとおりです。

RetryPolicy retryPolicy = new RetryPolicy()
  .retryIf(bark -> bark.equals("Woof"))
  .withMaxDuration(pollDurationSec, TimeUnit.SECONDS);
  .withDelay(pollIntervalMillis, TimeUnit.MILLISECONDS);

Failsafe.with(retryPolicy).get(() -> dog.bark());

ご覧のように非常に単純で、正確なシナリオを処理します。

4
Jonathan

RxJava を使用できます

  Observable.interval(3, TimeUnit.SECONDS, Schedulers.io())
                .map(tick -> dog)
                .takeWhile( dog-> { return ! dog.bark().equals("Woof"); })
                .subscribe(dog ->dog.bark());


        try {
            Thread.sleep(10000);
        }catch(Exception e){}

http://blog.freeside.co/2015/01/29/simple-background-polling-with-rxjava/

3
frhack