Introduction
A lot of times we want to measure how long something took, like measuring the time it takes to complete a network API call. Or we might want to know how long it took to write something to disk. Though these may not give us accurate numbers, we are interested in the approximate time it took to perform something or a sequence of operations.
We normally get the current time in milliseconds or nanoseconds before and after the event and subtract them to find the elapsed time. If you realize, this is like using a Stopwatch. But unfortunately the java library does not offer a stopwatch. Let us look at a couple of good Stopwatch implementations offered by Google Guava and Apache Commons Lang for measuring elapsed time in Java.
Using a Stopwatch to measure performance of code? - Stop there!
If you are looking to use a Stopwatch approach to measure how good a code is and to measure its performance, you are doing it wrong. To learn more refer to the below posts.
The right way to measure the execution time of a code say to compare multiple pieces of code to find which one is efficient is to use the Java Microbenchmark Harness.
The usual way of measuring elapsed time
long start = System.nanoTime();
doSomething();
long end = System.nanoTime();
System.out.println("Took " + (end - start));
The above shows the usual way to measure the elapsed time or execution time in Java. But this is not flexible as using a Stopwatch. A stopwatch is a timer that gives us ability to stop, start and reset.
Google Guava Stopwatch - Creation
Google Guava offers a stopwatch class to measure time. It has two methods to create a stopwatch - one that creates a stopwatch instance in running state and the other just creates a stopwatch object without starting it.
Stopwatch stopwatch = Stopwatch.createStarted();
The above returns a stopwatch while in a running state.
Stopwatch stopwatch = Stopwatch.create();
Calling the create() method creates a stopwatch that is not started yet.
Google Guava Stopwatch - Measuring elapsed time
We call the elapsed time passing the time unit to get the time elapsed.
Stopwatch stopwatch = Stopwatch.createStarted();
Thread.sleep(100);
System.out.println(stopwatch.elapsed(TimeUnit.MILLISECONDS));
The above would print a number little over 100. This applies to all the measurements shown here, as none of them can provide an accurate measurement. Even Thread.sleep’s accuracy depends on thread schedulers and a lot of other factors.
However, the preferred method to get the elapsed time is to use the elapsed() method which returns a Duration object. The Duration object belongs to java.time package.
Duration elapsed = stopwatch.elapsed();
System.out.println(elapsed.toMillis());
Once we have a Duration instance, we can do a lot of things by using the methods on it (You can explore the methods on a Duration class).
Starting, Stopping and Resetting a Google Guava Stopwatch
If the stopwatch was created by calling the create() method or is in a stopped state, we can start it by calling the start() method. To stop a stopwatch, call the stop() method.
Until you start a stopwatch, it will not measure the time elapsed.
Stopwatch stopwatch = Stopwatch.createUnstarted();
Thread.sleep(100);
stopwatch.start();
Thread.sleep(100);
System.out.println(stopwatch.elapsed(TimeUnit.MILLISECONDS));
In the above code, the stopwatch will not consider the first sleep call’s execution time as the stopwatch was started only after it (at line 3). Hence, the output will only include the last sleep’s execution time.
System.out.println(stopwatch.isRunning());//true
stopwatch.stop();
System.out.println(stopwatch.isRunning());//false
The stopwatch’s isRunning method returns true if the stopwatch is still running. We can call the elapsed() method even if the stopwatch is stopped (calling elapsed over and over will keep returning the same value once the stopwatch is stopped).
Now if we start the stopwatch, it will start counting, adding to the already elapsed time. If we want to start over, call the reset() method which will reset the stopwatch’s elapsed time count to 0 and stops the stopwatch.
stopwatch.reset();
stopwatch.start();
Thread.sleep(100);
System.out.println(stopwatch.elapsed(TimeUnit.MILLISECONDS));
The methods start() and stop() must be called only once at a time. If we call back to back (consecutive) start() or stop() it throws an IllegalStateException. In other words, we cannot start a stopwatch that is already running and vice versa for stopping.
Guava Stopwatch’s toString
The toString method provides a friendly representation of the time elapsed
System.out.println(stopwatch.toString());
or simply
System.out.println(stopwatch);
Prints like,
100.8 ms
Apache Commons Lang Stopwatch
We have looked at the Google Guava’s stopwatch class. Let us look at the Stopwatch class from the Apache Commons Lang.
Similar to the Google Guava stopwatch, we can create a Apache Commons Lang Stopwatch in started state or in stopped state. Incidentally, the method names are the same as in Google Guava’s - createStarted() and create()
To get the time elapsed, there are two methods - getTime and formatTime. The getTime returns the time on the stopwatch in milliseconds and the formatTime returns the same time as formatted by DurationFormatUtils#formatDurationHMS i.e., in HH:mm:ss.SSS format.
Stopwatch stopWatch = StopWatch.createStarted();
Thread.sleep(100);
System.out.println(stopWatch.getTime());
System.out.println(stopWatch.formatTime());
This outputs like,
102
00:00:00.102
As I said earlier, the exact time might vary upto a few milliseconds over 100.
Splitting and Unsplitting a Apache Commons Lang Stopwatch
An Apache Commons Lang stopwatch has an additional method called split which is not available in the Google Guava Stopwatch. A split sets the stop time of the watch and allows us to extract the time the split was called. Calling split does not cause the start time to be affected, and the stopwatch continues as usual.
StopWatch stopWatch = StopWatch.createStarted();
Thread.sleep(100);
stopWatch.split();
Thread.sleep(100);
System.out.println(stopWatch.getTime());
System.out.println(stopWatch.getSplitTime());
System.out.println(stopWatch.formatTime());
System.out.println(stopWatch.formatSplitTime());
The above gives an output like,
211
103
00:00:00.212
00:00:00.103
The split time is the time elapsed after the first sleep. The getTime() returns the time when the method was called. This shows that the stopwatch is still running, and it enables us to get the split time at any time afterwards.
The getSplitTime() and formatSplitTime()’s output format is similar to getTime() and formatTime().
The getSplitTime() returns the time between start and latest split. So, if we call split twice, it returns the time elapsed from the start of the stopwatch and the 2nd split.
It also offers an unsplit() method to remove the split (clears the stop time). Calling getSplitTime() or formatSplitTime() when we haven’t called split() or called unsplit() will throw an IllegalStateException.
Starting, Stopping and Resetting a Apache Commons Lang Stopwatch
These methods behave the same way as we have seen earlier.
StopWatch stopWatch = StopWatch.create();
Thread.sleep(100);
stopWatch.start(); //The above sleep not considered
Thread.sleep(100);
stopWatch.stop();
System.out.println(stopWatch.getTime()); // 104
stopWatch.reset();
stopWatch.start();
Thread.sleep(100);
System.out.println(stopWatch.getTime());// 103
stopWatch.stop();
In the above example, we start the stopwatch, stop it, reset it and start it again.
Pausing and resuming a Apache Commons Lang Stopwatch
These are two useful methods not present in the Google Guava stopwatch. The suspend() method pauses the stopwatch and resume() resumes it.
StopWatch stopWatch = StopWatch.createStarted();
Thread.sleep(100);
stopWatch.suspend();
Thread.sleep(100);// This time will not be included as the stopwatch is suspended
stopWatch.resume();
Thread.sleep(50);
System.out.println(stopWatch.getTime()); // 157
The above will print some number in the 150s.
Apache Commons Lang Stopwatch status methods
There are three methods to find if a stopwatch is started, stopped or suspended.
System.out.println(stopWatch.isStarted());
System.out.println(stopWatch.isStopped());
System.out.println(stopWatch.isSuspended());
Apache Commons Lang Stopwatch’s toString
The toString() and toSplitString() method returns the stopwatch time and the split time in ISO 8601-like format i.e., has an hour, minute, seconds and milliseconds.
If we have provided our stopwatch a name when we created it, it adds the name of the stopwatch to this message.
A thing to note here is that to create a stopwatch with a name, we have to use the one-argument constructor that takes a String (name). But it will always create the stopwatch in a stopped state.
StopWatch stopWatch = new StopWatch("my stopwatch");
stopWatch.start(); //Have to start it
Thread.sleep(100);
stopWatch.split();
Thread.sleep(100);
System.out.println(stopWatch.toString());
System.out.println(stopWatch.toSplitString());
It prints like,
my stopwatch 00:00:00.205
my stopwatch 00:00:00.102
Conclusion
This post started with the need for measuring elapsed time in Java. We learnt that using a Stopwatch would be the easiest way to measure elapsed time. We looked at two Stopwatch classes from Google Guava and the Apache Commons Lang. The Apache Commons Lang’s Stopwatch has more functionalities when compared with the Google Guava’s. Pick the one that suits your need.
You can find the other posts on Google Guava utilities here - https://javadevcentral.com/categories/google-guava