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 accuratelySystem.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
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
-
long start = System.nanoTime();- Java reads the current high-resolution time source.
- Suppose it returns
5000000000.
-
greet();- The method runs.
- It prints
Hello.
-
long end = System.nanoTime();- Java reads the time source again.
- Suppose it now returns
5001200000.
-
long duration = end - start;- Java subtracts the values.
5001200000 - 5000000000 = 1200000- The duration is
1,200,000nanoseconds.
-
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.
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
| Option | Purpose | Good for timing execution? | Notes |
|---|---|---|---|
System.nanoTime() | Measure elapsed time | Yes | Best choice for durations |
System.currentTimeMillis() | Get current wall-clock time | Sometimes | Fine for rough timing, less precise |
java.util.Timer | Schedule future tasks | No | Not for measuring runtime |
Thread.sleep() | Pause a thread | No | Not related to timing a method |
nanoTime() vs currentTimeMillis()
| Feature | System.nanoTime() | System.currentTimeMillis() |
|---|---|---|
| Best use | Measuring elapsed time | Getting current clock time |
| Precision | Higher | Lower |
| Affected by wall-clock changes | No for elapsed comparison | Can be |
| Good for short method timing | Yes | Less ideal |
Simple timing vs proper benchmarking
| Approach | Best for | Limitation |
|---|---|---|
Manual nanoTime() | Quick checks and logging | Can be noisy |
| Repeated test loop | Small comparisons | Still imperfect |
| Dedicated benchmark tool | Accurate performance testing | More setup required |
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/finallyif exceptions may happen - Run multiple times for better estimates
Avoid this
- Do not use
java.util.Timerto 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.
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." ]
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.