One‑Line Java Time Tracker: Millisecond Precision and Up to 300% Faster Performance
The article shows how to replace repetitive System.currentTimeMillis() timing code with a concise TimeTracker utility that leverages try‑with‑resources, functional interfaces, and flexible exception handling to achieve millisecond‑level measurement and dramatically improve code readability and performance.
Problem
Typical timing code repeats the pattern:
long start = System.currentTimeMillis();
try {
// business logic
} finally {
// calculate elapsed time
}This boilerplate is verbose and easy to forget.
Evolution: embracing try-with-resources
Implementing AutoCloseable allows a TimeTracker to record the start time in its constructor and compute the elapsed time in close(). Usage becomes:
try (TimeTracker ignored = new TimeTracker("Database operation")) {
// business code, timing handled automatically
}The resource is closed automatically and the duration is printed.
Pro: functional interface
Static helper methods accept functional interfaces so the caller can avoid an explicit try block.
TimeTracker.track("User query", () -> userService.findById(123));For methods that return a value:
String result = TimeTracker.track("Simple task", () -> {
Thread.sleep(1000);
return "Done";
});Pro Max: exception handling
The basic track method catches any exception and re‑throws it as a RuntimeException:
public static <T> T track(String operationName, ThrowableSupplier<T> execution) {
try {
return trackThrows(operationName, execution);
} catch (Exception e) {
throw new RuntimeException("Execution failed: " + operationName, e);
}
}When the caller needs to preserve the original exception, trackThrows is provided:
try {
TimeTracker.trackThrows("Operation", () -> riskyMethod());
} catch (SpecificException e) {
// precise handling
}Complete implementation
The TimeTracker class includes:
Fields: operationName, startTime (nanoseconds), logEnabled.
Constructor records System.nanoTime() and optionally prints a start message.
Static factory of(String operationName) returns a new instance.
Four tracking methods: track(String, ThrowableSupplier<T>) – wraps exceptions. trackThrows(String, ThrowableSupplier<T>) – propagates exceptions. track(String, ThrowableRunnable) – void version with wrapping. trackThrows(String, ThrowableRunnable) – void version with propagation.
Implementation of close() computes elapsed time as (System.nanoTime() - startTime) / 1_000_000 and prints "%s execution completed, elapsed: %d ms" when logging is enabled.
Two functional interfaces:
@FunctionalInterface
public interface ThrowableSupplier<T> {
T get() throws Exception;
}
@FunctionalInterface
public interface ThrowableRunnable {
void run() throws Exception;
}Demo usage
A TimeTrackerDemo class illustrates typical scenarios:
Simple task with automatic exception wrapping:
TimeTracker.track("Simple task", () -> {
Thread.sleep(1000);
return "Done";
});Task that may throw a checked exception using trackThrows:
try {
TimeTracker.trackThrows("Potentially failing task", () -> {
if (Math.random() < 0.5) {
throw new IOException("Simulated IO error");
}
return "Success";
});
} catch (Exception e) {
e.printStackTrace();
}Nested tracking of sub‑tasks:
TimeTracker.trackThrows("Complex flow", () -> {
TimeTracker.track("Subtask 1", () -> Thread.sleep(500));
return TimeTracker.trackThrows("Subtask 2", () -> {
Thread.sleep(500);
return "All done";
});
});Try‑with‑resources example:
try (TimeTracker tracker = TimeTracker.of("Resource demo")) {
performResourceIntensiveTask();
}Multiple resources in a single try statement:
try (
TimeTracker t1 = TimeTracker.of("Stage 1");
TimeTracker t2 = TimeTracker.of("Stage 2");
CustomResource r = acquireResource()
) {
processResourcesSequentially(r);
} catch (Exception e) {
e.printStackTrace();
}Ignoring return values for background tasks:
try (TimeTracker ignored = TimeTracker.of("Background task")) {
performBackgroundTask();
}Improvement suggestions (technical)
Integrate a logging framework such as SLF4J to replace System.out.printf for flexible output.
Collect additional statistics (max, min, average) across multiple invocations.
Expose performance metrics via JMX or Micrometer for external monitoring.
Add asynchronous support so that timing can be applied to CompletableFuture pipelines.
java1234
Former senior programmer at a Fortune Global 500 company, dedicated to sharing Java expertise. Visit Feng's site: Java Knowledge Sharing, www.java1234.com
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
