背景介绍

我们在工作中难免会写一些重复性的代码,所以需要我们具备一定的抽象能力,比如把共同的逻辑抽取到抽象类中,也可以通过一些工具类来避免冗余代码

今天这篇文章就是把一个调用服务的重试功能抽取出一个工具类,以备复用。这里为了方便介绍,把调用服务简化成方法的调用,被调用的 foo 方法如下:

  1. public static List<String> foo() {// 没有显示抛出异常
  2. System.out.println("调用方法");
  3. // 模拟抛出异常
  4. System.out.println(1/0);
  5. List<String> list = new ArrayList<>();
  6. list.add("1");
  7. return list;
  8. }

调用方和重试逻辑如下:

  1. List<String> result = null;
  2. // 重试次数
  3. int retryCount = 0;
  4. // 调用服务的开关,默认打开
  5. boolean callSwitch = true;
  6. // 只要调用服务开关开着,并且重试次数不大于最大的重试次数,就调用服务
  7. while (callSwitch && retryCount <= 3) {
  8. try {
  9. // 调用服务
  10. result = foo();
  11. // 省略了对结果的校验,假设到了这里就说明没有问题,把调用服务开关关掉
  12. callSwitch = false;
  13. } catch (Exception e) {
  14. // 发生了异常(比如超时,就需要重试了)
  15. // 调用服务的开关打开
  16. callSwitch = true;
  17. retryCount++;
  18. }
  19. }
  20. // 后面对 result 进行处理

其实上面的代码就已经解决了,服务重试的逻辑,测试没有问题后,可以提交代码让同事帮忙进行 CR 了,可是小朋同学看到这个代码后,给了建议:

可以抽象一层,提出一个 retry 的工具类,这样大家都可以简单复用你的 retry 逻辑

抽象思考过程

白牙心想,也对哈,那就提出一个工具类吧,可是发了会儿呆,竟然没有头绪(反映出了抽象能力的薄弱,平时要多注意抽象能力的培养)。小朋见状,给了一点提示,白牙立马在键盘上噼里啪啦敲击了起来,就有了下面的工具类

主要依赖函数式接口 Supplier 和 BiFunction

  1. public class RetryUtil {
  2. public static <T> T retry(int maxRetryCount, Supplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) {
  3. T result = null;
  4. Exception exception = null;
  5. int retryCount = 0;
  6. boolean callMethod = true;
  7. while (callMethod && retryCount <= maxRetryCount) {
  8. try {
  9. // 获取调用服务的结果
  10. result = supplier.get();
  11. } catch (Exception e) {
  12. // 如果重试次数不小于最大重试次数,就抛出异常,我们把对异常的处理交给业务方
  13. if (retryCount >= maxRetryCount) {
  14. throw e;
  15. }
  16. exception = e;
  17. }
  18. // 对结果进行判断
  19. callMethod = consumer.apply(result, exception);
  20. if (callMethod) {
  21. retryCount++;
  22. }
  23. }
  24. return result;
  25. }
  26. }

业务调用方的代码如下:

  1. List<String> result1 = retry(3,// 最大重试次数
  2. ()-> foo(),// 调用服务
  3. (list, e) -> e != null || list == null || list.isEmpty());// 对结果处理

自测没有问题后,又提交代码让小朋给 CR 一下,小朋凝视了会儿,就有了下面的对话

小朋:“retry 方法没有抛出异常”

白牙:“被调用的服务没有显示的抛出异常,这里也就没有抛出”

小朋:“那人如果有服务方显示抛出异常呢?”

白牙:“我再改一版”

服务方显示抛出了异常,这样 retry 方法也得显示抛出异常,但调用方就会显示会处理的异常,如下所示:

  1. public static List<String> foo() throws Exception{// 显示抛出异常
  2. System.out.println("调用方法");
  3. // 模拟抛出异常
  4. System.out.println(1/0);
  5. List<String> list = new ArrayList<>();
  6. list.add("1");
  7. return list;
  8. }
  1. public class RetryUtil {
  2. public static <T> T retry(int maxRetryCount, Supplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) throws Exception{
  3. // 省略...
  4. }

出现这种情况是因为 Supplier 的 get 方法没有抛出异常

  1. @FunctionalInterface
  2. public interface Supplier<T> {
  3. /**
  4. * Gets a result.
  5. *
  6. * @return a result
  7. */
  8. T get();
  9. }

既然你不支持,那就自己写个呗,于是就有了下面的 DspSupplier,它和 Supplier 的主要区别就是在 get 方法中显示抛出了异常

  1. @FunctionalInterface
  2. interface DspSupplier<T> {
  3. /**
  4. * Gets a result.
  5. *
  6. * @return a result
  7. */
  8. T get() throws Exception;
  9. }

于是 retry 方法就变成了下面这样子

  1. public class RetryUtil {
  2. public static <T> T retry(int maxRetryCount, DspSupplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) throws Exception{
  3. // 省略...
  4. }

使用了自定义的 Supplier 后,调用方就没有 “Unhandled exception” 了

总结

我们平时再开发的过程中,可以尝试去利用函数式接口去实现一些逻辑的抽取,做成一个工具类,供大家使用,简化人力,也是对自己编码能力的一个提升。

上面的案例比较简单,但麻雀虽小,五脏俱全,也是一个不错的体验

欢迎关注公众号 【每天晒白牙】,获取最新文章,我们一起交流,共同进步!

把"重试"抽象出来做个工具类吧的更多相关文章

  1. java中使用反射做一个工具类,来为指定类中的成员变量进行赋值操作,使用与多个类对象的成员变量的赋值。

    //------------------------------------------------我是代码的分割线 // 首选是一个工具类,在该工具类里面,定义了一个方法,public void s ...

  2. Redis设置Key/value的规则定义和注意事项(附工具类)

    对于redis的存储key/value键值对,经过多次踩坑之后,我们总结了一套规则:这篇文章主要讲解定义key/value键值对时的定义规则和注意事项. 前面一篇文章讲了如何定义Redis的客户端和D ...

  3. 【SSH三大框架】Hibernate基础第二篇:编写HibernateUtil工具类优化性能

    相对于上一篇中的代码编写HibernateUtil类以提高程序的执行速度 首先,仍然要写一个javabean(User.java): package cn.itcast.hibernate.domai ...

  4. Java并发工具类之线程间数据交换工具Exchanger

    Exchanger是一个用于线程间协做的工具类,主要用于线程间的数据交换.它提供了一个同步点,在这个同步点,两个线程可以彼此交换数据.两个线程通过exchange方法交换数据,如果一个线程执行exch ...

  5. jxl java工具类,导出excel,导入数据库

    1: 引入jxl jar 我使用的为maven管理, <!--Excel工具--> <dependency> <groupId>net.sourceforge.je ...

  6. IP工具类-自己动手做个ip解析器

    IP工具类-自己动手做个ip解析器 一.资料准备 导入依赖包:

  7. 为什么工具类App,都要做一个社区?

    非著名程序员涩郎 非著名程序员,字耿左直右,号涩郎,爱搞机,爱编程,是爬行在移动互联网中的一名码匠!个人微信号:loonggg,微博:涩郎,专注于移动互联网的开发和研究,本号致力于分享IT技术和程序猿 ...

  8. 【java工具类】java做的一个xml转Excel工具,基于maven工程

    说明:适合数据库导出为xml时转成Excel 本工具将上传至GitHub:https://github.com/xiaostudy/xiaostudyAPI3 doc4j的maven依赖 <!- ...

  9. 使用POI做的一个生成Excel的工具类。包含了导出Excel和解析Excel方法

    PoiExcelUtils.java /** * */ package com.common.office; import java.io.File; import java.io.FileInput ...

随机推荐

  1. Java网络编程——TCP图片上传

    1.编写一个服务器端程序,用来接收图片.创建一个监听指定端口号的ServerSocket服务端对象,在while(true)无限循环中持续调用ServerSocket的accept()方法来接收客户端 ...

  2. DjangoCBV源码分析

    目录 FBV CBV CBV基本写法 CBV源码分析 settings源码分析 FBV FBV是基于函数的视图 CBV CBV是基于类的视图 CBV基本写法 ​ 朝login提交get请求会自动执行M ...

  3. FIND_IN_SET 精确查找

    FIND_IN_SET(str,strlist) mysql专为精确匹配字符串而设置的函数 一个字符串列表就是一个由一些被‘,’符号分开的自链组成的字符串 1,2,3,4,5,6,7,8,9: 此函数 ...

  4. ACWing 248. 窗内的星星|扫描线+懒惰标记

    传送门 题目描述 在一个天空中有很多星星(看作平面直角坐标系),已知每颗星星的坐标和亮度(都是整数). 求用宽为W.高为H的矩形窗户(W,H为正整数)能圈住的星星的亮度总和最大是多少.(矩形边界上的星 ...

  5. LCA (Tarjan&倍增)

    LCA_Tarjan 参考博客:https://www.cnblogs.com/JVxie/p/4854719.html LCA的Tarjan写法需要结合并查集 从叶子节点往上并 int Find ( ...

  6. 2017CCPC杭州(ABCDJ)

    所有的题目在这里<--- 待补... Problem A. HDU6264:Super-palindrome 题意: 题目定义了一个超级回文串,这个串满足:它的任一奇数长度的串都是回文串. 现在 ...

  7. docker发布.net core程序的坑

    docker发布遇到的两个问题 1:Could not resolve CoreCLR path. For more details, enable tracing by setting COREHO ...

  8. 【Java基础总结】字符串

    1. java内存区域(堆区.栈区.常量池) 2. String length() //长度 //获取子串位置 indexOf(subStr) lastIndexOf(subStr) //获取子串 c ...

  9. UGUI之MaskableGraphic

    MaskableGraphic继承自Graphic,并且继承了IClippable, IMaskable, IMaterialModifier三个接口.它是RawImage.Image和Text的父类 ...

  10. vue报错 [Intervention] Ignored attempt to cancel a touchmove event with cancelable

    在vue开发中使用vue-awesome-swiper制作轮播图,手动拖动时会报错,解决方案: 需要滑动的标签 { touch-action: none; } -------------------- ...