1
\$\begingroup\$

I have received a nice answer for this post. Now, it is my attempt for some improvement:

package net.coderodde.time;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

/**
 * This class provides easy-to-use means for measuring elapsed time.
 * 
 * @author Rodion "rodde" Efremov
 * @version 1.6 (Feb 12, 2019)
 */
public final class StopWatch {

    private boolean isMeasuring; // false by default.
    private long startTimeMillis;
    private long markTimeMillis;
    private final List<Long> memory = new ArrayList<>();

    /**
     * Starts measuring time.
     */
    public void start() {
        setImpl(true);
    }

    /**
     * Stops measuring time.
     */
    public void stop() {
        setImpl(false);
    }   

    /**
     * Resets the starting time to the current moment.
     */
    public void reset() {
        setImpl(true);
    }

    private void setImpl(boolean expectedStatus) {
        if (expectedStatus) {
            checkMeasuringStatusIsOff();
        } else {
            checkMeasuringStatusIsOn();
        }

        startTimeMillis = System.currentTimeMillis();
        markTimeMillis  = startTimeMillis;
        isMeasuring     = !isMeasuring;
        memory.clear();
    }

    /**
     * Marks current time for future calculation of lap times.
     */
    public void mark() {
        checkMeasuringStatusIsOn();
        markTimeMillis = System.currentTimeMillis();
    }

    /**
     * Returns the time elapsed from beginning of the current lap.
     * 
     * @return the lap time.
     */
    public long lap() {
        checkMeasuringStatusIsOn();
        long now = System.currentTimeMillis();
        memory.add(now);
        long saveMarkTimeMillis = markTimeMillis;
        markTimeMillis = now;
        return now - saveMarkTimeMillis;
    }

    /**
     * Returns the entire lap memory.
     * 
     * @return the list of lap times.
     */
    public long[] recall() {
        long[] mem = new long[memory.size()];
        mem[0] = memory.get(0) - startTimeMillis;

        for (int i = 1; i < mem.length; i++) {
            mem[i] = memory.get(i) -
                     memory.get(i - 1);
        }

        return mem;
    }

    /**
     * Returns the time of a full previous lap.
     * 
     * @return the lap time of the previous full lap.
     */
    public long split() {
        checkMeasuringStatusIsOn();

        switch (memory.size()) {
            case 1:
                return memory.get(0) - startTimeMillis;

            default:
                int index = memory.size() - 2;
                return memory.get(index + 1) - memory.get(index);
        }
    }

    @Override
    public String toString() {
        return String.format(
                "(isMeasuring=%b, startTimeMillis=%d, markTimeMillis=%d, " + 
                "memory=%s)",
                isMeasuring,
                startTimeMillis,
                markTimeMillis,
                memory.toString());
    }

    private void checkMeasuringStatus(boolean expecteedMeasuringStatus,
                                      String exceptionMessage) {
        if (isMeasuring != expecteedMeasuringStatus) {
            throw new IllegalStateException(exceptionMessage);
        }
    }

    private void checkMeasuringStatusIsOn() {
        checkMeasuringStatus(true, "The stopwatch is not ticking.");
    }

    private void checkMeasuringStatusIsOff() {
        checkMeasuringStatus(false, "The stopwatch is ticking.");
    }

    public static void main(String[] args) {
        StopWatch sw = new StopWatch();
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println(sw);
            String cmd = scanner.next();

            switch (cmd)  {
                case "start":
                    sw.start();
                    break;

                case "stop":
                    sw.stop();
                    break;

                case "recall":
                    System.out.println(Arrays.toString(sw.recall()));
                    break;

                case "split":
                    System.out.println(sw.split());
                    break;

                case "lap":
                    System.out.println(sw.lap());
                    break;

                case "mark":
                   sw.mark();
                   break;

                case "quit":
                case "exit":
                    return;
            }
        }
    }
}

So, am I going into the right direction?

\$\endgroup\$
1
\$\begingroup\$

Typo: expecteedMeasuringStatus the word expected is spelled with only one consecutive e.

Measuring time:

Imagine that some user would start your application, start measuring the time, then change the system time, then at some point later stop the measuring. What happens? Your time measuring will be inaccurate. Solution: Use System.nanoTime() and not System.currentTimeMillis()

\$\endgroup\$
  • \$\begingroup\$ True. Citing, This method can only be used to measure elapsed time \$\endgroup\$ – coderodde Feb 12 at 11:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.