Java 8 – 重试方法,直到满足条件(间隔)
我想创建一个可以运行方法的类,直到满足返回值的条件。
看起来应该是这样的
methodPoller.poll(pollDurationSec, pollIntervalMillis) .method(dog.bark()) .until(dog -> dog.bark().equals("Woof")) .execute();
我的方法poller看起来有点像这个()//跟随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 MethodPoller method(Supplier supplier) { return this; } public MethodPoller until(Predicate predicate) { return this; } }
但是我很难从这里开始。
在满足条件之前,如何实现对常规方法的重试?
谢谢。
是的,这可以在Java 7中轻松完成,甚至可以使用Java 8完成。
method
方法的参数应该是java.util.function.Supplier
,而until
方法的参数应该是java.util.function.Predicate
。
然后,您可以使用方法引用或lambda表达式来创建Poller,如下所示:
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 { Duration pollDurationSec; int pollIntervalMillis; private Supplier pollMethod = null; private Predicate pollResultPredicate = null; public MethodPoller() { } public MethodPoller poll(Duration pollDurationSec, int pollIntervalMillis) { this.pollDurationSec = pollDurationSec; this.pollIntervalMillis = pollIntervalMillis; return this; } public MethodPoller method(Supplier supplier) { pollMethod = supplier; return this; } public MethodPoller until(Predicate 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 poller = new MethodPoller<>(); String uuidThatStartsWithOneTwoThree = poller.method(() -> UUID.randomUUID().toString()) .until(s -> s.startsWith("123")) .execute(); assertTrue(uuidThatStartsWithOneTwoThree.startsWith("123")); System.out.println(uuidThatStartsWithOneTwoThree); } }
你可以使用Awaitility而不是自己写这个吗?
await() .atMost(3, SECONDS) .until(dog::bark, equalTo("woof"));
您可以使用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/
这是使用Failsafe的解决方案:
RetryPolicy retryPolicy = new RetryPolicy() .retryIf(bark -> bark.equals("Woof")) .withMaxDuration(pollDurationSec, TimeUnit.SECONDS); .withDelay(pollIntervalMillis, TimeUnit.MILLISECONDS); Failsafe.with(retryPolicy).get(() -> dog.bark());
你可以看到非常简单,并处理你的确切场景。