Java8如何優(yōu)雅的記錄代碼運(yùn)行時(shí)間
在日常后端開發(fā)中,性能優(yōu)化是一項(xiàng)核心任務(wù)。我們經(jīng)常需要測(cè)量某段代碼的執(zhí)行耗時(shí),例如查詢耗時(shí)、接口響應(yīng)時(shí)間、批處理任務(wù)處理時(shí)間等。在 Java 中,傳統(tǒng)的做法可能是使用 System.currentTimeMillis():
long start = System.currentTimeMillis();
// 業(yè)務(wù)邏輯
long end = System.currentTimeMillis();
System.out.println("執(zhí)行耗時(shí): " + (end - start) + "ms");
雖然這非常直接,但在 Java 8 引入 java.time 包之后,我們可以使用更現(xiàn)代、更語(yǔ)義化的方式 —— Instant 和 Duration 來實(shí)現(xiàn)這一目標(biāo)。
本文將帶你深入了解 Java 8 中幾種記錄代碼運(yùn)行時(shí)間的優(yōu)雅方式,并附上實(shí)用工具類與建議,提高你的代碼可讀性與復(fù)用性。
Java 8 簡(jiǎn)單實(shí)現(xiàn)方式
Java 8 中的 java.time.Instant 表示一個(gè)時(shí)間點(diǎn),Duration 表示兩個(gè)時(shí)間點(diǎn)之間的時(shí)長(zhǎng):
import java.time.Duration;
import java.time.Instant;
public class SampleTimer {
public static void main(String[] args) {
Instant start = Instant.now();
// 模擬業(yè)務(wù)邏輯
executeBusinessLogic();
Instant end = Instant.now();
long timeElapsed = Duration.between(start, end).toMillis();
System.out.println("執(zhí)行耗時(shí): " + timeElapsed + " ms");
}
private static void executeBusinessLogic() {
try {
Thread.sleep(500); // 模擬耗時(shí)操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
相比 System.currentTimeMillis(),這種寫法更具可讀性和表達(dá)力,并且跨平臺(tái)表現(xiàn)一致(System.currentTimeMillis 可能受系統(tǒng)時(shí)間調(diào)整影響)。
封裝計(jì)時(shí)工具類(更通用 & 可復(fù)用)
為了更好地管理運(yùn)行時(shí)間測(cè)量代碼,我們可以封裝一個(gè)小型工具類,例如 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("【任務(wù): %s】耗時(shí): %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("【任務(wù): %s】耗時(shí): %d ms%n", taskName, duration);
}
}
}
使用方式如下:
public class TimerUtilsTest {
public static void main(String[] args) {
// 沒有返回值
TimerUtils.measure("執(zhí)行任務(wù)A", () -> {
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {}
});
// 有返回值
String result = TimerUtils.measure("執(zhí)行任務(wù)B", () -> {
try {
Thread.sleep(300);
} catch (InterruptedException ignored) {}
return "任務(wù)完成";
});
System.out.println("任務(wù)B返回結(jié)果:" + result);
}
}
這種封裝方式可以很好地提升代碼的可讀性、復(fù)用性,尤其適合在 Spring Boot 項(xiàng)目中進(jìn)行日志輸出分析。
進(jìn)階使用:結(jié)合日志框架輸出
實(shí)際項(xiàng)目中,推薦的做法是將耗時(shí)統(tǒng)計(jì)信息輸出到日志中,便于統(tǒng)一采集和排查性能瓶頸。結(jié)合 SLF4J + Logback,可以這樣集成:
private static final Logger logger = LoggerFactory.getLogger(MyService.class);
public void process() {
Instant start = Instant.now();
try {
// 執(zhí)行業(yè)務(wù)邏輯
} finally {
long elapsed = Duration.between(start, Instant.now()).toMillis();
logger.info("處理接口耗時(shí): {} ms", elapsed);
}
}
比 System.out.println 更專業(yè),也更便于后續(xù) ELK/Prometheus 等監(jiān)控系統(tǒng)采集。
使用 AOP 自動(dòng)記錄方法執(zhí)行時(shí)間(Spring Boot 推薦)
性能日志可以通過 Spring AOP 自動(dòng)記錄,無(wú)需在每個(gè)方法中手動(dòng)添加計(jì)時(shí)代碼:
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("方法 [{}] 執(zhí)行耗時(shí): {} ms", methodName, elapsed);
return result;
}
}
使用示例:
@Timed
public void handleRequest() {
// 邏輯代碼
}
優(yōu)勢(shì):
- 解耦業(yè)務(wù)邏輯與日志統(tǒng)計(jì)
- 透明統(tǒng)一統(tǒng)計(jì)性能數(shù)據(jù)
- 對(duì) Controller、Service 層尤為實(shí)用
其他替代品推薦
除了 Java 原生類,還有一些開源工具類也支持高效計(jì)時(shí):
Guava 的 Stopwatch:
Stopwatch stopwatch = Stopwatch.createStarted();
// 執(zhí)行代碼
stopwatch.stop();
System.out.println("耗時(shí): " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms");
Micrometer 和 Spring Boot Actuator 提供的 @Timed 注解和 Metrics 接入更強(qiáng)大采集工具,如 Prometheus、Grafana。
總結(jié)
在注重性能的后端開發(fā)中,精準(zhǔn)、高效地記錄代碼執(zhí)行時(shí)間是不可或缺的一步。本文從 Java 8 原生的 Instant/Duration 入手,展示了編寫更優(yōu)雅、規(guī)范、可擴(kuò)展的代碼計(jì)時(shí)方式。
| 方法 | 優(yōu)雅度 | 可復(fù)用性 | 推薦度 |
|---|---|---|---|
| System.currentTimeMillis | 一般 | 低 | ? |
| Instant + Duration | 良好 | 中 | ? |
| 工具類封裝 | 高 | 高 | ?? |
| AOP 自動(dòng)化記錄 | 極高 | 極高 | ??? |
到此這篇關(guān)于Java8如何優(yōu)雅的記錄代碼運(yùn)行時(shí)間的文章就介紹到這了,更多相關(guān)Java8記錄代碼運(yùn)行時(shí)間內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解spring-cloud與netflixEureka整合(注冊(cè)中心)
這篇文章主要介紹了詳解spring-cloud與netflixEureka整合(注冊(cè)中心),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
解決Springboot全局異常處理與AOP日志處理中@AfterThrowing失效問題
這篇文章主要介紹了解決Springboot全局異常處理與AOP日志處理中@AfterThrowing失效問題,文中介紹了兩種失效場(chǎng)景,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-05-05
Mybatis提示Tag name expected的問題及解決
MyBatis是一個(gè)開源的Java持久層框架,用于將Java對(duì)象與數(shù)據(jù)庫(kù)表進(jìn)行映射,它提供了一種簡(jiǎn)單、靈活的方式來訪問數(shù)據(jù)庫(kù),同時(shí)也提供了強(qiáng)大的SQL映射和查詢功能2025-01-01
SpringMVC HttpMessageConverter報(bào)文信息轉(zhuǎn)換器
??HttpMessageConverter???,報(bào)文信息轉(zhuǎn)換器,將請(qǐng)求報(bào)文轉(zhuǎn)換為Java對(duì)象,或?qū)ava對(duì)象轉(zhuǎn)換為響應(yīng)報(bào)文。???HttpMessageConverter???提供了兩個(gè)注解和兩個(gè)類型:??@RequestBody,@ResponseBody???,??RequestEntity,ResponseEntity??2023-01-01
SpringBoot整合jnotify實(shí)現(xiàn)針對(duì)指定目錄及其(動(dòng)態(tài))子目錄的監(jiān)聽的方法
本文介紹了JNotify這一Java庫(kù)在SpringBoot中的應(yīng)用,JNotify允許應(yīng)用程序監(jiān)聽文件系統(tǒng)事件,包括文件夾/文件的創(chuàng)建、刪除、修改和重命名,由于JNotify底層調(diào)用的關(guān)鍵部分是C語(yǔ)言開發(fā)的,所以在使用前需要在系統(tǒng)中加入相應(yīng)的動(dòng)態(tài)庫(kù)2024-10-10
Java通過切面實(shí)現(xiàn)統(tǒng)一處理Token設(shè)置用戶信息
這篇文章主要介紹了Java切面統(tǒng)一處理Token設(shè)置用戶信息,常見的后端開發(fā)中,接口請(qǐng)求中一般前端都是先通過用戶登錄獲取token,每次接口請(qǐng)求都需要在頭信息中攜帶token信息,后端每次都需要手動(dòng)處理token信息,從token信息中解析獲取用戶信息,需要的朋友可以參考下2023-10-10
JAVA浮點(diǎn)數(shù)計(jì)算精度損失底層原理與解決方案
本文主要介紹了JAVA浮點(diǎn)數(shù)計(jì)算精度損失底層原理與解決方案。具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-02-02
java開發(fā)中常遇到的各種難點(diǎn)以及解決思路方案
Java項(xiàng)目是一個(gè)復(fù)雜的軟件開發(fā)過程,其中會(huì)涉及到很多技術(shù)難點(diǎn),這篇文章主要給大家介紹了關(guān)于java開發(fā)中常遇到的各種難點(diǎn)以及解決思路方案的相關(guān)資料,需要的朋友可以參考下2023-07-07

