java 在初始化后将执行的实现中出现“变量可能尚未初始化”

kmpatx3s  于 2022-12-10  发布在  Java
关注(0)|答案(1)|浏览(245)

我有这样的平安守则:

private final static Thread mainThread = Thread.currentThread();
private final static ScheduledFuture<?> consumeSchedule;

static{

    Runnable consumeMessages = () -> {

        //...Some code...

        //stop the printSchedule
        if(!mainThread.isAlive()){
            consumeSchedule.cancel(false); //Variable might not have been initialized
        }

    };

    //this will execute until the main thread will stop.
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
    consumeSchedule = executor.scheduleAtFixedRate(consumeMessages, 0, printRateMS, TimeUnit.MILLISECONDS);

}

如何避免“变量可能未初始化”错误,因为很明显,cancel将在printSchedule初始化后调用。
或者如何在主线程终止时停止consumeSchedule?

7kqas0il

7kqas0il1#

好吧,这看起来可能有点奇怪,但是如果将lambda表达式转换为匿名类,错误就会消失:

Runnable consumeMessages = new Runnable() {

    @Override
    public void run() {
        // Some code...
        if (!mainThread.isAlive()) {
            consumeSchedule.cancel(false);
        }
    }
};

这是因为lambda表达式的工作方式。
我认为下面从Java语言规范§ 15.27.2. Lambda Body中摘录的内容在这里是适用的:
与匿名类声明中出现的代码不同,lambda主体中出现的名称、thissuper关键字的含义,沿着被引用声明的可访问性,与周围上下文中的含义相同(除了lambda参数引入了新名称)。
(强调我的。)
因此,被引用声明的可访问性实际上与您编写的代码相同:

static {
    // Some code...
    if (!mainThread.isAlive()) {
        consumeSchedule.cancel(false);
    }

    // This will execute until the main thread will stop.
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
    consumeSchedule = executor.scheduleAtFixedRate(consumeMessages, 0, printRateMS, TimeUnit.MILLISECONDS);
}

现在,编译器抱怨的原因变得更加明显了:在赋值之前,您已经使用了consumeSchedule。这是从Java Language Specification § 16. Definite Assignment得出的:
每一个由语句声明的局部变量(参见14.4.2节、14.14.1节、14.14.2节、14.20.3节)和每一个空的final字段(参见4.12.4节、8.3.1.2节),在其值发生任何访问时,都必须有一个 * 明确赋值 * 的值。
(...)
每次存取局部变量或空白final字段x时,必须在存取前明确指定x,否则会发生编译时期错误。

相关问题