Coverage Report - org.apache.commons.lang3.time.StopWatch
 
Classes in this File Line Coverage Branch Coverage Complexity
StopWatch
98%
59/60
96%
29/30
1,848
StopWatch$1
N/A
N/A
1,848
StopWatch$SplitState
100%
3/3
N/A
1,848
StopWatch$State
100%
5/5
N/A
1,848
StopWatch$State$1
100%
4/4
N/A
1,848
StopWatch$State$2
100%
4/4
N/A
1,848
StopWatch$State$3
100%
4/4
N/A
1,848
StopWatch$State$4
100%
4/4
N/A
1,848
 
 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  
  */
 57  
 public class StopWatch {
 58  
 
 59  
     private static final long NANO_2_MILLIS = 1000000L;
 60  
     
 61  
     /**
 62  
      * Enumeration type which indicates the status of stopwatch.
 63  
      */
 64  9
     private enum State {
 65  
 
 66  1
         UNSTARTED {
 67  1
             @Override boolean isStarted() { return false; }
 68  1
             @Override boolean isStopped() { return true;  }
 69  1
             @Override boolean isSuspended() { return false; }
 70  
         },
 71  1
         RUNNING {
 72  1
             @Override boolean isStarted() { return true; }
 73  1
             @Override boolean isStopped() { return false; }
 74  1
             @Override boolean isSuspended() { return false; }
 75  
         },
 76  1
         STOPPED {
 77  1
             @Override boolean isStarted() { return false; }
 78  1
             @Override boolean isStopped() { return true; }
 79  1
             @Override boolean isSuspended() { return false; }
 80  
         },
 81  1
         SUSPENDED {
 82  1
             @Override boolean isStarted() { return true; }
 83  1
             @Override boolean isStopped() { return false; }
 84  1
             @Override  boolean isSuspended() { return true; }
 85  
         };
 86  
 
 87  
         /**
 88  
          * <p>
 89  
          * The method is used to find out if the StopWatch is started. A suspended
 90  
          * StopWatch is also started watch.
 91  
          * </p>
 92  
 
 93  
          * @return boolean
 94  
          *             If the StopWatch is started.
 95  
          */
 96  
         abstract boolean isStarted();
 97  
 
 98  
         /**
 99  
          * <p>
 100  
          * This method is used to find out whether the StopWatch is stopped. The
 101  
          * stopwatch which's not yet started and explicitly stopped stopwatch is
 102  
          * considered as stopped.
 103  
          * </p>
 104  
          *
 105  
          * @return boolean
 106  
          *             If the StopWatch is stopped.
 107  
          */
 108  
         abstract boolean isStopped();
 109  
 
 110  
         /**
 111  
          * <p>
 112  
          * This method is used to find out whether the StopWatch is suspended.
 113  
          * </p>
 114  
          *
 115  
          * @return boolean
 116  
          *             If the StopWatch is suspended.
 117  
          */
 118  
         abstract boolean isSuspended();
 119  
     }
 120  
 
 121  
     /**
 122  
      * Enumeration type which indicates the split status of stopwatch.
 123  
      */    
 124  3
     private enum SplitState {
 125  1
         SPLIT,
 126  1
         UNSPLIT
 127  
     }
 128  
     /**
 129  
      * The current running state of the StopWatch.
 130  
      */
 131  8
     private State runningState = State.UNSTARTED;
 132  
 
 133  
     /**
 134  
      * Whether the stopwatch has a split time recorded.
 135  
      */
 136  8
     private SplitState splitState = SplitState.UNSPLIT;
 137  
 
 138  
     /**
 139  
      * The start time.
 140  
      */
 141  
     private long startTime;
 142  
 
 143  
     /**
 144  
      * The start time in Millis - nanoTime is only for elapsed time so we 
 145  
      * need to also store the currentTimeMillis to maintain the old 
 146  
      * getStartTime API.
 147  
      */
 148  
     private long startTimeMillis;
 149  
 
 150  
     /**
 151  
      * The stop time.
 152  
      */
 153  
     private long stopTime;
 154  
 
 155  
     /**
 156  
      * <p>
 157  
      * Constructor.
 158  
      * </p>
 159  
      */
 160  
     public StopWatch() {
 161  8
         super();
 162  8
     }
 163  
 
 164  
     /**
 165  
      * <p>
 166  
      * Start the stopwatch.
 167  
      * </p>
 168  
      * 
 169  
      * <p>
 170  
      * This method starts a new timing session, clearing any previous values.
 171  
      * </p>
 172  
      * 
 173  
      * @throws IllegalStateException
 174  
      *             if the StopWatch is already running.
 175  
      */
 176  
     public void start() {
 177  10
         if (this.runningState == State.STOPPED) {
 178  1
             throw new IllegalStateException("Stopwatch must be reset before being restarted. ");
 179  
         }
 180  9
         if (this.runningState != State.UNSTARTED) {
 181  1
             throw new IllegalStateException("Stopwatch already started. ");
 182  
         }
 183  8
         this.startTime = System.nanoTime();
 184  8
         this.startTimeMillis = System.currentTimeMillis();
 185  8
         this.runningState = State.RUNNING;
 186  8
     }
 187  
 
 188  
 
 189  
     /**
 190  
      * <p>
 191  
      * Stop the stopwatch.
 192  
      * </p>
 193  
      * 
 194  
      * <p>
 195  
      * This method ends a new timing session, allowing the time to be retrieved.
 196  
      * </p>
 197  
      * 
 198  
      * @throws IllegalStateException
 199  
      *             if the StopWatch is not running.
 200  
      */
 201  
     public void stop() {
 202  8
         if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) {
 203  2
             throw new IllegalStateException("Stopwatch is not running. ");
 204  
         }
 205  6
         if (this.runningState == State.RUNNING) {
 206  4
             this.stopTime = System.nanoTime();
 207  
         }
 208  6
         this.runningState = State.STOPPED;
 209  6
     }
 210  
 
 211  
     /**
 212  
      * <p>
 213  
      * Resets the stopwatch. Stops it if need be.
 214  
      * </p>
 215  
      * 
 216  
      * <p>
 217  
      * This method clears the internal values to allow the object to be reused.
 218  
      * </p>
 219  
      */
 220  
     public void reset() {
 221  2
         this.runningState = State.UNSTARTED;
 222  2
         this.splitState = SplitState.UNSPLIT;
 223  2
     }
 224  
 
 225  
     /**
 226  
      * <p>
 227  
      * Split the time.
 228  
      * </p>
 229  
      * 
 230  
      * <p>
 231  
      * This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected,
 232  
      * enabling {@link #unsplit()} to continue the timing from the original start point.
 233  
      * </p>
 234  
      * 
 235  
      * @throws IllegalStateException
 236  
      *             if the StopWatch is not running.
 237  
      */
 238  
     public void split() {
 239  2
         if (this.runningState != State.RUNNING) {
 240  1
             throw new IllegalStateException("Stopwatch is not running. ");
 241  
         }
 242  1
         this.stopTime = System.nanoTime();
 243  1
         this.splitState = SplitState.SPLIT;
 244  1
     }
 245  
 
 246  
     /**
 247  
      * <p>
 248  
      * Remove a split.
 249  
      * </p>
 250  
      * 
 251  
      * <p>
 252  
      * This method clears the stop time. The start time is unaffected, enabling timing from the original start point to
 253  
      * continue.
 254  
      * </p>
 255  
      * 
 256  
      * @throws IllegalStateException
 257  
      *             if the StopWatch has not been split.
 258  
      */
 259  
     public void unsplit() {
 260  3
         if (this.splitState != SplitState.SPLIT) {
 261  2
             throw new IllegalStateException("Stopwatch has not been split. ");
 262  
         }
 263  1
         this.splitState = SplitState.UNSPLIT;
 264  1
     }
 265  
 
 266  
     /**
 267  
      * <p>
 268  
      * Suspend the stopwatch for later resumption.
 269  
      * </p>
 270  
      * 
 271  
      * <p>
 272  
      * This method suspends the watch until it is resumed. The watch will not include time between the suspend and
 273  
      * resume calls in the total time.
 274  
      * </p>
 275  
      * 
 276  
      * @throws IllegalStateException
 277  
      *             if the StopWatch is not currently running.
 278  
      */
 279  
     public void suspend() {
 280  4
         if (this.runningState != State.RUNNING) {
 281  1
             throw new IllegalStateException("Stopwatch must be running to suspend. ");
 282  
         }
 283  3
         this.stopTime = System.nanoTime();
 284  3
         this.runningState = State.SUSPENDED;
 285  3
     }
 286  
 
 287  
     /**
 288  
      * <p>
 289  
      * Resume the stopwatch after a suspend.
 290  
      * </p>
 291  
      * 
 292  
      * <p>
 293  
      * This method resumes the watch after it was suspended. The watch will not include time between the suspend and
 294  
      * resume calls in the total time.
 295  
      * </p>
 296  
      * 
 297  
      * @throws IllegalStateException
 298  
      *             if the StopWatch has not been suspended.
 299  
      */
 300  
     public void resume() {
 301  3
         if (this.runningState != State.SUSPENDED) {
 302  2
             throw new IllegalStateException("Stopwatch must be suspended to resume. ");
 303  
         }
 304  1
         this.startTime += System.nanoTime() - this.stopTime;
 305  1
         this.runningState = State.RUNNING;
 306  1
     }
 307  
 
 308  
     /**
 309  
      * <p>
 310  
      * Get the time on the stopwatch.
 311  
      * </p>
 312  
      * 
 313  
      * <p>
 314  
      * This is either the time between the start and the moment this method is called, or the amount of time between
 315  
      * start and stop.
 316  
      * </p>
 317  
      * 
 318  
      * @return the time in milliseconds
 319  
      */
 320  
     public long getTime() {
 321  11
         return getNanoTime() / NANO_2_MILLIS;
 322  
     }
 323  
     /**
 324  
      * <p>
 325  
      * Get the time on the stopwatch in nanoseconds.
 326  
      * </p>
 327  
      * 
 328  
      * <p>
 329  
      * This is either the time between the start and the moment this method is called, or the amount of time between
 330  
      * start and stop.
 331  
      * </p>
 332  
      * 
 333  
      * @return the time in nanoseconds
 334  
      * @since 3.0
 335  
      */
 336  
     public long getNanoTime() {
 337  11
         if (this.runningState == State.STOPPED || this.runningState == State.SUSPENDED) {
 338  7
             return this.stopTime - this.startTime;
 339  4
         } else if (this.runningState == State.UNSTARTED) {
 340  3
             return 0;
 341  1
         } else if (this.runningState == State.RUNNING) {
 342  1
             return System.nanoTime() - this.startTime;
 343  
         }
 344  0
         throw new RuntimeException("Illegal running state has occurred.");
 345  
     }
 346  
 
 347  
     /**
 348  
      * <p>
 349  
      * Get the split time on the stopwatch.
 350  
      * </p>
 351  
      * 
 352  
      * <p>
 353  
      * This is the time between start and latest split.
 354  
      * </p>
 355  
      * 
 356  
      * @return the split time in milliseconds
 357  
      * 
 358  
      * @throws IllegalStateException
 359  
      *             if the StopWatch has not yet been split.
 360  
      * @since 2.1
 361  
      */
 362  
     public long getSplitTime() {
 363  3
         return getSplitNanoTime() / NANO_2_MILLIS;
 364  
     }
 365  
     /**
 366  
      * <p>
 367  
      * Get the split time on the stopwatch in nanoseconds.
 368  
      * </p>
 369  
      * 
 370  
      * <p>
 371  
      * This is the time between start and latest split.
 372  
      * </p>
 373  
      * 
 374  
      * @return the split time in nanoseconds
 375  
      * 
 376  
      * @throws IllegalStateException
 377  
      *             if the StopWatch has not yet been split.
 378  
      * @since 3.0
 379  
      */
 380  
     public long getSplitNanoTime() {
 381  3
         if (this.splitState != SplitState.SPLIT) {
 382  1
             throw new IllegalStateException("Stopwatch must be split to get the split time. ");
 383  
         }
 384  2
         return this.stopTime - this.startTime;
 385  
     }
 386  
 
 387  
     /**
 388  
      * Returns the time this stopwatch was started.
 389  
      * 
 390  
      * @return the time this stopwatch was started
 391  
      * @throws IllegalStateException
 392  
      *             if this StopWatch has not been started
 393  
      * @since 2.4
 394  
      */
 395  
     public long getStartTime() {
 396  4
         if (this.runningState == State.UNSTARTED) {
 397  2
             throw new IllegalStateException("Stopwatch has not been started");
 398  
         }
 399  
         // System.nanoTime is for elapsed time
 400  2
         return this.startTimeMillis;
 401  
     }
 402  
 
 403  
     /**
 404  
      * <p>
 405  
      * Gets a summary of the time that the stopwatch recorded as a string.
 406  
      * </p>
 407  
      * 
 408  
      * <p>
 409  
      * The format used is ISO 8601-like, <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.
 410  
      * </p>
 411  
      * 
 412  
      * @return the time as a String
 413  
      */
 414  
     @Override
 415  
     public String toString() {
 416  1
         return DurationFormatUtils.formatDurationHMS(getTime());
 417  
     }
 418  
 
 419  
     /**
 420  
      * <p>
 421  
      * Gets a summary of the split time that the stopwatch recorded as a string.
 422  
      * </p>
 423  
      * 
 424  
      * <p>
 425  
      * The format used is ISO 8601-like, <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.
 426  
      * </p>
 427  
      * 
 428  
      * @return the split time as a String
 429  
      * @since 2.1
 430  
      */
 431  
     public String toSplitString() {
 432  1
         return DurationFormatUtils.formatDurationHMS(getSplitTime());
 433  
     }
 434  
 
 435  
     /**
 436  
      * <p>
 437  
      * The method is used to find out if the StopWatch is started. A suspended
 438  
      * StopWatch is also started watch.
 439  
      * </p>
 440  
      *
 441  
      * @return boolean
 442  
      *             If the StopWatch is started.
 443  
      * @since 3.2
 444  
      */
 445  
     public boolean isStarted() {
 446  4
         return runningState.isStarted();
 447  
     }
 448  
 
 449  
     /**
 450  
      * <p>
 451  
      * This method is used to find out whether the StopWatch is suspended.
 452  
      * </p>
 453  
      *
 454  
      * @return boolean
 455  
      *             If the StopWatch is suspended.
 456  
      * @since 3.2
 457  
      */
 458  
     public boolean isSuspended() {
 459  4
         return runningState.isSuspended();
 460  
     }
 461  
 
 462  
     /**
 463  
      * <p>
 464  
      * This method is used to find out whether the StopWatch is stopped. The
 465  
      * stopwatch which's not yet started and explicitly stopped stopwatch is
 466  
      * considered as stopped.
 467  
      * </p>
 468  
      *
 469  
      * @return boolean
 470  
      *             If the StopWatch is stopped.
 471  
      * @since 3.2
 472  
      */
 473  
     public boolean isStopped() {
 474  4
         return runningState.isStopped();
 475  
     }    
 476  
 
 477  
 }