Skip to content

Commit 9df5701

Browse files
author
edelgadoh
committed
Adding labels to split StopWatch feature
1 parent 7d14157 commit 9df5701

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

src/main/java/org/apache/commons/lang3/time/StopWatch.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
import java.time.Duration;
2121
import java.time.Instant;
22+
import java.util.ArrayList;
23+
import java.util.Collections;
24+
import java.util.List;
2225
import java.util.Objects;
2326
import java.util.concurrent.TimeUnit;
2427
import java.util.function.Supplier;
@@ -27,6 +30,8 @@
2730
import org.apache.commons.lang3.function.FailableConsumer;
2831
import org.apache.commons.lang3.function.FailableRunnable;
2932
import org.apache.commons.lang3.function.FailableSupplier;
33+
import org.apache.commons.lang3.math.NumberUtils;
34+
import org.apache.commons.lang3.tuple.ImmutablePair;
3035

3136
/**
3237
* {@link StopWatch} provides a convenient API for timings.
@@ -248,6 +253,11 @@ public static StopWatch createStarted() {
248253
*/
249254
private long stopTimeNanos;
250255

256+
/**
257+
* The split history list.
258+
*/
259+
private List<Split> splitHistory;
260+
251261
/**
252262
* Constructs a new instance.
253263
*/
@@ -326,6 +336,16 @@ public String getMessage() {
326336
return message;
327337
}
328338

339+
/**
340+
* Gets the split history list.
341+
*
342+
* @return the list of splits.
343+
* @since 3.19.0
344+
*/
345+
public List<Split> getSplitHistory() {
346+
return Collections.unmodifiableList(splitHistory);
347+
}
348+
329349
/**
330350
* Gets the <em>elapsed</em> time in nanoseconds.
331351
*
@@ -557,6 +577,7 @@ private long nanosToMillis(final long nanos) {
557577
public void reset() {
558578
runningState = State.UNSTARTED;
559579
splitState = SplitState.UNSPLIT;
580+
splitHistory = new ArrayList<>();
560581
}
561582

562583
/**
@@ -626,6 +647,22 @@ public void split() {
626647
splitState = SplitState.SPLIT;
627648
}
628649

650+
/**
651+
* <p>
652+
* Captures the duration (elapsed time of this split vs the last split) and is recorded in a list.
653+
* The label specified is used to identify the current split.
654+
* </p>
655+
*
656+
* @param label A message for string presentation.
657+
* @throws IllegalStateException if the StopWatch is not running.
658+
* @since 3.19.0
659+
*/
660+
public void addSplitHistory(final String label) {
661+
split();
662+
final long duration = System.nanoTime() - splitHistory.get(splitHistory.size() - 1).getDuration().getNano();
663+
splitHistory.add(new Split(label, Duration.ofNanos(duration)));
664+
}
665+
629666
/**
630667
* Starts this StopWatch.
631668
*
@@ -645,6 +682,8 @@ public void start() {
645682
startTimeNanos = System.nanoTime();
646683
startInstant = Instant.now();
647684
runningState = State.RUNNING;
685+
splitHistory = new ArrayList<>();
686+
splitHistory.add(new Split(StringUtils.EMPTY, Duration.ofNanos(NumberUtils.LONG_ZERO)));
648687
}
649688

650689
/**
@@ -674,6 +713,7 @@ public void stop() {
674713
if (runningState == State.RUNNING) {
675714
stopTimeNanos = System.nanoTime();
676715
stopInstant = Instant.now();
716+
addSplitHistory(StringUtils.EMPTY);
677717
}
678718
runningState = State.STOPPED;
679719
}
@@ -746,4 +786,45 @@ public void unsplit() {
746786
splitState = SplitState.UNSPLIT;
747787
}
748788

789+
/**
790+
* Class to store details of each split.
791+
* @since 3.19.0
792+
*/
793+
public static final class Split extends ImmutablePair<String, Duration> {
794+
795+
/**
796+
* Constructor with label and duration.
797+
* @param label Label for this split.
798+
* @param duration Duration of the split.
799+
*/
800+
public Split(String label, Duration duration) {
801+
super(label, duration);
802+
}
803+
804+
/**
805+
* Get the label of this split.
806+
* @return label.
807+
*/
808+
public String getLabel() {
809+
return getLeft();
810+
}
811+
812+
/**
813+
* Duration of this split.
814+
* @return duration.
815+
*/
816+
public Duration getDuration() {
817+
return getRight();
818+
}
819+
820+
/**
821+
* Converts this instance to a handy string.
822+
* @return this instance as a string.
823+
*/
824+
@Override
825+
public String toString() {
826+
return String.format("Split [label=%s, duration=%s])", getLabel(), getDuration());
827+
}
828+
}
829+
749830
}

src/test/java/org/apache/commons/lang3/time/StopWatchTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@
2626
import java.io.IOException;
2727
import java.time.Duration;
2828
import java.time.Instant;
29+
import java.util.List;
2930
import java.util.concurrent.TimeUnit;
3031
import java.util.concurrent.atomic.AtomicInteger;
3132

3233
import org.apache.commons.lang3.AbstractLangTest;
34+
import org.apache.commons.lang3.StringUtils;
3335
import org.apache.commons.lang3.ThreadUtils;
36+
import org.apache.commons.lang3.math.NumberUtils;
3437
import org.apache.commons.lang3.reflect.FieldUtils;
3538
import org.junit.jupiter.api.RepeatedTest;
3639
import org.junit.jupiter.api.Test;
@@ -500,6 +503,36 @@ void testToStringWithMessage() throws InterruptedException {
500503
assertEquals(SPLIT_CLOCK_STR_LEN + MESSAGE.length() + 1, splitStr.length(), "Formatted split string not the correct length");
501504
}
502505

506+
@Test
507+
void testSplitsWithStringLabels() {
508+
final StopWatch watch = new StopWatch();
509+
final String firstLabel = "one";
510+
final String secondLabel = "two";
511+
final String thirdLabel = "three";
512+
watch.start();
513+
// starting splits
514+
watch.addSplitHistory(firstLabel);
515+
watch.addSplitHistory(secondLabel);
516+
watch.addSplitHistory(thirdLabel);
517+
watch.stop();
518+
// getting splits
519+
final List<StopWatch.Split> splits = watch.getSplitHistory();
520+
// check sizes
521+
assertEquals(5, splits.size());
522+
// check labels
523+
assertEquals(StringUtils.EMPTY, splits.get(0).getLabel());
524+
assertEquals(firstLabel, splits.get(1).getLabel());
525+
assertEquals(secondLabel, splits.get(2).getLabel());
526+
assertEquals(thirdLabel, splits.get(3).getLabel());
527+
assertEquals(StringUtils.EMPTY, splits.get(4).getLabel());
528+
// check duration
529+
assertEquals(NumberUtils.LONG_ZERO, splits.get(0).getDuration().getNano());
530+
assertTrue(splits.get(1).getDuration().getNano() > 0);
531+
assertTrue(splits.get(2).getDuration().getNano() > 0);
532+
assertTrue(splits.get(3).getDuration().getNano() > 0);
533+
assertTrue(splits.get(4).getDuration().getNano() > 0);
534+
}
535+
503536
private int throwIOException() throws IOException {
504537
throw new IOException("A");
505538
}

0 commit comments

Comments
 (0)