Question

How to Measure Method Execution Time in Java

javatimingexecution-time

Question

How can I measure how long a method takes to run in Java?

I want to record a method's execution time and understand whether Java has a built-in utility specifically for timing how long a task takes.

I have found many results about timer classes used for scheduling threads and tasks, but that is not what I need. I want to measure elapsed execution time for code like this:

public void doWork() {
    // method logic here
}

What is the correct way to time this kind of method execution in Java?

Short Answer

By the end of this page, you will understand how to measure elapsed time in Java, when to use System.nanoTime() instead of System.currentTimeMillis(), how to wrap code you want to time, and what mistakes to avoid when doing simple performance measurements.

Concept

Measuring a method's execution time means recording a start time, running the method, then recording an end time and calculating the difference.

In Java, the most common built-in tools are:

  • System.nanoTime() for measuring elapsed time accurately
  • System.currentTimeMillis() for measuring wall-clock time in milliseconds

For timing how long code takes to run, System.nanoTime() is usually the better choice.

Why System.nanoTime() matters

System.nanoTime() is designed for measuring durations. It gives you a high-resolution time source that is appropriate for computing elapsed time between two points.

long start = System.nanoTime();
doWork();
long end = System.nanoTime();
long duration = end - start;

This does not mean the value is the current date or time in nanoseconds. It is only useful for comparing two values to get a duration.

Why not use Timer?

Java's Timer class is for scheduling tasks to run later or repeatedly. It is not intended for measuring how long a method takes.

Why this matters in real programming

Timing code is useful when you want to:

  • compare two implementations
  • find slow methods
  • monitor performance in scripts or services
  • log expensive operations
  • troubleshoot bottlenecks

For casual timing, simple start/end measurements are enough. For serious benchmarking, you need more careful tools and methods because JVM warmup, optimization, and garbage collection can affect results.

Mental Model

Think of method timing like using a stopwatch:

  • press start right before the method runs
  • press stop right after it finishes
  • subtract the two readings

System.nanoTime() is that stopwatch.

A Timer in Java is more like an alarm clock. It helps you schedule something to happen later. It does not tell you how long something just took.

So the key idea is:

  • stopwatch = measure duration
  • alarm clock = schedule future work
Take Quiz

Syntax and Examples

The basic pattern looks like this:

long start = System.nanoTime();

// code to measure
someMethod();

long end = System.nanoTime();
long durationNanos = end - start;

System.out.println("Duration: " + durationNanos + " ns");

Example: timing a method

public class Main {
    public static void main(String[] args) {
        long start = System.nanoTime();

        doWork();

        long end = System.nanoTime();
        long durationNanos = end - start;
        double durationMillis = durationNanos / 1_000_000.0;

        System.out.println("Execution time: " + durationNanos + " ns");
        System.out.println("Execution time: " + durationMillis + " ms");
    }

    public static void doWork() {
        for (int i = 0; i < 1_000_000; i++) {
            Math.sqrt(i);
        }
    }
}

What this does

  • stores the starting time
  • runs doWork()
  • stores the ending time
  • subtracts start from end
  • prints the result in nanoseconds and milliseconds

Using currentTimeMillis()

You can also do this:

long start = System.currentTimeMillis();
doWork();
long end = System.currentTimeMillis();

System.out.println("Execution time: " + (end - start) + " ms");

This is simpler, but it is less suitable for precise duration measurement. Prefer nanoTime() when measuring elapsed execution time.

Step by Step Execution

Consider this example:

public class Main {
    public static void main(String[] args) {
        long start = System.nanoTime();
        greet();
        long end = System.nanoTime();

        long duration = end - start;
        System.out.println(duration);
    }

    public static void greet() {
        System.out.println("Hello");
    }
}

Step by step

  1. long start = System.nanoTime();

    • Java reads the current high-resolution time source.
    • Suppose it returns 5000000000.
  2. greet();

    • The method runs.
    • It prints Hello.
  3. long end = System.nanoTime();

    • Java reads the time source again.
    • Suppose it now returns 5001200000.
  4. long duration = end - start;

    • Java subtracts the values.
    • 5001200000 - 5000000000 = 1200000
    • The duration is 1,200,000 nanoseconds.
  5. System.out.println(duration);

    • Prints the elapsed time.

Converting units

double millis = duration / 1_000_000.0;
double seconds = duration / 1_000_000_000.0;

This is often easier to read than raw nanoseconds.

Real World Use Cases

Here are common places where developers time code in Java:

Logging slow operations

long start = System.nanoTime();
loadUserProfile();
long duration = System.nanoTime() - start;
System.out.println("loadUserProfile took " + duration + " ns");

Useful for:

  • database calls
  • file reading
  • API requests
  • expensive calculations

Comparing two approaches

You may want to compare:

  • loop vs stream
  • one sorting strategy vs another
  • cached result vs recalculated result

Monitoring background jobs

For batch jobs, imports, and report generation, timing helps answer:

  • how long did the whole job take?
  • which step is slow?
  • did the latest change improve performance?

Measuring scripts and command-line tools

If you build a Java tool that processes files or data, timing helps estimate runtime and detect regressions.

Take Quiz

Real Codebase Usage

In real projects, developers rarely scatter raw timing code everywhere. They often use simple patterns that keep code readable.

Pattern: measure around a block of work

long start = System.nanoTime();
processOrder(order);
long elapsed = System.nanoTime() - start;
logger.info("processOrder took {} ns", elapsed);

Pattern: early return still needs careful timing

If a method has guard clauses or early returns, measure around the method call from the outside, or use a try/finally block.

long start = System.nanoTime();
try {
    validateAndSave(user);
} finally {
    long elapsed = System.nanoTime() - start;
    System.out.println("validateAndSave took " + elapsed + " ns");
}

Pattern: validation and error handling

Timing is often combined with validation and exception tracking.

long start = System.nanoTime();
try {
    sendEmail(message);
} catch (Exception e) {
    System.err.println("Email failed: " + e.getMessage());
} finally {
    long elapsed = System.nanoTime() - start;
    System.out.println("sendEmail finished in " + elapsed + " ns");
}

Pattern: helper method for reuse

Teams sometimes create a small utility to reduce repetition.

public static long measure(Runnable task) {
    long start = System.nanoTime();
    task.run();
    return System.nanoTime() - start;
}

Usage:

long elapsed = measure(() -> doWork());
System.out.println("doWork took " + elapsed + " ns");

This keeps timing logic consistent across the codebase.

Common Mistakes

1. Using Timer instead of elapsed-time measurement

Timer schedules tasks. It does not measure method runtime.

Broken idea:

Timer timer = new Timer();

This is the wrong tool for execution timing.

2. Using System.currentTimeMillis() for precise benchmarking

currentTimeMillis() is okay for rough measurements, but it is not ideal for short durations.

Better:

long start = System.nanoTime();
// code
long end = System.nanoTime();

3. Forgetting to subtract start from end

Broken code:

long start = System.nanoTime();
doWork();
System.out.println(System.nanoTime());

This prints a raw time source value, not the duration.

Correct:

long start = System.nanoTime();
doWork();
long duration = System.nanoTime() - start;
System.out.println(duration);

4. Measuring code only once

A single run can be misleading because of:

  • JVM warmup
  • garbage collection
  • other system activity

For more reliable results, run the code multiple times and compare averages.

5. Timing code that includes unrelated work

If your timing includes logging, printing, or setup work, the result may not reflect the method itself.

Example:

long start = System.nanoTime();
System.out.println("Starting");
doWork();
System.out.println("Done");
long end = System.nanoTime();

Printing to the console can be slow. It affects the measurement.

6. Ignoring exceptions

If a method throws an exception, your end time may never be recorded unless you use try/finally.

Correct pattern:

long start = System.nanoTime();
try {
    riskyWork();
} finally {
    long elapsed = System.nanoTime() - start;
    System.out.println(elapsed);
}

Comparisons

OptionPurposeGood for timing execution?Notes
System.nanoTime()Measure elapsed timeYesBest choice for durations
System.currentTimeMillis()Get current wall-clock timeSometimesFine for rough timing, less precise
java.util.TimerSchedule future tasksNoNot for measuring runtime
Thread.sleep()Pause a threadNoNot related to timing a method

nanoTime() vs currentTimeMillis()

FeatureSystem.nanoTime()System.currentTimeMillis()
Best useMeasuring elapsed timeGetting current clock time
PrecisionHigherLower
Affected by wall-clock changesNo for elapsed comparisonCan be
Good for short method timingYesLess ideal

Simple timing vs proper benchmarking

ApproachBest forLimitation
Manual nanoTime()Quick checks and loggingCan be noisy
Repeated test loopSmall comparisonsStill imperfect
Dedicated benchmark toolAccurate performance testingMore setup required
Take Quiz

Cheat Sheet

Quick pattern

long start = System.nanoTime();
methodToMeasure();
long duration = System.nanoTime() - start;

Convert units

double ms = duration / 1_000_000.0;
double sec = duration / 1_000_000_000.0;

Prefer this

  • Use System.nanoTime() for elapsed time
  • Use try/finally if exceptions may happen
  • Run multiple times for better estimates

Avoid this

  • Do not use java.util.Timer to measure method duration
  • Do not rely on one run for serious benchmarking
  • Do not include unrelated console output in the timed section

Reusable helper

public static long measure(Runnable task) {
    long start = System.nanoTime();
    task.run();
    return System.nanoTime() - start;
}

Rule of thumb

  • Need elapsed runtime? nanoTime()
  • Need actual clock time/date? currentTimeMillis() or Java time APIs

FAQ

How do I measure execution time of a method in Java?

Use System.nanoTime() before and after the method call, then subtract the start value from the end value.

Is there a built-in timer utility in Java for measuring method runtime?

There is no special Timer class for this purpose. The standard approach is using System.nanoTime().

Should I use System.currentTimeMillis() or System.nanoTime()?

Use System.nanoTime() for elapsed time measurement. Use currentTimeMillis() only for rough timing or clock-based values.

Why is java.util.Timer not the right tool?

java.util.Timer schedules tasks to run later or repeatedly. It does not measure how long code takes to execute.

Can I measure very fast methods accurately?

You can, but results may be noisy. Run the method many times and compare averages for a more useful measurement.

What if the method throws an exception?

Use a try/finally block so you still record the elapsed time even if the method fails.

Is nanoTime() actually returning the current time in nanoseconds?

No. It returns a high-resolution time source intended for measuring elapsed duration, not the current date or clock time.

Take Quiz

Mini Project

Description

Build a small Java program that measures how long different tasks take to run. This project demonstrates practical elapsed-time measurement using System.nanoTime() and shows how to reuse timing logic for multiple methods.

Goal

Create a reusable method-timing utility and use it to measure at least two different tasks in Java.

Requirements

[ "Create a method that accepts a Runnable and returns the elapsed time.", "Measure the runtime of two different tasks.", "Print the durations in both nanoseconds and milliseconds.", "Use System.nanoTime() for all timing measurements." ]

Take Quiz

Keep learning

Related questions

View more