Java 8 - 重试方法,直到满足条件(以间隔为单位)

2022-09-02 05:16:11

我想创建一个可以运行方法的类,直到满足有关返回值的条件。

它应该看起来像这样

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;
    }
}

但是我很难从这里开始。
在满足条件之前,如何实现对常规方法的重试?
谢谢。


答案 1

是的,这可以在Java 7中轻松完成,甚至可以使用Java 8更干净。

方法的参数应为 a,方法的参数应为 。methodjava.util.function.Supplier<T>untiljava.util.function.Predicate<T>

然后,您可以使用方法引用或 lambda 表达式来创建轮询器,如下所示:

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 这是一个你可以使用的库。如果没有,它可能是你的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);
    }
}

答案 2

与其自己写这篇文章,你能用《Awaitility》吗

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

推荐