Java8如何优雅的记录代码运行时间

 更新时间:2025年04月20日 09:47:29   作者:李博帅  
这篇文章主要为大家详细介绍了 Java 8 中几种记录代码运行时间的优雅方式,并附上实用工具类与建议,希望可以帮助大家提高大家的代码可读性与复用性

在日常后端开发中,性能优化是一项核心任务。我们经常需要测量某段代码的执行耗时,例如查询耗时、接口响应时间、批处理任务处理时间等。在 Java 中,传统的做法可能是使用 System.currentTimeMillis():

long start = System.currentTimeMillis();
// 业务逻辑
long end = System.currentTimeMillis();
System.out.println("执行耗时: " + (end - start) + "ms");

虽然这非常直接,但在 Java 8 引入 java.time 包之后,我们可以使用更现代、更语义化的方式 —— Instant 和 Duration 来实现这一目标。

本文将带你深入了解 Java 8 中几种记录代码运行时间的优雅方式,并附上实用工具类与建议,提高你的代码可读性与复用性。

Java 8 简单实现方式

Java 8 中的 java.time.Instant 表示一个时间点,Duration 表示两个时间点之间的时长:

import java.time.Duration;
import java.time.Instant;

public class SampleTimer {
    public static void main(String[] args) {
        Instant start = Instant.now();

        // 模拟业务逻辑
        executeBusinessLogic();

        Instant end = Instant.now();
        long timeElapsed = Duration.between(start, end).toMillis();
        System.out.println("执行耗时: " + timeElapsed + " ms");
    }

    private static void executeBusinessLogic() {
        try {
            Thread.sleep(500); // 模拟耗时操作
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

相比 System.currentTimeMillis(),这种写法更具可读性和表达力,并且跨平台表现一致(System.currentTimeMillis 可能受系统时间调整影响)。

封装计时工具类(更通用 & 可复用)

为了更好地管理运行时间测量代码,我们可以封装一个小型工具类,例如 TimerUtils:

import java.time.Duration;
import java.time.Instant;
import java.util.function.Supplier;

public class TimerUtils {

    public static <T> T measure(String taskName, Supplier<T> supplier) {
        Instant start = Instant.now();
        try {
            return supplier.get();
        } finally {
            Instant end = Instant.now();
            long duration = Duration.between(start, end).toMillis();
            System.out.printf("【任务: %s】耗时: %d ms%n", taskName, duration);
        }
    }

    public static void measure(String taskName, Runnable runnable) {
        Instant start = Instant.now();
        try {
            runnable.run();
        } finally {
            Instant end = Instant.now();
            long duration = Duration.between(start, end).toMillis();
            System.out.printf("【任务: %s】耗时: %d ms%n", taskName, duration);
        }
    }
}

使用方式如下:

public class TimerUtilsTest {
    public static void main(String[] args) {
        // 没有返回值
        TimerUtils.measure("执行任务A", () -> {
            try {
                Thread.sleep(200);
            } catch (InterruptedException ignored) {}
        });

        // 有返回值
        String result = TimerUtils.measure("执行任务B", () -> {
            try {
                Thread.sleep(300);
            } catch (InterruptedException ignored) {}
            return "任务完成";
        });

        System.out.println("任务B返回结果:" + result);
    }
}

这种封装方式可以很好地提升代码的可读性、复用性,尤其适合在 Spring Boot 项目中进行日志输出分析。

进阶使用:结合日志框架输出

实际项目中,推荐的做法是将耗时统计信息输出到日志中,便于统一采集和排查性能瓶颈。结合 SLF4J + Logback,可以这样集成:

private static final Logger logger = LoggerFactory.getLogger(MyService.class);

public void process() {
    Instant start = Instant.now();

    try {
        // 执行业务逻辑
    } finally {
        long elapsed = Duration.between(start, Instant.now()).toMillis();
        logger.info("处理接口耗时: {} ms", elapsed);
    }
}

比 System.out.println 更专业,也更便于后续 ELK/Prometheus 等监控系统采集。

使用 AOP 自动记录方法执行时间(Spring Boot 推荐)

性能日志可以通过 Spring AOP 自动记录,无需在每个方法中手动添加计时代码:

1.自定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Timed {
    String value() default "";
}

2.编写切面类:

@Aspect
@Component
public class TimingAspect {
    private static final Logger logger = LoggerFactory.getLogger(TimingAspect.class);

    @Around("@annotation(timed)")
    public Object around(ProceedingJoinPoint pjp, Timed timed) throws Throwable {
        Instant start = Instant.now();
        Object result = pjp.proceed();
        long elapsed = Duration.between(start, Instant.now()).toMillis();

        String methodName = pjp.getSignature().toShortString();
        logger.info("方法 [{}] 执行耗时: {} ms", methodName, elapsed);
        return result;
    }
}

使用示例:

@Timed
public void handleRequest() {
    // 逻辑代码
}

优势:

  • 解耦业务逻辑与日志统计
    • 透明统一统计性能数据
    • 对 Controller、Service 层尤为实用

其他替代品推荐

除了 Java 原生类,还有一些开源工具类也支持高效计时:

Guava 的 Stopwatch:

Stopwatch stopwatch = Stopwatch.createStarted();
// 执行代码
stopwatch.stop();
System.out.println("耗时: " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms");

Micrometer 和 Spring Boot Actuator 提供的 @Timed 注解和 Metrics 接入更强大采集工具,如 Prometheus、Grafana。

总结

在注重性能的后端开发中,精准、高效地记录代码执行时间是不可或缺的一步。本文从 Java 8 原生的 Instant/Duration 入手,展示了编写更优雅、规范、可扩展的代码计时方式。

方法优雅度可复用性推荐度
System.currentTimeMillis一般
Instant + Duration良好
工具类封装✅✅
AOP 自动化记录极高极高✅✅✅

到此这篇关于Java8如何优雅的记录代码运行时间的文章就介绍到这了,更多相关Java8记录代码运行时间内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解spring-cloud与netflixEureka整合(注册中心)

    详解spring-cloud与netflixEureka整合(注册中心)

    这篇文章主要介绍了详解spring-cloud与netflixEureka整合(注册中心),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-02-02
  • 解决Springboot全局异常处理与AOP日志处理中@AfterThrowing失效问题

    解决Springboot全局异常处理与AOP日志处理中@AfterThrowing失效问题

    这篇文章主要介绍了解决Springboot全局异常处理与AOP日志处理中@AfterThrowing失效问题,文中介绍了两种失效场景,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-05-05
  • Mybatis提示Tag name expected的问题及解决

    Mybatis提示Tag name expected的问题及解决

    MyBatis是一个开源的Java持久层框架,用于将Java对象与数据库表进行映射,它提供了一种简单、灵活的方式来访问数据库,同时也提供了强大的SQL映射和查询功能
    2025-01-01
  • java.lang.annotation包详细介绍

    java.lang.annotation包详细介绍

    java.lang.annotation 包是 Java 标准库中的一个核心包,专门用于定义和支持 Java 注解(Annotation),这篇文章主要介绍了java.lang.annotation包介绍,需要的朋友可以参考下
    2024-07-07
  • SpringMVC HttpMessageConverter报文信息转换器

    SpringMVC HttpMessageConverter报文信息转换器

    ​​HttpMessageConverter​​​,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文。​​​HttpMessageConverter​​​提供了两个注解和两个类型:​​@RequestBody,@ResponseBody​​​,​​RequestEntity,ResponseEntity​​
    2023-01-01
  • SpringBoot整合jnotify实现针对指定目录及其(动态)子目录的监听的方法

    SpringBoot整合jnotify实现针对指定目录及其(动态)子目录的监听的方法

    本文介绍了JNotify这一Java库在SpringBoot中的应用,JNotify允许应用程序监听文件系统事件,包括文件夹/文件的创建、删除、修改和重命名,由于JNotify底层调用的关键部分是C语言开发的,所以在使用前需要在系统中加入相应的动态库
    2024-10-10
  • Java容器类源码详解 Deque与ArrayDeque

    Java容器类源码详解 Deque与ArrayDeque

    这篇文章主要介绍了Java容器类源码详解 Deque与ArrayDeque,Deque 接口继承自 Queue接口,但 Deque 支持同时从两端添加或移除元素,因此又被成为双端队列。,需要的朋友可以参考下
    2019-06-06
  • Java通过切面实现统一处理Token设置用户信息

    Java通过切面实现统一处理Token设置用户信息

    这篇文章主要介绍了Java切面统一处理Token设置用户信息,常见的后端开发中,接口请求中一般前端都是先通过用户登录获取token,每次接口请求都需要在头信息中携带token信息,后端每次都需要手动处理token信息,从token信息中解析获取用户信息,需要的朋友可以参考下
    2023-10-10
  • JAVA浮点数计算精度损失底层原理与解决方案

    JAVA浮点数计算精度损失底层原理与解决方案

    本文主要介绍了JAVA浮点数计算精度损失底层原理与解决方案。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • java开发中常遇到的各种难点以及解决思路方案

    java开发中常遇到的各种难点以及解决思路方案

    Java项目是一个复杂的软件开发过程,其中会涉及到很多技术难点,这篇文章主要给大家介绍了关于java开发中常遇到的各种难点以及解决思路方案的相关资料,需要的朋友可以参考下
    2023-07-07

最新评论