Mastering Guava’s Stopwatch: Precise Timing in Java Applications
An in‑depth guide explains Guava’s Stopwatch utility, showing how to create, start, stop, and reset timers, customize the time source via Ticker, compare it with raw System.nanoTime or System.currentTimeMillis, and highlights its advantages for accurate performance measurement in Java and Android projects.
Stopwatch is a timer (also called a stop‑watch) that records elapsed time.
# How to Use
Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
stopwatch.stop(); // optional
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch);Android usage example:
Stopwatch.createStarted(new Ticker() {
public long read() {
return android.os.SystemClock.elapsedRealtime();
}
});It is possible to measure execution time with plain System.currentTimeMillis, but Stopwatch provides a richer API and abstraction.
long startTime = System.currentTimeMillis();
try {
// simulate business logic
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() - startTime);Guava recommends not using System.nanoTime directly for several reasons:
Time source can be replaced by providing a custom Ticker.
nanoTime returns raw nanoseconds without a meaningful unit; Stopwatch abstracts the result.
# Source Code Analysis
Key member variables
private final Ticker ticker;
private boolean isRunning;
private long elapsedNanos;
private long startTick;Ticker abstract class
public static Ticker systemTicker() {
return SYSTEM_TICKER;
}
private static final Ticker SYSTEM_TICKER = new Ticker() {
@Override
public long read() {
// actually System.nanoTime();
return Platform.systemNanoTime();
}
};
// Subclasses can override read()Construction methods
public static Stopwatch createUnstarted() {
return new Stopwatch();
}
public static Stopwatch createUnstarted(Ticker ticker) {
return new Stopwatch(ticker);
}
public static Stopwatch createStarted() {
return new Stopwatch().start();
}
Stopwatch() {
this.ticker = Ticker.systemTicker();
}
Stopwatch(Ticker ticker) {
this.ticker = checkNotNull(ticker, "ticker");
}Execution flow
public Stopwatch start() {
checkState(!isRunning, "This stopwatch is already running.");
isRunning = true;
startTick = ticker.read();
return this;
}
public Stopwatch stop() {
long tick = ticker.read();
checkState(isRunning, "This stopwatch is already stopped.");
isRunning = false;
elapsedNanos += tick - startTick;
return this;
}
public Stopwatch reset() {
elapsedNanos = 0;
isRunning = false;
return this;
}Retrieving results
private long elapsedNanos() {
return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
}
public long elapsed(TimeUnit desiredUnit) {
return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
}# Summary
Supports TimeUnit for converting elapsed time to various units (e.g., seconds).
A single Stopwatch instance can be reset and reused for multiple measurements.
The time source is replaceable; developers can provide a custom Ticker.
Spring’s StopWatch is similar but does not allow custom time sources and cannot be reset, though it supports milliseconds and nanoseconds and adds a task concept.
Source: https://my.oschina.net/lowkeysoft/blog/1595755
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
