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