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.

Programmer DD
Programmer DD
Programmer DD
Mastering Guava’s Stopwatch: Precise Timing in Java Applications

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
JavaPerformanceguavaTimingStopwatchTicker
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.