Java
Code Timing
Method Execution
Programming Techniques
Java Performance Measurement

How do I time a method's execution in Java?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you want a quick, practical timing in Java, use System.nanoTime(). If you want trustworthy benchmark numbers for very fast methods, use JMH instead, because naive timing is easily distorted by JIT warmup, dead-code elimination, and JVM optimizations.

The Simple Timing Pattern

For ordinary profiling during development, wrap the method call with System.nanoTime().

java
1public class TimerExample {
2    static void work() {
3        for (int i = 0; i < 1_000_000; i++) {
4            Math.sqrt(i);
5        }
6    }
7
8    public static void main(String[] args) {
9        long start = System.nanoTime();
10        work();
11        long end = System.nanoTime();
12
13        long elapsedNanos = end - start;
14        System.out.println("Elapsed ns: " + elapsedNanos);
15        System.out.println("Elapsed ms: " + elapsedNanos / 1_000_000.0);
16    }
17}

System.nanoTime() is preferred over System.currentTimeMillis() for elapsed-time measurement because it is designed for monotonic interval timing rather than wall-clock time.

A Reusable Helper

If you need this often, wrap the pattern in a helper method.

java
1public class Timers {
2    public static long time(Runnable action) {
3        long start = System.nanoTime();
4        action.run();
5        return System.nanoTime() - start;
6    }
7
8    public static void main(String[] args) {
9        long nanos = time(() -> {
10            for (int i = 0; i < 1_000_000; i++) {
11                Math.sqrt(i);
12            }
13        });
14
15        System.out.println("Elapsed ns: " + nanos);
16    }
17}

That is enough for logging, smoke-checking performance regressions, or comparing slower application operations.

Why Naive Microbenchmarks Lie

Very short methods are hard to measure correctly on the JVM. The runtime may optimize away work, inline methods, or change performance after warmup.

That means code like this is often misleading:

  • run the method once
  • print one timing number
  • assume the number is stable

For quick diagnostics, repeat the method many times and warm up first. For serious measurement, use JMH.

When to Use JMH

JMH exists specifically to benchmark JVM code correctly. It handles warmup iterations, measurement iterations, forks, and several optimization pitfalls that manual timing does not.

A minimal benchmark looks like this:

java
1import org.openjdk.jmh.annotations.Benchmark;
2
3public class MyBenchmark {
4    @Benchmark
5    public double compute() {
6        return Math.sqrt(12345.6789);
7    }
8}

That example is not a full JMH project setup, but it shows the intended direction: once timing results matter, move from ad hoc code to a benchmarking framework.

Another practical distinction is whether you are measuring one slow operation or a tiny hot method. For code that already takes milliseconds or seconds, a simple nanoTime() wrapper is often enough. For code that runs in microseconds or nanoseconds, framework-based benchmarking becomes much more important.

Timing in Production Code

For production systems, manual timers are rarely the best observability tool. Use metrics libraries, tracing, or APM tooling instead. They provide percentiles, aggregation, and context that a single log line cannot.

So there are really three levels:

  • 'System.nanoTime() for quick local timing'
  • JMH for repeatable benchmarks
  • metrics or tracing for live systems

Common Pitfalls

The biggest mistake is using System.currentTimeMillis() for tiny operations. Its granularity and wall-clock nature make it a worse fit for elapsed timing.

Another mistake is benchmarking code that the JVM can optimize away. If the result is unused, the measurement may not reflect real work.

A third mistake is timing only one run and treating it as stable. JVM warmup changes performance significantly.

Summary

  • Use System.nanoTime() for quick method timing in Java.
  • Wrap the timing pattern in a helper if you do it often.
  • Avoid System.currentTimeMillis() for short elapsed-time measurements.
  • For microbenchmarks, use JMH instead of hand-rolled loops.
  • For production visibility, prefer metrics and tracing over ad hoc timing prints.

Course illustration
Course illustration

All Rights Reserved.