【问题标题】:Variable might not have benn initialized for final variable and anonymous class变量可能尚未为最终变量和匿名类初始化
【发布时间】:2012-03-31 14:23:48
【问题描述】:

我写了这段代码:

ScheduledExecutorService ExtractorTimer=Executors.newScheduledThreadPool(1);
final ScheduledFuture<?> SchedulerHandle;
SchedulerHandle =ExtractorTimer.scheduleWithFixedDelay(
    new Runnable() {
        public void run() {
            if(DB.buildConnection()){
                  SchedulerHandle.cancel(false);
            }
        }
     },0, 60,java.util.concurrent.TimeUnit.SECONDS);

它给出了这个:

Variable SchedulerHandle might not have benn initialized

有什么问题?
我该如何解决?

【问题讨论】:

  • 我在您的代码中没有看到名为 ScheduledFuture 的变量。 (顺便说一句,您应该避免以首字母大写来命名变量,因为它们很容易与类名混淆。)
  • 我的意思是,您可能没有向我们展示实际的错误消息...
  • 对不起。是一个错字。我编辑了这个问题。

标签: java variables initialization


【解决方案1】:

编译器是正确的。这里其实有问题。

问题的出现是因为 Java 处理匿名 Runnable 类中 SchedulerHandle 变量的使用方式。在实例化Runnable 类时,使用合成构造函数参数将SchedulerHandle 的值传递给匿名类。这个值存储在一个隐藏的属性中,这就是 run() 方法使用的......而不是封闭类的范围内的变量。

那么为什么会导致错误呢?

嗯,我上面描述的机制意味着SchedulerHandle 需要在Runnable 实例创建之前进行初始化。但事实上,它会在 scheduleWithFixedDelay 调用返回之后被初始化。所以在需要变量值的时候它还没有被初始化。

【讨论】:

    【解决方案2】:

    因为 SchedulerHandle 是最终的并且您没有立即定义它,所以您的编译器会警告您,它可能没有在 run() 方法中初始化。 只需这样做:

    最终 ScheduledFuture SchedulerHandle = ExtractorTimer.scheduleWithFixedDelay(...

    更新:这完全是错误的。让我们看看,您想每 60 秒调用一次 DB.buildConnection(),直到它返回 true。不幸的是,您不能在调用该方法的 Runnable 中引用从 scheduleWithFixedDelay() 返回的 SchedulerHandle,因为必须首先定义 Runnable - 但它不知道 SchedulerHandle 是什么,因为它当时不存在。

    因此,取消进程的另一种方法是终止您的 ScheduledExecutorService,如下所示:

    ScheduledExecutorService ExtractorTimer=Executors.newScheduledThreadPool(1);
    final ScheduledFuture<?> SchedulerHandle;
    SchedulerHandle =ExtractorTimer.scheduleWithFixedDelay(
        new Runnable() {
            public void run() {
                if(DB.buildConnection()){
                      ExtractorTimer.shutdown();
                }
            }
        },0, 60,java.util.concurrent.TimeUnit.SECONDS);
    

    但请注意,如果您这样做,您将无法重复使用 ExtractorTimer,并且任何给定的任务都将被取消!未来的 schedule()s 也不会执行。让它再次可用的唯一方法是创建一个新的 ScheduledExecutorService - 这是这种方法的缺点。

    因此,如果您可以仅将 ExtractorTimer 用于这一项任务,那么一切都应该没问题。

    【讨论】:

    • 这样做没有效果!我仍然收到消息。
    • 作为关闭整个线程池的替代方法,Runnable 可能会简单地抛出一个RuntimeException。这也会停止任务。
    • @A.H.我认为是的,虽然我当时不太理解 Java 文档:“如果任务的任何执行遇到异常,则后续执行将被抑制。否则,任务只会通过取消或终止执行程序来终止。”所以他们被“压制”,而不是被取消?不知道有没有区别。
    • 快速测试显示isCancelled==falseisDone==trueget() 将收到一个包装原始异常的ExecutionException。如果@snigger 可以忍受 - 好的。
    【解决方案3】:

    试试:

    final ScheduledFuture<?> SchedulerHandle = null;
    

    【讨论】:

    • ROTFL。这并没有真正的帮助。
    • 试一试。它解决了 Netbeans 中的问题对我来说看起来很合乎逻辑:-)
    • 您注意到SchedulerHandle.cancel(false); 即将推出的NPE 了吗?还有这个最终变量的赋值?如果这在 Netbeans 中真的有效,我在接下来的十年内不会碰这个 IDE。
    • ScheduledFuture> SchedulerHandle;变量未初始化,对吗?然后调用 scheduleWithFixedDelay,它可以抛出异常,对吗?如果它抛出异常,SchedulerHandle 仍然没有初始化,对吗?所以,用 null 初始化它或处理异常
    • 第一点:变量为final。你初始化它。所以下一行 - 对这个变量的赋值 - 不会编译。如果 Netbeans 没有向您显示此错误……太糟糕了。第二:scheduleWithFixedDelay 是否抛出异常无关紧要。 Runnable 将异步执行。当发生这种情况时,它会由于 `SchedulerHandle.cancel(false); 行而抛出 NPE。 ` - 您固定到null 的变量。并且删除 final 将不起作用,因为这样您就无法从 Runnable 内部访问该变量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 2015-07-04
    • 1970-01-01
    相关资源
    最近更新 更多