Home > Enterprise >  How do I restart the timer countdown
How do I restart the timer countdown

Time:06-03

I am trying to reset the timer so it can pull another value from my array. Does anyone know the solution? My error is saying:

peat = peat= 1; 
local variables referenced from an inner class must be final or effectively final

I am stuck and I know I need to reset the timer but I don't know how.

class MyProgram {

    public static void main(String[] args) {
        int peat = 0;
        int cdown = 0;
        Scanner input1 = new Scanner(System.in);
        System.out.println("What is your name");
        String personsName = input1.next();
        System.out.println((personsName)   " Are you ready to impove yourself");
        String motiv = input1.next();

        String[] myArray = new String[4];
        myArray[0] = "Keep going";
        myArray[1] = "1 more rep";
        myArray[2] = "you have come so far don't stop now";
        myArray[3] = "Think of the progress you have made";

        if (motiv.equals("yes")) {
            System.out.println("Today is the day hard work begins");
        } else {
            System.out.println("type yes when you're ready to work");
        }

        Scanner input2 = new Scanner(System.in);
        System.out.println("You will recive quotes throughout your workout to remind you to keep working type ok if you accept");
        String confirm = input2.next();

        if (confirm.equals("ok")) {
            final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
            final Runnable runnable = new Runnable() {
                int countdown = 10;
                public void run() {
                    System.out.println(countdown);
                    countdown--;
                    if (countdown == 0 && peat < 4) {
                        System.out.println(myArray[0]);
                        //reset count down to 10
                        peat = peat   1;
                    } else {
                        scheduler.shutdown();
                    }
                }
            };
            scheduler.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);
        }
        while (cdown < 1) {
            System.out.println(myArray[1]);
            cdown = cdown   1;
        }
    }
}

CodePudding user response:

As the error message states, Java doesn't allow modifying variables belonging to the outer scope from within a "lambda" scope (instances of anonymous classes also create such a scope).

In your case, in order to work-around this issue, you could make peat a class variable:

import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.SECONDS;

public class MyProgram {

    private static int peat = 0;

    public static void main(String[] args) {
        // Code of main()
        // Remove local "peat" variable
    }
}

CodePudding user response:

This is because peat is not a final or effectively-final variable. As the documentation states:

An anonymous class cannot access local variables in its enclosing scope that are not declared as final or effectively final.

https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html#accessing

In fact, when a local class (a class defined in a block) accesses a local variable or parameter of the enclosing block, it captures that variable or parameter. This means that the value is literally copied within the local class.

Although a local class is declared within a block, its context is completely dissociated from the one where it has been created. Any modification made from the local class must be prevented as there is no way to reflect those changes in the enclosing scope. Likewise, in the enclosing scope the variable must remain unmodified as well, as once its value has been captured for the local class, any changes from the enclosing scope cannot be reflected within the local class.

If you want to launch a timer with a ScheduledThreadPoolExecutor, then you cannot rely on a class defined on the go using the enclosing scope's variables, but you need to declare a class extending Runnable. This Timer class can be instantiated by passing the number of seconds (or any other sensibility the Timer is scheduled with), a reference to the scheduler and the array of messages.

class Timer implements Runnable {
    private ScheduledExecutorService scheduler;
    private int numSecs;

    private String[] vetMessages;

    public Timer(ScheduledExecutorService scheduler, int numSecs, String[] vetMessages) {
        this.scheduler = scheduler;
        this.numSecs = numSecs;
        this.vetMessages = vetMessages;
    }

    @Override
    public void run() {
        numSecs--;
        if (numSecs < 4) {
            System.out.println(vetMessages[numSecs]);
            if (numSecs <= 0) {
                scheduler.shutdown();
            }
        }
    }
}

class MyProgram {

    public static void main(String[] args) {
        Scanner input1 = new Scanner(System.in);
        System.out.println("What is your name");
        String personsName = input1.next();
        System.out.println((personsName)   " Are you ready to impove yourself");
        String motiv = input1.next();

        String[] myArray = new String[4];
        myArray[0] = "Keep going";
        myArray[1] = "1 more rep";
        myArray[2] = "you have come so far don't stop now";
        myArray[3] = "Think of the progress you have made";

        if (motiv.equals("yes")) {
            System.out.println("Today is the day hard work begins");
        } else {
            System.out.println("type yes when you're ready to work");
        }

        Scanner input2 = new Scanner(System.in);
        System.out.println("You will recive quotes throughout your workout to remind you to keep working type ok if you accept");
        String confirm = input2.next();

        if (confirm.equals("ok")) {
            final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
            Timer t = new Timer(scheduler, 10, myArray);

            //Added an initial delay of 1 second to not start the Timer immediately and decrement the number of seconds right away
            scheduler.scheduleAtFixedRate(t, 1, 1, TimeUnit.SECONDS);
        }
    }
}
  • Related