同事:把"重试"抽象出来做个工具类吧
背景介绍
我们在工作中难免会写一些重复性的代码,所以需要我们具备一定的抽象能力,比如把共同的逻辑抽取到抽象类中,也可以通过一些工具类来避免冗余代码
今天这篇文章就是把一个调用服务的重试功能抽取出一个工具类,以备复用。这里为了方便介绍,把调用服务简化成方法的调用,被调用的 foo 方法如下:
public static List<String> foo() {// 没有显示抛出异常
System.out.println("调用方法");
// 模拟抛出异常
System.out.println(1/0);
List<String> list = new ArrayList<>();
list.add("1");
return list;
}
调用方和重试逻辑如下:
List<String> result = null;
// 重试次数
int retryCount = 0;
// 调用服务的开关,默认打开
boolean callSwitch = true;
// 只要调用服务开关开着,并且重试次数不大于最大的重试次数,就调用服务
while (callSwitch && retryCount <= 3) {
try {
// 调用服务
result = foo();
// 省略了对结果的校验,假设到了这里就说明没有问题,把调用服务开关关掉
callSwitch = false;
} catch (Exception e) {
// 发生了异常(比如超时,就需要重试了)
// 调用服务的开关打开
callSwitch = true;
retryCount++;
}
}
// 后面对 result 进行处理
其实上面的代码就已经解决了,服务重试的逻辑,测试没有问题后,可以提交代码让同事帮忙进行 CR 了,可是小朋同学看到这个代码后,给了建议:
可以抽象一层,提出一个 retry 的工具类,这样大家都可以简单复用你的 retry 逻辑
抽象思考过程
白牙心想,也对哈,那就提出一个工具类吧,可是发了会儿呆,竟然没有头绪(反映出了抽象能力的薄弱,平时要多注意抽象能力的培养)。小朋见状,给了一点提示,白牙立马在键盘上噼里啪啦敲击了起来,就有了下面的工具类
主要依赖函数式接口 Supplier 和 BiFunction
public class RetryUtil {
public static <T> T retry(int maxRetryCount, Supplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) {
T result = null;
Exception exception = null;
int retryCount = 0;
boolean callMethod = true;
while (callMethod && retryCount <= maxRetryCount) {
try {
// 获取调用服务的结果
result = supplier.get();
} catch (Exception e) {
// 如果重试次数不小于最大重试次数,就抛出异常,我们把对异常的处理交给业务方
if (retryCount >= maxRetryCount) {
throw e;
}
exception = e;
}
// 对结果进行判断
callMethod = consumer.apply(result, exception);
if (callMethod) {
retryCount++;
}
}
return result;
}
}
业务调用方的代码如下:
List<String> result1 = retry(3,// 最大重试次数
()-> foo(),// 调用服务
(list, e) -> e != null || list == null || list.isEmpty());// 对结果处理
自测没有问题后,又提交代码让小朋给 CR 一下,小朋凝视了会儿,就有了下面的对话
小朋:“retry 方法没有抛出异常”
白牙:“被调用的服务没有显示的抛出异常,这里也就没有抛出”
小朋:“那人如果有服务方显示抛出异常呢?”
白牙:“我再改一版”
服务方显示抛出了异常,这样 retry 方法也得显示抛出异常,但调用方就会显示会处理的异常,如下所示:
public static List<String> foo() throws Exception{// 显示抛出异常
System.out.println("调用方法");
// 模拟抛出异常
System.out.println(1/0);
List<String> list = new ArrayList<>();
list.add("1");
return list;
}
public class RetryUtil {
public static <T> T retry(int maxRetryCount, Supplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) throws Exception{
// 省略...
}
提示未处理的异常
出现这种情况是因为 Supplier 的 get 方法没有抛出异常
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
既然你不支持,那就自己写个呗,于是就有了下面的 DspSupplier,它和 Supplier 的主要区别就是在 get 方法中显示抛出了异常
@FunctionalInterface
interface DspSupplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get() throws Exception;
}
于是 retry 方法就变成了下面这样子
public class RetryUtil {
public static <T> T retry(int maxRetryCount, DspSupplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) throws Exception{
// 省略...
}
使用了自定义的 Supplier 后,调用方就没有 “Unhandled exception” 了
总结
我们平时再开发的过程中,可以尝试去利用函数式接口去实现一些逻辑的抽取,做成一个工具类,供大家使用,简化人力,也是对自己编码能力的一个提升。 上面的案例比较简单,但麻雀虽小,五脏俱全,也是一个不错的体验
- poj-------(2240)Arbitrage(最短路)
- MySQL在线DDL修改表结构的简单经验分享
- HDUOJ-----(1162)Eddy's picture(最小生成树)
- hduoj----1142A Walk Through the Forest(记忆化搜索+最短路)
- java设计之简单的JAVA计算器
- Java之线程———GUI线程(包含打字游戏和计时器俩个GUI实列)
- la----3695 City Game(最大子矩阵)
- poj------(3468)A Simple Problem with Integers(区间更新)
- hdu-------(1698)Just a Hook(线段树区间更新)
- NBitcoin:密码学第2部分
- gh-ost:在线DDL修改MySQL表结构工具
- poj-----(2828)Buy Tickets(线段树单点更新)
- javaSE之线程联合
- ASM 翻译系列第三十一弹:了解ASM文件的空间分配
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Destoon 6.0 guestbook.php 通用SQL注入漏洞
- Hadoop2.7.6_01_部署
- Hadoop2.7.6_02_HDFS常用操作
- Bottle HTTP 头注入漏洞探究
- Hadoop2.7.6_03_HDFS原理
- Hadoop2.7.6_04_HDFS的Shell操作与常见问题
- Hadoop2.7.6_05_mapreduce-Yarn
- Hadoop2.7.6_06_mapreduce参数优化
- NFS服务搭建与配置
- Hadoop2.7.6_07_HA高可用
- Hadoop2.7.6_08_Federation联邦机制 1.1. HDFS-federation图解2.1. 注意事项3.1. 部署3.2. 环境变量3.3. c
- ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析
- Hive-1.2.1_01_安装部署
- Supervisord远程命令执行漏洞(CVE-2017-11610)
- Hive-1.2.1_02_简单操作与访问方式