双冒号运算符(::)和(有效)最终

时间:2017-03-13 14:10:47

标签: java java-8

所以我一直在检查使用CloseableExecutorService接口的可能性。然后我看到Lukas回答here这只是使用方法参考:

ExecutorService service = Executors.newSingleThreadExecutor();
try (Closeable close = service::shutdown) {

}

所以我一直在挖掘并希望在try块中初始化服务:

@Test(expected = RejectedExecutionException.class)
    public void singleThreadTest() throws Exception {

        ExecutorService es = null;

        try (Closeable closeable = (es = Executors.newSingleThreadExecutor())::shutdown){

            es.execute(()->System.out.println("executed " + Thread.currentThread().getId()));
        } 
        System.out.println("executed " + Thread.currentThread().getId());

        System.out.println(es.isShutdown());

        es.execute(()->{});

    }

这部分相当不错,有点困惑,但如果有异常,我会相信,然后我试过了:

@Test(expected = RejectedExecutionException.class)
    public void singleThreadTest() throws Exception {

        ExecutorService es = null;

        try (Closeable closeable = es::shutdown){

            es = Executors.newSingleThreadExecutor();
            es.execute(()->System.out.println("executed " + Thread.currentThread().getId()));
        } 
        System.out.println("executed " + Thread.currentThread().getId());

        System.out.println(es.isShutdown());

        es.execute(()->{});

    }

对于这个代码块,我得到NullPointerException但代码块已成功执行(新线程已创建,但在close()阶段我遇到异常)。我注意到,当我宣布:

Closeable closeable = es::shutdown

es必须(有效)最终,这个问题只发生在双冒号运算符中。即低于一个不编译:

try (Closeable closeable = new Closeable() {

            @Override
            public void close() throws IOException {
                es.shutdown();

            }
        }){

这是一个错误吗?这是什么原因?  *方法参考impl?  * IDE  * JVM(oracle - debian)?

  

跟进:

@Test(expected = RejectedExecutionException.class)
    public void singleThreadTest() throws Exception {

        ExecutorService es = null;


        es = Executors.newSingleThreadExecutor();
        es = Executors.newSingleThreadExecutor();
        es = null;
        try (Closeable closeable = ()->es.shutdown();){

            es = Executors.newSingleThreadExecutor();
            es.execute(()->System.out.println("executed " + Thread.currentThread().getId()));
        } 
        System.out.println("executed " + Thread.currentThread().getId());

        System.out.println(es.isShutdown());

        es.execute(()->{});

    }

此代码无法编译,但确实如此:

@Test(expected = RejectedExecutionException.class)
    public void singleThreadTest() throws Exception {

        ExecutorService es = null;


        es = Executors.newSingleThreadExecutor();
        es = Executors.newSingleThreadExecutor();
        es = null;
        try (Closeable closeable = es::shutdown;){

            es = Executors.newSingleThreadExecutor();
            es.execute(()->System.out.println("executed " + Thread.currentThread().getId()));
        } 
        System.out.println("executed " + Thread.currentThread().getId());

        System.out.println(es.isShutdown());

        es.execute(()->{});

    }

1 个答案:

答案 0 :(得分:1)

不,这不是一个错误。您要关闭的变量/参数的值需要在捕获点知道。

当你得到一个NPE时,因为你在es = null时声明了匿名内部类(或lambda或方法引用)。这就是被捕获的价值:未来的任务没有被看到。

Why can method reference use non-final variables?

为了阻止你犯这个错误,有一个限制“X必须(有效)最终”,这意味着如果你试图改变你想要捕获的变量X的值,它将无法编译。

Why are only final variables accessible in anonymous class?

基本上,您需要将代码重新排列为以下内容:

final ExecutorService es = Executors.newSingleThreadExecutor();
try (Closeable closeable = es::shutdown) {
    // ...