Skip to content

Commit 3a15e39

Browse files
author
edelgadoh
committed
Adding labels to split StopWatch feature - refactor based on PR review
1 parent 4fc37db commit 3a15e39

File tree

2 files changed

+67
-292
lines changed

2 files changed

+67
-292
lines changed

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

Lines changed: 50 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.time.Duration;
2121
import java.time.Instant;
2222
import java.util.ArrayList;
23+
import java.util.Collections;
2324
import java.util.List;
2425
import java.util.Objects;
2526
import java.util.concurrent.TimeUnit;
@@ -29,6 +30,7 @@
2930
import org.apache.commons.lang3.function.FailableConsumer;
3031
import org.apache.commons.lang3.function.FailableRunnable;
3132
import org.apache.commons.lang3.function.FailableSupplier;
33+
import org.apache.commons.lang3.math.NumberUtils;
3234

3335
/**
3436
* {@link StopWatch} provides a convenient API for timings.
@@ -251,9 +253,9 @@ public static StopWatch createStarted() {
251253
private long stopTimeNanos;
252254

253255
/**
254-
* The list of splits
256+
* The list of recorded splits.
255257
*/
256-
private List<Split> splits;
258+
private List<Split> recordedSplits;
257259

258260
/**
259261
* Constructs a new instance.
@@ -333,6 +335,16 @@ public String getMessage() {
333335
return message;
334336
}
335337

338+
/**
339+
* Gets the recorded splits.
340+
*
341+
* @return the list of splits.
342+
* @since 3.19.0
343+
*/
344+
public List<Split> getRecordedSplits() {
345+
return Collections.unmodifiableList(recordedSplits);
346+
}
347+
336348
/**
337349
* Gets the <em>elapsed</em> time in nanoseconds.
338350
*
@@ -635,55 +647,20 @@ public void split() {
635647

636648
/**
637649
* <p>
638-
* Splits the time to track the elapsed time between two consecutive {@code split()} calls.
639-
* The label specified is used to identify each split
650+
* Captures the duration (elapsed time of this split vs the last split) and is recorded in a list.
651+
* The label specified is used to identify the current split.
640652
* </p>
641653
*
642-
* <p>
643-
* After calling {@link #stop()}, we can call {@link #getReport()} to have a report with all time between each {@code split()} call, example:
644-
* </p>
645-
*
646-
* <pre>
647-
* 1 00:14:00.000
648-
* 2 00:02:00.000
649-
* 3 00:04:00.000
650-
* </pre>
651-
*
652-
* @param label A number to identify this split
653-
*
654-
* @throws IllegalStateException
655-
* if the StopWatch is not running.
656-
*/
657-
public void split(int label) {
658-
split(String.valueOf(label));
659-
}
660-
661-
/**
662-
* <p>
663-
* Splits the time to track the elapsed time between two consecutive {@code split()} calls.
664-
* The label specified is used to identify each split
665-
* </p>
666-
*
667-
* <p>
668-
* After calling {@link #stop()}, we can call {@link #getReport()} to have a report with all time between each {@code split()} call, example:
669-
* </p>
670-
*
671-
* <pre>
672-
* Baking cookies 00:14:00.000
673-
* Serving 00:02:00.000
674-
* Eating 00:04:00.000
675-
* </pre>
676-
*
677654
* @param label A message for string presentation.
678-
*
679-
* @throws IllegalStateException
680-
* if the StopWatch is not running.
655+
* @throws IllegalStateException if the StopWatch is not running.
656+
* @since 3.19.0
681657
*/
682-
public void split(String label) {
658+
public void recordSplit(final String label) {
683659
if (this.runningState != State.RUNNING) {
684660
throw new IllegalStateException("Stopwatch is not running.");
685661
}
686-
splits.add(new Split(label));
662+
final long duration = System.nanoTime() - recordedSplits.get(recordedSplits.size() - 1).getNanoTime();
663+
recordedSplits.add(new Split(label, duration));
687664
}
688665

689666
/**
@@ -705,7 +682,8 @@ public void start() {
705682
startTimeNanos = System.nanoTime();
706683
startInstant = Instant.now();
707684
runningState = State.RUNNING;
708-
splits = new ArrayList<>();
685+
recordedSplits = new ArrayList<>();
686+
recordedSplits.add(new Split(StringUtils.EMPTY, NumberUtils.LONG_ZERO));
709687
}
710688

711689
/**
@@ -735,20 +713,11 @@ public void stop() {
735713
if (runningState == State.RUNNING) {
736714
stopTimeNanos = System.nanoTime();
737715
stopInstant = Instant.now();
738-
split(StringUtils.EMPTY);
716+
recordSplit(StringUtils.EMPTY);
739717
}
740718
runningState = State.STOPPED;
741719
}
742720

743-
/**
744-
* Stops the watch if necessary
745-
*/
746-
private void stopIfNecessary() {
747-
if (this.runningState == State.RUNNING || this.runningState == State.SUSPENDED) {
748-
stop();
749-
}
750-
}
751-
752721
/**
753722
* Suspends this StopWatch for later resumption.
754723
*
@@ -818,180 +787,67 @@ public void unsplit() {
818787
}
819788

820789
/**
821-
* Stops the watch and returns the list of splits with duration on each split (using milliseconds)
822-
* @return list of splits
790+
* Class to store details of each split.
791+
* @since 3.19.0
823792
*/
824-
public List<Split> getProcessedSplits() {
825-
return getProcessedSplits(TimeUnit.MILLISECONDS);
826-
}
827-
828-
/**
829-
* Stops the watch and returns the list of splits with duration on each split (using nanoseconds)
830-
* @return list of splits
831-
*/
832-
public List<Split> getNanoProcessedSplits() {
833-
return getProcessedSplits(TimeUnit.NANOSECONDS);
834-
}
835-
836-
/**
837-
* Stops the watch and returns the list of splits with duration on each split
838-
*
839-
* @param timeUnit the unit of time, not null. Any value will calculate with milliseconds precision unless
840-
* {@code TimeUnit.NANOSECONDS} is specified.
841-
* @return list of splits
842-
*/
843-
public List<Split> getProcessedSplits(TimeUnit timeUnit) {
844-
stopIfNecessary();
845-
processSplits(timeUnit);
846-
final List<Split> result = new ArrayList<>(splits);
847-
848-
// we remove the last split because it's an internal and automatic split
849-
result.remove(result.size() - 1);
850-
851-
return result;
852-
}
853-
854-
/**
855-
* Fill durations (time took) on each split
856-
*
857-
* @param timeUnit the unit of time, not null. Any value will calculate with milliseconds precision unless
858-
* {@code TimeUnit.NANOSECONDS} is specified.
859-
*/
860-
private void processSplits(TimeUnit timeUnit) {
861-
// we need at least 2 splits to calculate the elapsed time
862-
if (splits.size() < 2) {
863-
return;
864-
}
865-
866-
for (int i = 0; i < splits.size() - 1; i++) {
867-
final long durationNanos = splits.get(i + 1).getStartNanoTime() - splits.get(i).getStartNanoTime();
868-
final long duration = (timeUnit == TimeUnit.NANOSECONDS)
869-
? durationNanos
870-
: TimeUnit.MILLISECONDS.convert(durationNanos, TimeUnit.NANOSECONDS);
871-
splits.get(i).setDuration(duration);
872-
}
873-
874-
}
875-
876-
/**
877-
* <p>
878-
* Stops the watch and returns the splits report.
879-
* This report contains the elapsed time (on milliseconds) between each split
880-
* </p>
881-
*
882-
* @return the splits report
883-
*/
884-
public String getReport() {
885-
return getReport(TimeUnit.MILLISECONDS);
886-
}
887-
888-
/**
889-
* <p>
890-
* Stops the watch and returns the splits report.
891-
* This report contains the elapsed time (on nanoseconds) between each split
892-
* </p>
893-
*
894-
* @return the splits report
895-
*/
896-
public String getNanoReport() {
897-
return getReport(TimeUnit.NANOSECONDS);
898-
}
899-
900-
/**
901-
* <p>
902-
* Stops the watch and returns the splits report.
903-
* This report contains the elapsed time between each split
904-
* </p>
905-
*
906-
* @param timeUnit the unit of time, not null. Any value will calculate with milliseconds precision unless
907-
* {@code TimeUnit.NANOSECONDS} is specified.
908-
* @return the splits report
909-
*/
910-
private String getReport(TimeUnit timeUnit) {
911-
final StringBuilder report = new StringBuilder();
912-
913-
String duration;
914-
for (final Split split : getProcessedSplits(timeUnit)) {
915-
report.append(System.lineSeparator());
916-
report.append(split.getLabel()).append(StringUtils.SPACE);
917-
918-
if (timeUnit == TimeUnit.NANOSECONDS) {
919-
duration = String.valueOf(split.getDuration());
920-
} else {
921-
duration = DurationFormatUtils.formatDurationHMS(split.getDuration());
922-
}
923-
924-
report.append(duration);
925-
}
926-
927-
return report.toString();
928-
}
929-
930-
/**
931-
* Class to store details of each split
932-
*/
933-
protected static class Split {
793+
public static final class Split {
934794

935795
/**
936-
* The start nano time of this split
796+
* The nano time of this split.
937797
*/
938-
private long startNanoTime = System.nanoTime();
798+
private long nanoTime = System.nanoTime();
939799

940800
/**
941-
* The duration (time took) on this split
942-
* This field is filled when user calls getSplits() or tries to print the splits report
801+
* The duration (time took) on this split.
943802
*/
944803
private long duration;
945804

946-
/*
947-
* The label for this split
805+
/**
806+
* The label for this split.
948807
*/
949808
private String label;
950809

951810
/**
952-
* Constructor with label
953-
* @param label Label for this split
811+
* Constructor with label and duration.
812+
* @param label Label for this split.
813+
* @param duration time on nano.
954814
*/
955-
public Split(String label) {
815+
public Split(String label, long duration) {
956816
this.label = label;
817+
this.duration = duration;
957818
}
958819

959820
/**
960-
* <p>
961-
* Get the timestamp when this split was created
962-
* </p>
963-
*
964-
* @return startNanoTime
821+
* Get the nano time of this split.
822+
* @return nano time.
965823
*/
966-
public long getStartNanoTime() {
967-
return startNanoTime;
824+
public long getNanoTime() {
825+
return nanoTime;
968826
}
969827

970828
/**
971-
* <p>
972-
* Get the label of this split
973-
* </p>
974-
*
975-
* @return label
829+
* Get the label of this split.
830+
* @return label.
976831
*/
977832
public String getLabel() {
978833
return label;
979834
}
980835

981836
/**
982-
* Duration of this split
983-
* @return duration (time on ms or nano)
837+
* Duration of this split.
838+
* @return duration time on nano.
984839
*/
985840
public long getDuration() {
986841
return duration;
987842
}
988843

989844
/**
990-
* Set the duration of this split
991-
* @param duration time (on ms or nano)
845+
* Converts this instance to a handy string.
846+
* @return this instance as a string.
992847
*/
993-
private void setDuration(long duration) {
994-
this.duration = duration;
848+
@Override
849+
public String toString() {
850+
return String.format("Split [label=%s, duration=%d])", getLabel(), getDuration());
995851
}
996852
}
997853

0 commit comments

Comments
 (0)