2020import java .time .Duration ;
2121import java .time .Instant ;
2222import java .util .ArrayList ;
23+ import java .util .Collections ;
2324import java .util .List ;
2425import java .util .Objects ;
2526import java .util .concurrent .TimeUnit ;
2930import org .apache .commons .lang3 .function .FailableConsumer ;
3031import org .apache .commons .lang3 .function .FailableRunnable ;
3132import 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