【问题标题】:JAVA local variables referenced from an inner class must be final or effectively final从内部类引用的 JAVA 局部变量必须是 final 或有效 final
【发布时间】:2018-01-03 12:57:18
【问题描述】:

我正在尝试返回 stats 对象。

但我得到了

从内部类引用的局部变量必须是 final 或 有效地最终

stats = statistics; 上我如何返回对象但确保.close(); 已运行?

 public static Statistics getStatistics(String environmentName) {
    Container container = getContainer(environmentName);
    Statistics stats = new Statistics();

    try {
        dockerClient().statsCmd(container.getId()).exec(new ResultCallback<Statistics>() {
            @Override
            public void onStart(Closeable closeable) {

            }

            @Override
            public void onNext(Statistics statistics) {
                stats = statistics;
            }

            @Override
            public void onError(Throwable throwable) {

            }

            @Override
            public void onComplete() {

            }

            @Override
            public void close() throws IOException {

            }
        }).close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return stats;
}

【问题讨论】:

  • 本地内部类可以访问包含它的类的字段以及定义它的块的字段。但是,这些类只有在声明为 final 或实际上是 final 时才能访问包含它的块的变量或参数。
  • @Brijesh 在简单的英语中是什么意思?
  • 如果我输入Statistics 表示我不能为最终赋值...
  • @sadas 根据github.com/docker-java/docker-java/blob/master/src/main/java/…,看起来exec() 方法正在返回一些东西,很可能是您作为参数传递的对象。创建该类型的普通类,将结果存储在字段中。稍后,您可以从exec() 调用的返回对象中访问该字段。

标签: java


【解决方案1】:

您想致电getStatistics 并立即使用生成的统计信息。这称为同步用法。

但实际上只能异步通过回调通知统计信息终于到达。

所以改变:

f(String env) {
    Statistics stats = getStatistics(env);
    g(stats);
}

f(String env) {
    retrievStatistics(env);
}

public static void retrieveStatistics(String environmentName) {
    Container container = getContainer(environmentName);
    stats = null;
    try {
        dockerClient().statsCmd(container.getId()).exec(new ResultCallback<Statistics>() {
            Statistics stats;

            @Override
            public void onNext(Statistics statistics) {
                g(statistics);
                stats = statistics; // Alternative when using onComplete instead.
            }

            @Override public void onStart(Closeable closeable) {}
            @Override public void onError(Throwable throwable) { }
            @Override public void onComplete() {
                g(stats); // Or this
            }
            @Override public void close() throws IOException { }
        }).close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

像您那样繁忙的等待循环是次优的。

【讨论】:

    【解决方案2】:

    您可以尝试使用 java.util.concurrent.CompletableFuture (java 8)。 在这种情况下:

    public static Statistics getStatistics(String environmentName) {
        Container container = null;
        CompletableFuture<Statistics> future = new CompletableFuture<>();
    
        try {
            dockerClient().statsCmd(container.getId()).exec(new ResultCallback<Statistics>() {
                @Override
                public void onStart(Closeable closeable) {
    
                }
    
                @Override
                public void onNext(Statistics statistics) {
                    if (!future.isDone()) {
                        future.complete(statistics);
                    }
                }
    
                @Override
                public void onError(Throwable throwable) {
                    future.completeExceptionally(throwable);
                }
    
                @Override
                public void onComplete() {
                    if (!future.isDone()) {
                        future.complete(null);
                    }
                }
    
                @Override
                public void close() throws IOException {
    
                }
            }).close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        try {
            // wait until statistics resolved
            return future.get();
    
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
    

    或者,如果 exec 代码是同步的,您可以使用 AtomicReference,例如,作为临时容器。该方法类似于上面的 CompletableFuture 示例,但开销更少

    【讨论】:

      【解决方案3】:

      您正在创建一个匿名内部类:

      new ResultCallback<Statistics>() { @Override public void onStart(Closeable closeable) { } @Override public void onNext(Statistics statistics) { stats = statistics; } @Override public void onError(Throwable throwable) { } @Override public void onComplete() { } @Override public void close() throws IOException { } }).close();
      

      问题是您在方法中定义统计数据是不必要的,因为您在匿名内部类 @Override public void onNext(Statistics statistics) { stats = statistics; } 中再次定义它

      相反,尝试直接在类中声明变量并初始化为null。内部函数只在匿名类中重新定义。

      【讨论】:

        猜你喜欢
        • 2019-09-24
        • 1970-01-01
        • 2021-01-12
        • 1970-01-01
        • 1970-01-01
        • 2015-01-25
        • 1970-01-01
        相关资源
        最近更新 更多