garydgregory commented on code in PR #1473:
URL: https://github.com/apache/commons-lang/pull/1473#discussion_r2463839905
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -626,6 +633,59 @@ public void split() {
splitState = SplitState.SPLIT;
}
+ /**
+ * <p>
+ * Splits the time to track the elapsed time between two consecutive
{@code split()} calls.
+ * The label specified is used to identify each split
+ * </p>
+ *
+ * <p>
+ * After calling {@link #stop()}, we can call {@link #getReport()} to have
a report with all time between each {@code split()} call, example:
+ * </p>
+ *
+ * <pre>
+ * 1 00:14:00.000
+ * 2 00:02:00.000
+ * 3 00:04:00.000
+ * </pre>
+ *
+ * @param label A number to identify this split
+ *
+ * @throws IllegalStateException
+ * if the StopWatch is not running.
+ */
+ public void split(int label) {
+ split(String.valueOf(label));
+ }
+
+ /**
+ * <p>
+ * Splits the time to track the elapsed time between two consecutive
{@code split()} calls.
+ * The label specified is used to identify each split
+ * </p>
+ *
+ * <p>
+ * After calling {@link #stop()}, we can call {@link #getReport()} to have
a report with all time between each {@code split()} call, example:
+ * </p>
+ *
+ * <pre>
+ * Baking cookies 00:14:00.000
+ * Serving 00:02:00.000
+ * Eating 00:04:00.000
+ * </pre>
+ *
+ * @param label A message for string presentation.
+ *
+ * @throws IllegalStateException
+ * if the StopWatch is not running.
+ */
+ public void split(String label) {
Review Comment:
Use final where you can:
```java
public void split(final String label)
```
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -626,6 +633,59 @@ public void split() {
splitState = SplitState.SPLIT;
}
+ /**
+ * <p>
+ * Splits the time to track the elapsed time between two consecutive
{@code split()} calls.
+ * The label specified is used to identify each split
+ * </p>
+ *
+ * <p>
+ * After calling {@link #stop()}, we can call {@link #getReport()} to have
a report with all time between each {@code split()} call, example:
+ * </p>
+ *
+ * <pre>
+ * 1 00:14:00.000
+ * 2 00:02:00.000
+ * 3 00:04:00.000
+ * </pre>
+ *
+ * @param label A number to identify this split
+ *
+ * @throws IllegalStateException
+ * if the StopWatch is not running.
+ */
+ public void split(int label) {
Review Comment:
This feels superfluous in a first cut. It's best to minimize the use of new
APIs initially. If use cases reveal the need for additional convenience methods
later, we can add them later. But once a public or protected API is in, it's in
forever for that major release line. Best to be conservative.
The example in the Javadoc show sequential incrementing values (1, 2, 3).
These are good for default labels and it's what you see (for example) in the
Android stopwatch "Lap" feature.
The concern is what is the relationship of this feature with the existing
`split()` method. They appear to be unrelated which is confusing.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -626,6 +633,59 @@ public void split() {
splitState = SplitState.SPLIT;
}
+ /**
+ * <p>
+ * Splits the time to track the elapsed time between two consecutive
{@code split()} calls.
+ * The label specified is used to identify each split
+ * </p>
+ *
+ * <p>
+ * After calling {@link #stop()}, we can call {@link #getReport()} to have
a report with all time between each {@code split()} call, example:
+ * </p>
+ *
+ * <pre>
+ * 1 00:14:00.000
+ * 2 00:02:00.000
+ * 3 00:04:00.000
+ * </pre>
+ *
+ * @param label A number to identify this split
+ *
+ * @throws IllegalStateException
+ * if the StopWatch is not running.
+ */
+ public void split(int label) {
+ split(String.valueOf(label));
+ }
+
+ /**
+ * <p>
+ * Splits the time to track the elapsed time between two consecutive
{@code split()} calls.
+ * The label specified is used to identify each split
+ * </p>
+ *
+ * <p>
+ * After calling {@link #stop()}, we can call {@link #getReport()} to have
a report with all time between each {@code split()} call, example:
+ * </p>
+ *
+ * <pre>
+ * Baking cookies 00:14:00.000
+ * Serving 00:02:00.000
+ * Eating 00:04:00.000
+ * </pre>
+ *
+ * @param label A message for string presentation.
+ *
+ * @throws IllegalStateException
+ * if the StopWatch is not running.
+ */
Review Comment:
Add missing Javadoc since tag to all new public and protected elements.
##########
src/test/java/org/apache/commons/lang3/time/StopWatchTest.java:
##########
@@ -500,6 +501,117 @@ void testToStringWithMessage() throws
InterruptedException {
assertEquals(SPLIT_CLOCK_STR_LEN + MESSAGE.length() + 1,
splitStr.length(), "Formatted split string not the correct length");
}
+ @Test
+ void testSplitsWithStringLabels() {
+ final StopWatch watch = new StopWatch();
+ final String firstLabel = "one";
+ final String secondLabel = "two";
+ final String thirdLabel = "three";
+ final int firstSleepTime = 400;
+ final int secondSleepTime = 300;
+ final int thirdSleepTime = 200;
+ watch.start();
+ ThreadUtils.sleepQuietly(Duration.ofMillis(100));
Review Comment:
For testing splits, there should be no need to sleep the tests all the time,
which slows down the build.
All that we care about is that the splits are _ordered_ and have a
_reasonable_, non-negative duration. We can have one test that makes sure the
duration of each split is "valid". That test may require a sleep to make sure
it lasted at least 1 nanosecond, but... Note that this minimium sleep will
likely be at least 20 milliseconds due to clock granularity (and that being
different on different OSs).
##########
src/test/java/org/apache/commons/lang3/time/FastDateParser_TimeZoneStrategyTest.java:
##########
@@ -170,6 +170,16 @@ private void
testTimeZoneStrategyPattern_TimeZone_getAvailableIDs(final Locale l
Objects.requireNonNull(locale, "locale");
assumeFalse(LocaleUtils.isLanguageUndetermined(locale), () ->
toFailureMessage(locale, null, null));
assumeTrue(LocaleUtils.isAvailableLocale(locale), () ->
toFailureMessage(locale, null, null));
+ //Only breaks in GitHub in macOS 13 + JDK 25 builds:
Review Comment:
This doesn't belong in this PR.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -746,4 +817,182 @@ public void unsplit() {
splitState = SplitState.UNSPLIT;
}
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using milliseconds)
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits() {
+ return getProcessedSplits(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using nanoseconds)
+ * @return list of splits
+ */
+ public List<Split> getNanoProcessedSplits() {
+ return getProcessedSplits(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits(TimeUnit timeUnit) {
+ stopIfNecessary();
+ processSplits(timeUnit);
+ final List<Split> result = new ArrayList<>(splits);
+
+ // we remove the last split because it's an internal and automatic
split
+ result.remove(result.size() - 1);
+
+ return result;
+ }
+
+ /**
+ * Fill durations (time took) on each split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ */
+ private void processSplits(TimeUnit timeUnit) {
+ // we need at least 2 splits to calculate the elapsed time
+ if (splits.size() < 2) {
+ return;
+ }
+
+ for (int i = 0; i < splits.size() - 1; i++) {
+ final long durationNanos = splits.get(i + 1).getStartNanoTime() -
splits.get(i).getStartNanoTime();
+ final long duration = (timeUnit == TimeUnit.NANOSECONDS)
+ ? durationNanos
+ : TimeUnit.MILLISECONDS.convert(durationNanos,
TimeUnit.NANOSECONDS);
+ splits.get(i).setDuration(duration);
+ }
+
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on milliseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getReport() {
+ return getReport(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on nanoseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getNanoReport() {
+ return getReport(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time between each split
+ * </p>
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return the splits report
+ */
+ private String getReport(TimeUnit timeUnit) {
+ final StringBuilder report = new StringBuilder();
+
+ String duration;
+ for (final Split split : getProcessedSplits(timeUnit)) {
+ report.append(System.lineSeparator());
+ report.append(split.getLabel()).append(StringUtils.SPACE);
+
+ if (timeUnit == TimeUnit.NANOSECONDS) {
+ duration = String.valueOf(split.getDuration());
+ } else {
+ duration =
DurationFormatUtils.formatDurationHMS(split.getDuration());
+ }
+
+ report.append(duration);
+ }
+
+ return report.toString();
+ }
+
+ /**
+ * Class to store details of each split
+ */
+ protected static class Split {
Review Comment:
This design is broken: If this class is `protected`, then it's `public`
methods cannot be accessed outside of this package. If you intend to call
`public` methods on this class, then it must be `public`. This class should
also be `final` for now.
A split should have a `toString()` method that returns `"Split(<label>
<duration>)"`.
Alternatively, this `Split` class can extend `ImmutablePair<String,
Duration>`, which seems simpler.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -746,4 +817,182 @@ public void unsplit() {
splitState = SplitState.UNSPLIT;
}
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using milliseconds)
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits() {
+ return getProcessedSplits(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using nanoseconds)
+ * @return list of splits
+ */
+ public List<Split> getNanoProcessedSplits() {
+ return getProcessedSplits(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits(TimeUnit timeUnit) {
+ stopIfNecessary();
+ processSplits(timeUnit);
+ final List<Split> result = new ArrayList<>(splits);
+
+ // we remove the last split because it's an internal and automatic
split
+ result.remove(result.size() - 1);
+
+ return result;
+ }
+
+ /**
+ * Fill durations (time took) on each split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ */
+ private void processSplits(TimeUnit timeUnit) {
+ // we need at least 2 splits to calculate the elapsed time
+ if (splits.size() < 2) {
+ return;
+ }
+
+ for (int i = 0; i < splits.size() - 1; i++) {
+ final long durationNanos = splits.get(i + 1).getStartNanoTime() -
splits.get(i).getStartNanoTime();
+ final long duration = (timeUnit == TimeUnit.NANOSECONDS)
+ ? durationNanos
+ : TimeUnit.MILLISECONDS.convert(durationNanos,
TimeUnit.NANOSECONDS);
+ splits.get(i).setDuration(duration);
+ }
+
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on milliseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getReport() {
+ return getReport(TimeUnit.MILLISECONDS);
Review Comment:
Remove (see below).
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -746,4 +817,182 @@ public void unsplit() {
splitState = SplitState.UNSPLIT;
}
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using milliseconds)
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits() {
+ return getProcessedSplits(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using nanoseconds)
+ * @return list of splits
+ */
+ public List<Split> getNanoProcessedSplits() {
+ return getProcessedSplits(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits(TimeUnit timeUnit) {
Review Comment:
There is no need for "processing" splits, see other comments.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -626,6 +633,59 @@ public void split() {
splitState = SplitState.SPLIT;
}
+ /**
+ * <p>
+ * Splits the time to track the elapsed time between two consecutive
{@code split()} calls.
+ * The label specified is used to identify each split
+ * </p>
+ *
+ * <p>
+ * After calling {@link #stop()}, we can call {@link #getReport()} to have
a report with all time between each {@code split()} call, example:
+ * </p>
+ *
+ * <pre>
+ * 1 00:14:00.000
+ * 2 00:02:00.000
+ * 3 00:04:00.000
+ * </pre>
+ *
+ * @param label A number to identify this split
+ *
+ * @throws IllegalStateException
+ * if the StopWatch is not running.
+ */
+ public void split(int label) {
+ split(String.valueOf(label));
+ }
+
+ /**
+ * <p>
+ * Splits the time to track the elapsed time between two consecutive
{@code split()} calls.
+ * The label specified is used to identify each split
+ * </p>
+ *
+ * <p>
+ * After calling {@link #stop()}, we can call {@link #getReport()} to have
a report with all time between each {@code split()} call, example:
+ * </p>
+ *
+ * <pre>
+ * Baking cookies 00:14:00.000
+ * Serving 00:02:00.000
+ * Eating 00:04:00.000
+ * </pre>
+ *
+ * @param label A message for string presentation.
+ *
Review Comment:
No blank line between Javadoc tags.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -746,4 +817,182 @@ public void unsplit() {
splitState = SplitState.UNSPLIT;
}
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using milliseconds)
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits() {
+ return getProcessedSplits(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using nanoseconds)
+ * @return list of splits
+ */
+ public List<Split> getNanoProcessedSplits() {
+ return getProcessedSplits(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits(TimeUnit timeUnit) {
+ stopIfNecessary();
+ processSplits(timeUnit);
+ final List<Split> result = new ArrayList<>(splits);
+
+ // we remove the last split because it's an internal and automatic
split
+ result.remove(result.size() - 1);
+
+ return result;
+ }
+
+ /**
+ * Fill durations (time took) on each split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ */
+ private void processSplits(TimeUnit timeUnit) {
Review Comment:
This is all unnecessary if splits are immutable.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -746,4 +817,182 @@ public void unsplit() {
splitState = SplitState.UNSPLIT;
}
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using milliseconds)
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits() {
+ return getProcessedSplits(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using nanoseconds)
+ * @return list of splits
+ */
+ public List<Split> getNanoProcessedSplits() {
+ return getProcessedSplits(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits(TimeUnit timeUnit) {
+ stopIfNecessary();
+ processSplits(timeUnit);
+ final List<Split> result = new ArrayList<>(splits);
+
+ // we remove the last split because it's an internal and automatic
split
+ result.remove(result.size() - 1);
+
+ return result;
+ }
+
+ /**
+ * Fill durations (time took) on each split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ */
+ private void processSplits(TimeUnit timeUnit) {
+ // we need at least 2 splits to calculate the elapsed time
+ if (splits.size() < 2) {
+ return;
+ }
+
+ for (int i = 0; i < splits.size() - 1; i++) {
+ final long durationNanos = splits.get(i + 1).getStartNanoTime() -
splits.get(i).getStartNanoTime();
+ final long duration = (timeUnit == TimeUnit.NANOSECONDS)
+ ? durationNanos
+ : TimeUnit.MILLISECONDS.convert(durationNanos,
TimeUnit.NANOSECONDS);
+ splits.get(i).setDuration(duration);
+ }
+
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on milliseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getReport() {
+ return getReport(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on nanoseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getNanoReport() {
+ return getReport(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time between each split
+ * </p>
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return the splits report
+ */
+ private String getReport(TimeUnit timeUnit) {
+ final StringBuilder report = new StringBuilder();
+
+ String duration;
+ for (final Split split : getProcessedSplits(timeUnit)) {
+ report.append(System.lineSeparator());
+ report.append(split.getLabel()).append(StringUtils.SPACE);
+
+ if (timeUnit == TimeUnit.NANOSECONDS) {
+ duration = String.valueOf(split.getDuration());
+ } else {
+ duration =
DurationFormatUtils.formatDurationHMS(split.getDuration());
+ }
+
+ report.append(duration);
+ }
+
+ return report.toString();
+ }
+
+ /**
+ * Class to store details of each split
+ */
+ protected static class Split {
+
+ /**
+ * The start nano time of this split
+ */
+ private long startNanoTime = System.nanoTime();
+
+ /**
+ * The duration (time took) on this split
+ * This field is filled when user calls getSplits() or tries to print
the splits report
+ */
+ private long duration;
+
+ /*
+ * The label for this split
+ */
+ private String label;
+
+ /**
+ * Constructor with label
+ * @param label Label for this split
+ */
+ public Split(String label) {
+ this.label = label;
+ }
+
+ /**
+ * <p>
+ * Get the timestamp when this split was created
+ * </p>
+ *
+ * @return startNanoTime
+ */
+ public long getStartNanoTime() {
+ return startNanoTime;
+ }
+
+ /**
+ * <p>
+ * Get the label of this split
+ * </p>
+ *
+ * @return label
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Duration of this split
+ * @return duration (time on ms or nano)
+ */
+ public long getDuration() {
+ return duration;
+ }
+
+ /**
+ * Set the duration of this split
+ * @param duration time (on ms or nano)
+ */
+ private void setDuration(long duration) {
Review Comment:
This doesn't make sense to me. Splits should be immutable; once you take
one, the duration is known and immutable, it doesn't even need to be stored, it
can be computed based on the stopwatch start time.
##########
src/test/java/org/apache/commons/lang3/time/StopWatchTest.java:
##########
@@ -500,6 +501,117 @@ void testToStringWithMessage() throws
InterruptedException {
assertEquals(SPLIT_CLOCK_STR_LEN + MESSAGE.length() + 1,
splitStr.length(), "Formatted split string not the correct length");
}
+ @Test
+ void testSplitsWithStringLabels() {
+ final StopWatch watch = new StopWatch();
+ final String firstLabel = "one";
+ final String secondLabel = "two";
+ final String thirdLabel = "three";
+ final int firstSleepTime = 400;
+ final int secondSleepTime = 300;
+ final int thirdSleepTime = 200;
+ watch.start();
+ ThreadUtils.sleepQuietly(Duration.ofMillis(100));
+
+ watch.split(firstLabel);
+ ThreadUtils.sleepQuietly(Duration.ofMillis(firstSleepTime));
+ watch.split(secondLabel);
+ ThreadUtils.sleepQuietly(Duration.ofMillis(secondSleepTime));
+ watch.split(thirdLabel);
+ ThreadUtils.sleepQuietly(Duration.ofMillis(thirdSleepTime));
+
+ final List<StopWatch.Split> splits = watch.getProcessedSplits();
+
+ // check sizes
+ assertEquals(3, splits.size());
+
+ // check labels
+ assertEquals(splits.get(0).getLabel(), firstLabel);
+ assertEquals(splits.get(1).getLabel(), secondLabel);
+ assertEquals(splits.get(2).getLabel(), thirdLabel);
+
+ // check duration
+ final int margin = 200;
+ assertEquals(firstSleepTime, splits.get(0).getDuration(), margin);
+ assertEquals(secondSleepTime, splits.get(1).getDuration(), margin);
+ assertEquals(thirdSleepTime, splits.get(2).getDuration(), margin);
+
+ // check report
+ final String report = watch.getReport();
+ assertTrue(report.contains("one 00:00:00."));
+ assertTrue(report.contains("two 00:00:00."));
+ assertTrue(report.contains("three 00:00:00."));
+ }
+
+ @Test
+ void testSplitsWithIntLabels() {
+ final StopWatch watch = new StopWatch();
+ final int firstLabel = 1;
+ final int secondLabel = 2;
+ final int thirdLabel = 3;
+ final int firstSleepTime = 400;
+ final int secondSleepTime = 300;
+ final int thirdSleepTime = 200;
+ watch.start();
+ ThreadUtils.sleepQuietly(Duration.ofMillis(100));
+
+ watch.split(firstLabel);
+ ThreadUtils.sleepQuietly(Duration.ofMillis(firstSleepTime));
+ watch.split(secondLabel);
+ ThreadUtils.sleepQuietly(Duration.ofMillis(secondSleepTime));
+ watch.split(thirdLabel);
+ ThreadUtils.sleepQuietly(Duration.ofMillis(thirdSleepTime));
+
+ final List<StopWatch.Split> splits = watch.getProcessedSplits();
+
Review Comment:
Remove all these blank lines. If you want to call something out, use an `//
inline comment` like you already do here.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -248,6 +250,11 @@ public static StopWatch createStarted() {
*/
private long stopTimeNanos;
+ /**
+ * The list of splits
Review Comment:
End a sentence with a period; this applies to this whole PR.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -746,4 +817,182 @@ public void unsplit() {
splitState = SplitState.UNSPLIT;
}
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using milliseconds)
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits() {
+ return getProcessedSplits(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using nanoseconds)
+ * @return list of splits
+ */
+ public List<Split> getNanoProcessedSplits() {
+ return getProcessedSplits(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits(TimeUnit timeUnit) {
+ stopIfNecessary();
+ processSplits(timeUnit);
+ final List<Split> result = new ArrayList<>(splits);
+
+ // we remove the last split because it's an internal and automatic
split
+ result.remove(result.size() - 1);
+
+ return result;
+ }
+
+ /**
+ * Fill durations (time took) on each split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ */
+ private void processSplits(TimeUnit timeUnit) {
+ // we need at least 2 splits to calculate the elapsed time
+ if (splits.size() < 2) {
+ return;
+ }
+
+ for (int i = 0; i < splits.size() - 1; i++) {
+ final long durationNanos = splits.get(i + 1).getStartNanoTime() -
splits.get(i).getStartNanoTime();
+ final long duration = (timeUnit == TimeUnit.NANOSECONDS)
+ ? durationNanos
+ : TimeUnit.MILLISECONDS.convert(durationNanos,
TimeUnit.NANOSECONDS);
+ splits.get(i).setDuration(duration);
+ }
+
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on milliseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getReport() {
+ return getReport(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on nanoseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getNanoReport() {
Review Comment:
Remove (see below).
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -746,4 +817,182 @@ public void unsplit() {
splitState = SplitState.UNSPLIT;
}
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using milliseconds)
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits() {
+ return getProcessedSplits(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using nanoseconds)
+ * @return list of splits
+ */
+ public List<Split> getNanoProcessedSplits() {
+ return getProcessedSplits(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits(TimeUnit timeUnit) {
+ stopIfNecessary();
+ processSplits(timeUnit);
+ final List<Split> result = new ArrayList<>(splits);
+
+ // we remove the last split because it's an internal and automatic
split
+ result.remove(result.size() - 1);
+
+ return result;
+ }
+
+ /**
+ * Fill durations (time took) on each split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ */
+ private void processSplits(TimeUnit timeUnit) {
+ // we need at least 2 splits to calculate the elapsed time
+ if (splits.size() < 2) {
+ return;
+ }
+
+ for (int i = 0; i < splits.size() - 1; i++) {
+ final long durationNanos = splits.get(i + 1).getStartNanoTime() -
splits.get(i).getStartNanoTime();
+ final long duration = (timeUnit == TimeUnit.NANOSECONDS)
+ ? durationNanos
+ : TimeUnit.MILLISECONDS.convert(durationNanos,
TimeUnit.NANOSECONDS);
+ splits.get(i).setDuration(duration);
+ }
+
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on milliseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getReport() {
+ return getReport(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on nanoseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getNanoReport() {
+ return getReport(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time between each split
+ * </p>
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return the splits report
+ */
+ private String getReport(TimeUnit timeUnit) {
+ final StringBuilder report = new StringBuilder();
+
+ String duration;
+ for (final Split split : getProcessedSplits(timeUnit)) {
+ report.append(System.lineSeparator());
+ report.append(split.getLabel()).append(StringUtils.SPACE);
+
+ if (timeUnit == TimeUnit.NANOSECONDS) {
+ duration = String.valueOf(split.getDuration());
+ } else {
+ duration =
DurationFormatUtils.formatDurationHMS(split.getDuration());
+ }
+
+ report.append(duration);
+ }
+
+ return report.toString();
+ }
+
+ /**
+ * Class to store details of each split
+ */
+ protected static class Split {
+
+ /**
+ * The start nano time of this split
+ */
+ private long startNanoTime = System.nanoTime();
+
+ /**
+ * The duration (time took) on this split
+ * This field is filled when user calls getSplits() or tries to print
the splits report
+ */
+ private long duration;
+
+ /*
+ * The label for this split
+ */
+ private String label;
+
+ /**
+ * Constructor with label
+ * @param label Label for this split
+ */
+ public Split(String label) {
+ this.label = label;
+ }
+
+ /**
+ * <p>
Review Comment:
The first sentence of a Javadoc doesn't need to be in a paragraph tag (by
convention); this comment applies throughout.
##########
src/main/java/org/apache/commons/lang3/time/StopWatch.java:
##########
@@ -746,4 +817,182 @@ public void unsplit() {
splitState = SplitState.UNSPLIT;
}
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using milliseconds)
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits() {
+ return getProcessedSplits(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split (using nanoseconds)
+ * @return list of splits
+ */
+ public List<Split> getNanoProcessedSplits() {
+ return getProcessedSplits(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Stops the watch and returns the list of splits with duration on each
split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return list of splits
+ */
+ public List<Split> getProcessedSplits(TimeUnit timeUnit) {
+ stopIfNecessary();
+ processSplits(timeUnit);
+ final List<Split> result = new ArrayList<>(splits);
+
+ // we remove the last split because it's an internal and automatic
split
+ result.remove(result.size() - 1);
+
+ return result;
+ }
+
+ /**
+ * Fill durations (time took) on each split
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ */
+ private void processSplits(TimeUnit timeUnit) {
+ // we need at least 2 splits to calculate the elapsed time
+ if (splits.size() < 2) {
+ return;
+ }
+
+ for (int i = 0; i < splits.size() - 1; i++) {
+ final long durationNanos = splits.get(i + 1).getStartNanoTime() -
splits.get(i).getStartNanoTime();
+ final long duration = (timeUnit == TimeUnit.NANOSECONDS)
+ ? durationNanos
+ : TimeUnit.MILLISECONDS.convert(durationNanos,
TimeUnit.NANOSECONDS);
+ splits.get(i).setDuration(duration);
+ }
+
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on milliseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getReport() {
+ return getReport(TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time (on nanoseconds) between each
split
+ * </p>
+ *
+ * @return the splits report
+ */
+ public String getNanoReport() {
+ return getReport(TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * <p>
+ * Stops the watch and returns the splits report.
+ * This report contains the elapsed time between each split
+ * </p>
+ *
+ * @param timeUnit the unit of time, not null. Any value will calculate
with milliseconds precision unless
+ * {@code TimeUnit.NANOSECONDS} is specified.
+ * @return the splits report
+ */
+ private String getReport(TimeUnit timeUnit) {
Review Comment:
Let's leave out any reporting API in this first cut. A simple "report" is
available from a `getSplits().toString()`, see my comment on `Split.toString()`
elsewhere in this PR.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]