如何将带计时与异常捕获的Java代码封装为辅助函数?
如何将重复的计时与异常处理代码封装为辅助函数?
这是个非常典型的代码复用场景,咱们可以借助Java 8+的函数式接口和Lambda表达式,把这段重复的计时、异常处理逻辑优雅地封装起来,以后再写类似的逻辑直接调用就行,再也不用复制粘贴啦。
第一步:定义一个支持抛出IOException的函数式接口
标准的Runnable接口不允许抛出受检异常(比如IOException),所以咱们自定义一个专用的接口:
@FunctionalInterface interface IoRunnable { void run() throws IOException; }
这个接口只定义了一个无返回值、可以抛出IOException的方法,刚好匹配你代码里doSomething()、doAnotherThing()这类方法的签名。
第二步:编写辅助函数封装重复逻辑
咱们可以把计时、日志、异常处理的逻辑都放到一个工具类的静态方法里:
import java.util.logging.Logger; public class TimingUtils { // 初始化日志对象 private static final Logger logger = Logger.getLogger(TimingUtils.class.getName()); /** * 执行一个IO操作并记录耗时 * @param operationName 操作名称,用于日志输出 * @param operation 要执行的IO操作 */ public static void timedIoOperation(String operationName, IoRunnable operation) { try { long t0 = System.nanoTime(); // 执行传入的业务逻辑 operation.run(); long t1 = System.nanoTime(); // 记录耗时日志 logger.info("{} takes {} nanoseconds", operationName, t1 - t0); } catch (IOException ex) { // 异常日志带上操作名称和异常栈,方便排查问题 logger.error("Something wrong happened during operation: {}", operationName, ex); // 如果需要让上层调用者处理异常,可以在这里重新抛出:throw ex; } } }
第三步:简化原来的业务代码
现在你原来的两段重复代码可以简化成一行调用:
原来的第一段代码:
try { long t0 = System.nanoTime(); obj.doSomething(); long t1 = System.nanoTime(); Logger.info("doSomthing takes {} nanoseconds", t1-t0); } catch (IOException ex) { Logger.error("something wrong happened"); }
现在改成:
TimingUtils.timedIoOperation("doSomething", () -> obj.doSomething());
原来的第二段代码:
try { long t0 = System.nanoTime(); obj.doAnotherThing(); long t1 = System.nanoTime(); Logger.info("doSomthing takes {} nanoseconds", t1-t0); } catch (IOException ex) { Logger.error("something wrong happened"); }
现在改成:
TimingUtils.timedIoOperation("doAnotherThing", () -> obj.doAnotherThing());
额外优化点说明
- 解决了原代码里的日志拼写错误(第二段日志写的还是"doSomthing"),现在操作名称是传入的,统一且准确。
- 异常日志里加入了异常栈信息,原代码里的
Logger.error没有传递异常对象,会丢失关键的排查信息,封装后补上了这个细节。 - 如果以后需要修改计时方式(比如改成毫秒)、调整日志格式,只需要修改
timedIoOperation这一个方法就行,所有调用处都会自动生效,维护起来特别方便。
内容的提问来源于stack exchange,提问作者Lubor
相关产品推荐
相关产品推荐

