diff --git a/src/main/java/org/apache/commons/lang3/time/StopWatch.java b/src/main/java/org/apache/commons/lang3/time/StopWatch.java index d9d4137334e..0ee511e529c 100644 --- a/src/main/java/org/apache/commons/lang3/time/StopWatch.java +++ b/src/main/java/org/apache/commons/lang3/time/StopWatch.java @@ -619,11 +619,14 @@ private long nanosToMillis(final long nanos) { *

* This method clears the internal values to allow the object to be reused. *

+ * + * @return this StopWatch. */ - public void reset() { + public StopWatch reset() { runningState = State.UNSTARTED; splitState = SplitState.UNSPLIT; splits.clear(); + return this; } /** @@ -633,14 +636,16 @@ public void reset() { * This method resumes the watch after it was suspended. The watch will not include time between the suspend and resume calls in the total time. *

* + * @return this StopWatch. * @throws IllegalStateException if this StopWatch has not been suspended. */ - public void resume() { + public StopWatch resume() { if (runningState != State.SUSPENDED) { throw new IllegalStateException("Stopwatch must be suspended to resume."); } startTimeNanos += System.nanoTime() - stopTimeNanos; runningState = State.RUNNING; + return this; } /** @@ -683,15 +688,17 @@ public void runT(final FailableRunnable runnable) throw * timing from the original start point. *

* + * @return this StopWatch. * @throws IllegalStateException if this StopWatch is not running. */ - public void split() { + public StopWatch split() { if (runningState != State.RUNNING) { throw new IllegalStateException("Stopwatch is not running."); } stopSet(); splitState = SplitState.SPLIT; splits.add(new Split(String.valueOf(splits.size()), Duration.ofNanos(stopTimeNanos - startTimeNanos))); + return this; } /** @@ -702,17 +709,19 @@ public void split() { * timing from the original start point. *

* + * @return this StopWatch. * @param label A message for string presentation. * @throws IllegalStateException if the StopWatch is not running. * @since 3.20.0 */ - public void split(final String label) { + public StopWatch split(final String label) { if (runningState != State.RUNNING) { throw new IllegalStateException("Stopwatch is not running."); } stopSet(); splitState = SplitState.SPLIT; splits.add(new Split(label, Duration.ofNanos(stopTimeNanos - startTimeNanos))); + return this; } /** @@ -722,9 +731,10 @@ public void split(final String label) { * This method starts a new timing session, clearing any previous values. *

* + * @return this StopWatch. * @throws IllegalStateException if this StopWatch is already running. */ - public void start() { + public StopWatch start() { if (runningState == State.STOPPED) { throw new IllegalStateException("Stopwatch must be reset before being restarted."); } @@ -735,6 +745,7 @@ public void start() { startInstant = Instant.now(); runningState = State.RUNNING; splits.clear(); + return this; } /** @@ -755,9 +766,10 @@ private void startResume() { * This method ends a new timing session, allowing the time to be retrieved. *

* + * @return this StopWatch. * @throws IllegalStateException if this StopWatch is not running. */ - public void stop() { + public StopWatch stop() { if (runningState != State.RUNNING && runningState != State.SUSPENDED) { throw new IllegalStateException("Stopwatch is not running."); } @@ -765,8 +777,12 @@ public void stop() { stopSet(); } runningState = State.STOPPED; + return this; } + /** + * Sets the stop time. + */ private void stopSet() { stopTimeNanos = System.nanoTime(); stopInstant = Instant.now(); @@ -779,14 +795,16 @@ private void stopSet() { * This method suspends the watch until it is resumed. The watch will not include time between the suspend and resume calls in the total time. *

* + * @return this StopWatch. * @throws IllegalStateException if this StopWatch is not currently running. */ - public void suspend() { + public StopWatch suspend() { if (runningState != State.RUNNING) { throw new IllegalStateException("Stopwatch must be running to suspend."); } stopSet(); runningState = State.SUSPENDED; + return this; } /** @@ -830,13 +848,15 @@ public String toString() { * This method clears the stop time. The start time is unaffected, enabling timing from the original start point to continue. *

* + * @return this StopWatch. * @throws IllegalStateException if this StopWatch has not been split. */ - public void unsplit() { + public StopWatch unsplit() { if (splitState != SplitState.SPLIT) { throw new IllegalStateException("Stopwatch has not been split."); } splitState = SplitState.UNSPLIT; splits.remove(splits.size() - 1); + return this; } } diff --git a/src/test/java/org/apache/commons/lang3/time/StopWatchTest.java b/src/test/java/org/apache/commons/lang3/time/StopWatchTest.java index 01abeaf54d3..1f54d122385 100644 --- a/src/test/java/org/apache/commons/lang3/time/StopWatchTest.java +++ b/src/test/java/org/apache/commons/lang3/time/StopWatchTest.java @@ -555,7 +555,6 @@ void testToSplitStringWithMessage() throws InterruptedException { @Test void testToString() throws InterruptedException { - // final StopWatch watch = StopWatch.createStarted(); sleepPlus1(MIN_DURATION); watch.split(); @@ -574,6 +573,29 @@ void testToStringWithMessage() throws InterruptedException { final String splitStr = watch.toString(); assertEquals(SPLIT_CLOCK_STR_LEN + MESSAGE.length() + 1, splitStr.length(), "Formatted split string not the correct length"); } + + @Test + void testFluentPattern() { + final StopWatch watch = StopWatch.createStarted() + .split() + .stop(); + assertTrue(watch.isStopped()); + watch + .reset() + .start() + .split() + .suspend(); + assertTrue(watch.isSuspended()); + watch + .resume() + .split(); + assertTrue(watch.isStarted()); + assertTrue(watch + .split() + .stop() + .formatTime().startsWith(ZERO_HOURS_PREFIX)); + assertTrue(watch.isStopped()); + } private int throwIOException() throws IOException { throw new IOException("A");