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");