Coverage Report - org.apache.commons.lang3.time.StopWatch
 
Classes in this File Line Coverage Branch Coverage Complexity
StopWatch
98%
56/57
96%
29/30
2.867
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  * 
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  * 
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.commons.lang3.time;
 19  
 
 20  
 /**
 21  
  * <p>
 22  
  * <code>StopWatch</code> provides a convenient API for timings.
 23  
  * </p>
 24  
  * 
 25  
  * <p>
 26  
  * To start the watch, call {@link #start()}. At this point you can:
 27  
  * </p>
 28  
  * <ul>
 29  
  * <li>{@link #split()} the watch to get the time whilst the watch continues in the background. {@link #unsplit()} will
 30  
  * remove the effect of the split. At this point, these three options are available again.</li>
 31  
  * <li>{@link #suspend()} the watch to pause it. {@link #resume()} allows the watch to continue. Any time between the
 32  
  * suspend and resume will not be counted in the total. At this point, these three options are available again.</li>
 33  
  * <li>{@link #stop()} the watch to complete the timing session.</li>
 34  
  * </ul>
 35  
  * 
 36  
  * <p>
 37  
  * It is intended that the output methods {@link #toString()} and {@link #getTime()} should only be called after stop,
 38  
  * split or suspend, however a suitable result will be returned at other points.
 39  
  * </p>
 40  
  * 
 41  
  * <p>
 42  
  * NOTE: As from v2.1, the methods protect against inappropriate calls. Thus you cannot now call stop before start,
 43  
  * resume before suspend or unsplit before split.
 44  
  * </p>
 45  
  * 
 46  
  * <p>
 47  
  * 1. split(), suspend(), or stop() cannot be invoked twice<br />
 48  
  * 2. unsplit() may only be called if the watch has been split()<br />
 49  
  * 3. resume() may only be called if the watch has been suspend()<br />
 50  
  * 4. start() cannot be called twice without calling reset()
 51  
  * </p>
 52  
  * 
 53  
  * <p>This class is not thread-safe</p>
 54  
  * 
 55  
  * @since 2.0
 56  
  * @version $Id: StopWatch.java 1401523 2012-10-24 00:50:52Z ggregory $
 57  
  */
 58  
 public class StopWatch {
 59  
 
 60  
     private static final long NANO_2_MILLIS = 1000000L;
 61  
 
 62  
     // running states
 63  
     private static final int STATE_UNSTARTED = 0;
 64  
 
 65  
     private static final int STATE_RUNNING = 1;
 66  
 
 67  
     private static final int STATE_STOPPED = 2;
 68  
 
 69  
     private static final int STATE_SUSPENDED = 3;
 70  
 
 71  
     // split state
 72  
     private static final int STATE_UNSPLIT = 10;
 73  
 
 74  
     private static final int STATE_SPLIT = 11;
 75  
 
 76  
     /**
 77  
      * The current running state of the StopWatch.
 78  
      */
 79  7
     private int runningState = STATE_UNSTARTED;
 80  
 
 81  
     /**
 82  
      * Whether the stopwatch has a split time recorded.
 83  
      */
 84  7
     private int splitState = STATE_UNSPLIT;
 85  
 
 86  
     /**
 87  
      * The start time.
 88  
      */
 89  
     private long startTime;
 90  
 
 91  
     /**
 92  
      * The start time in Millis - nanoTime is only for elapsed time so we 
 93  
      * need to also store the currentTimeMillis to maintain the old 
 94  
      * getStartTime API.
 95  
      */
 96  
     private long startTimeMillis;
 97  
 
 98  
     /**
 99  
      * The stop time.
 100  
      */
 101  
     private long stopTime;
 102  
 
 103  
     /**
 104  
      * <p>
 105  
      * Constructor.
 106  
      * </p>
 107  
      */
 108  
     public StopWatch() {
 109  7
         super();
 110  7
     }
 111  
 
 112  
     /**
 113  
      * <p>
 114  
      * Start the stopwatch.
 115  
      * </p>
 116  
      * 
 117  
      * <p>
 118  
      * This method starts a new timing session, clearing any previous values.
 119  
      * </p>
 120  
      * 
 121  
      * @throws IllegalStateException
 122  
      *             if the StopWatch is already running.
 123  
      */
 124  
     public void start() {
 125  9
         if (this.runningState == STATE_STOPPED) {
 126  1
             throw new IllegalStateException("Stopwatch must be reset before being restarted. ");
 127  
         }
 128  8
         if (this.runningState != STATE_UNSTARTED) {
 129  1
             throw new IllegalStateException("Stopwatch already started. ");
 130  
         }
 131  7
         this.startTime = System.nanoTime();
 132  7
         this.startTimeMillis = System.currentTimeMillis();
 133  7
         this.runningState = STATE_RUNNING;
 134  7
     }
 135  
 
 136  
     /**
 137  
      * <p>
 138  
      * Stop the stopwatch.
 139  
      * </p>
 140  
      * 
 141  
      * <p>
 142  
      * This method ends a new timing session, allowing the time to be retrieved.
 143  
      * </p>
 144  
      * 
 145  
      * @throws IllegalStateException
 146  
      *             if the StopWatch is not running.
 147  
      */
 148  
     public void stop() {
 149  7
         if (this.runningState != STATE_RUNNING && this.runningState != STATE_SUSPENDED) {
 150  2
             throw new IllegalStateException("Stopwatch is not running. ");
 151  
         }
 152  5
         if (this.runningState == STATE_RUNNING) {
 153  4
             this.stopTime = System.nanoTime();
 154  
         }
 155  5
         this.runningState = STATE_STOPPED;
 156  5
     }
 157  
 
 158  
     /**
 159  
      * <p>
 160  
      * Resets the stopwatch. Stops it if need be.
 161  
      * </p>
 162  
      * 
 163  
      * <p>
 164  
      * This method clears the internal values to allow the object to be reused.
 165  
      * </p>
 166  
      */
 167  
     public void reset() {
 168  2
         this.runningState = STATE_UNSTARTED;
 169  2
         this.splitState = STATE_UNSPLIT;
 170  2
     }
 171  
 
 172  
     /**
 173  
      * <p>
 174  
      * Split the time.
 175  
      * </p>
 176  
      * 
 177  
      * <p>
 178  
      * This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected,
 179  
      * enabling {@link #unsplit()} to continue the timing from the original start point.
 180  
      * </p>
 181  
      * 
 182  
      * @throws IllegalStateException
 183  
      *             if the StopWatch is not running.
 184  
      */
 185  
     public void split() {
 186  2
         if (this.runningState != STATE_RUNNING) {
 187  1
             throw new IllegalStateException("Stopwatch is not running. ");
 188  
         }
 189  1
         this.stopTime = System.nanoTime();
 190  1
         this.splitState = STATE_SPLIT;
 191  1
     }
 192  
 
 193  
     /**
 194  
      * <p>
 195  
      * Remove a split.
 196  
      * </p>
 197  
      * 
 198  
      * <p>
 199  
      * This method clears the stop time. The start time is unaffected, enabling timing from the original start point to
 200  
      * continue.
 201  
      * </p>
 202  
      * 
 203  
      * @throws IllegalStateException
 204  
      *             if the StopWatch has not been split.
 205  
      */
 206  
     public void unsplit() {
 207  3
         if (this.splitState != STATE_SPLIT) {
 208  2
             throw new IllegalStateException("Stopwatch has not been split. ");
 209  
         }
 210  1
         this.splitState = STATE_UNSPLIT;
 211  1
     }
 212  
 
 213  
     /**
 214  
      * <p>
 215  
      * Suspend the stopwatch for later resumption.
 216  
      * </p>
 217  
      * 
 218  
      * <p>
 219  
      * This method suspends the watch until it is resumed. The watch will not include time between the suspend and
 220  
      * resume calls in the total time.
 221  
      * </p>
 222  
      * 
 223  
      * @throws IllegalStateException
 224  
      *             if the StopWatch is not currently running.
 225  
      */
 226  
     public void suspend() {
 227  3
         if (this.runningState != STATE_RUNNING) {
 228  1
             throw new IllegalStateException("Stopwatch must be running to suspend. ");
 229  
         }
 230  2
         this.stopTime = System.nanoTime();
 231  2
         this.runningState = STATE_SUSPENDED;
 232  2
     }
 233  
 
 234  
     /**
 235  
      * <p>
 236  
      * Resume the stopwatch after a suspend.
 237  
      * </p>
 238  
      * 
 239  
      * <p>
 240  
      * This method resumes the watch after it was suspended. The watch will not include time between the suspend and
 241  
      * resume calls in the total time.
 242  
      * </p>
 243  
      * 
 244  
      * @throws IllegalStateException
 245  
      *             if the StopWatch has not been suspended.
 246  
      */
 247  
     public void resume() {
 248  3
         if (this.runningState != STATE_SUSPENDED) {
 249  2
             throw new IllegalStateException("Stopwatch must be suspended to resume. ");
 250  
         }
 251  1
         this.startTime += System.nanoTime() - this.stopTime;
 252  1
         this.runningState = STATE_RUNNING;
 253  1
     }
 254  
 
 255  
     /**
 256  
      * <p>
 257  
      * Get the time on the stopwatch.
 258  
      * </p>
 259  
      * 
 260  
      * <p>
 261  
      * This is either the time between the start and the moment this method is called, or the amount of time between
 262  
      * start and stop.
 263  
      * </p>
 264  
      * 
 265  
      * @return the time in milliseconds
 266  
      */
 267  
     public long getTime() {
 268  11
         return getNanoTime() / NANO_2_MILLIS;
 269  
     }
 270  
     /**
 271  
      * <p>
 272  
      * Get the time on the stopwatch in nanoseconds.
 273  
      * </p>
 274  
      * 
 275  
      * <p>
 276  
      * This is either the time between the start and the moment this method is called, or the amount of time between
 277  
      * start and stop.
 278  
      * </p>
 279  
      * 
 280  
      * @return the time in nanoseconds
 281  
      * @since 3.0
 282  
      */
 283  
     public long getNanoTime() {
 284  11
         if (this.runningState == STATE_STOPPED || this.runningState == STATE_SUSPENDED) {
 285  7
             return this.stopTime - this.startTime;
 286  4
         } else if (this.runningState == STATE_UNSTARTED) {
 287  3
             return 0;
 288  1
         } else if (this.runningState == STATE_RUNNING) {
 289  1
             return System.nanoTime() - this.startTime;
 290  
         }
 291  0
         throw new RuntimeException("Illegal running state has occurred.");
 292  
     }
 293  
 
 294  
     /**
 295  
      * <p>
 296  
      * Get the split time on the stopwatch.
 297  
      * </p>
 298  
      * 
 299  
      * <p>
 300  
      * This is the time between start and latest split.
 301  
      * </p>
 302  
      * 
 303  
      * @return the split time in milliseconds
 304  
      * 
 305  
      * @throws IllegalStateException
 306  
      *             if the StopWatch has not yet been split.
 307  
      * @since 2.1
 308  
      */
 309  
     public long getSplitTime() {
 310  3
         return getSplitNanoTime() / NANO_2_MILLIS;
 311  
     }
 312  
     /**
 313  
      * <p>
 314  
      * Get the split time on the stopwatch in nanoseconds.
 315  
      * </p>
 316  
      * 
 317  
      * <p>
 318  
      * This is the time between start and latest split.
 319  
      * </p>
 320  
      * 
 321  
      * @return the split time in nanoseconds
 322  
      * 
 323  
      * @throws IllegalStateException
 324  
      *             if the StopWatch has not yet been split.
 325  
      * @since 3.0
 326  
      */
 327  
     public long getSplitNanoTime() {
 328  3
         if (this.splitState != STATE_SPLIT) {
 329  1
             throw new IllegalStateException("Stopwatch must be split to get the split time. ");
 330  
         }
 331  2
         return this.stopTime - this.startTime;
 332  
     }
 333  
 
 334  
     /**
 335  
      * Returns the time this stopwatch was started.
 336  
      * 
 337  
      * @return the time this stopwatch was started
 338  
      * @throws IllegalStateException
 339  
      *             if this StopWatch has not been started
 340  
      * @since 2.4
 341  
      */
 342  
     public long getStartTime() {
 343  4
         if (this.runningState == STATE_UNSTARTED) {
 344  2
             throw new IllegalStateException("Stopwatch has not been started");
 345  
         }
 346  
         // System.nanoTime is for elapsed time
 347  2
         return this.startTimeMillis;
 348  
     }
 349  
 
 350  
     /**
 351  
      * <p>
 352  
      * Gets a summary of the time that the stopwatch recorded as a string.
 353  
      * </p>
 354  
      * 
 355  
      * <p>
 356  
      * The format used is ISO8601-like, <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.
 357  
      * </p>
 358  
      * 
 359  
      * @return the time as a String
 360  
      */
 361  
     @Override
 362  
     public String toString() {
 363  1
         return DurationFormatUtils.formatDurationHMS(getTime());
 364  
     }
 365  
 
 366  
     /**
 367  
      * <p>
 368  
      * Gets a summary of the split time that the stopwatch recorded as a string.
 369  
      * </p>
 370  
      * 
 371  
      * <p>
 372  
      * The format used is ISO8601-like, <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.
 373  
      * </p>
 374  
      * 
 375  
      * @return the split time as a String
 376  
      * @since 2.1
 377  
      */
 378  
     public String toSplitString() {
 379  1
         return DurationFormatUtils.formatDurationHMS(getSplitTime());
 380  
     }
 381  
 
 382  
 }