我正在尝试重置计时器,以便它可以从我的数组中提取另一个值。 有谁知道解决方案吗?我的错误是:
peat = peat= 1;
local variables referenced from an inner class must be final or effectively final
我被困住了,我知道我需要重置计时器,但我不知道如何操作。
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;
}
}
}
正如错误消息所述,Java 不允许在“lambda”作用域内修改属于外部作用域的变量(匿名类的实例也会创建这样的作用域)。
在您的情况下,为了解决此问题,您可以将
peat
设为类变量:
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
}
}
这是因为
peat
不是最终变量或有效最终变量。正如文档所述:
匿名类无法访问其封闭范围内未声明为final或有效final的局部变量。
当匿名类访问封闭块的局部变量时,匿名类捕获该变量。这意味着变量的值实际上是在匿名类中复制的。
在您的例子中,您使用 lambda 表达式来提供
Runnable
的实现。与匿名类一样,lambda 表达式被称为“词法作用域”,这意味着它们不会引入任何新级别的作用域。此外,它们也可以从封闭范围捕获变量。
与本地类和匿名类一样,lambda 表达式可以捕获变量;它们对封闭范围的局部变量具有相同的访问权限。 [...] Lambda 表达式具有词法范围。这意味着它们不会从超类型继承任何名称或引入新级别的范围。与本地类和匿名类一样,lambda 表达式只能访问封闭块的本地变量和参数,这些变量和参数是
final或 有效地final。
虽然匿名类是在块中声明的,但它的上下文与创建它的上下文完全分离。必须防止对匿名类进行任何修改,因为无法在封闭范围内反映这些更改。同样,在封闭作用域中,变量必须保持不变,因为一旦匿名类捕获了其值,封闭作用域中的任何更改都无法反映到匿名类中。
如果您想使用
ScheduledThreadPoolExecutor
启动计时器,那么您不能依赖动态定义的类并使用封闭范围的变量。您需要声明一个扩展
Runnable
的类。在以下示例中,可以通过传递秒数、对调度程序的引用和消息数组来实例化 Timer
类。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);
}
}
}