首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用java 8特性简化重试代码块

如何使用java 8特性简化重试代码块
EN

Stack Overflow用户
提问于 2016-06-29 17:11:29
回答 4查看 29.2K关注 0票数 12

在我的代码中,我有一个部分试图连接到某个外部接口,如果它失败了,那么它将重试固定次数。代码可以工作,但有点难看。我想知道是否可以用一种更优雅的方式使用一些花哨的Java8特性来完成这一任务?

代码语言:javascript
复制
int count = 0;
final int maxRetries = 3;
while ( count < maxRetries )
{
   try
   {
     // Some Code
     // break out of loop on success
   }
   catch ( final ExecutionException e )
   {
      LOG.debug( "retrying..." );
      if ( ++count >= maxRetries )
      {
         LOG.debug( "do something else...");
         //do something else
      }
   }
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-06-29 18:30:33

您可以做的是分离出重试逻辑。你需要一些辅助脚手架:

代码语言:javascript
复制
interface ThrowingTask {
    void run() throws ExecutionException;
}

现在,你写:

代码语言:javascript
复制
boolean runWithRetries(int maxRetries, ThrowingTask t) { 
    int count = 0;
    while (count < maxRetries) {
        try {
            t.run();
            return true;
        }
        catch (ExecutionException e) {
            if (++count >= maxRetries)
                return false;
        }
    }
}

现在,您可以使用重试运行事物,而不必将任务逻辑与重试逻辑混为一谈:

代码语言:javascript
复制
runWithRetries(MAX_RETRIES, () -> { /* do stuff */ });

您可以根据需要对此进行调整,因为您可以接受在重试时调用的lambdas,返回重试计数等。但游戏是编写像runWithRetries这样的方法,这些方法捕获控制流,但抽象需要完成哪些行为--所以您只需要编写一次重试循环,然后在需要的地方填写您想要的实际行为。

票数 28
EN

Stack Overflow用户

发布于 2016-06-29 18:26:54

嗯,在我看来,更多的功能方法将是使用Trymonad,遗憾的是,在jdk 8中,这一点并不适用于我们:

尽管如此,您仍然可以使用提供它的更好的单人图书馆。有了这样的实现,您就可以得到这样的实现:

代码语言:javascript
复制
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的调用,如果尝试recoverWith失败,则尝试下一个tryAttempt调用。客户端代码将如下所示:

代码语言:javascript
复制
tryTimes(10, () -> {
            // all the logic to do your possibly failing stuff
        }
);

因此,客户端代码将获得Try<T>,它可以通过直接调用.get() (如果成功返回值,如果失败抛出底层异常)或使用库文档中描述的其他方法来解压缩。

希望能帮上忙。

更新:

这也可以使用filterfindFirstlimit以功能方式完成,并且不需要任何外部库:

代码语言:javascript
复制
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次数,但将在第一次成功尝试时停止。

票数 7
EN

Stack Overflow用户

发布于 2017-09-08 12:42:39

类似于一些建议的方法,您可以创建一个类,将重试功能与您的其他代码分开。下面的类就是这样做的,并且允许您接受一个输入并返回一些结果:

代码语言:javascript
复制
public class Retrier<T, R> {
    private static final int DEFAULT_RETRY_COUNT = 3;
    private int retryCount;
    private Function<T, R> retriable;
    private T input;

    public Retrier(T input, Function<T, R> retriable) {
        this(input, retriable, DEFAULT_RETRY_COUNT);
    }

    public Retrier(T input, Function<T, R> retriable, int retryCount) {
        this.retryCount = retryCount;
        this.retriable = retriable;
        this.input = input;
    }

    public R execute() {
        int count = 0;
        while(true) {
            try {
                return retriable.apply(input);
            }
            catch (Exception e) {
                if (++count >= retryCount) {
                    throw e;
                }
            }
        }
    }
}

然后你可以像这样使用它。

代码语言:javascript
复制
String result = new Retrier<String, String>("input", input -> {/* process the input and return the result*/}).execute();

无论您的代码在何处抛出异常,它都会被重新尝试。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38106111

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档