双冒号运算符 (::) 和(有效)final [重复]

Posted

技术标签:

【中文标题】双冒号运算符 (::) 和(有效)final [重复]【英文标题】:Double colon operator (::) and (effectively) final [duplicate] 【发布时间】:2017-03-13 14:10:46 【问题描述】:

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

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


所以我一直在挖掘并想在尝试块中初始化服务:

@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(()->);

    

这部分相当不错,eclipse有点困惑,但如果有异常我相信它会被压制,那么我已经尝试过:

@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(()->);

    

【问题讨论】:

我觉得你的文字有点混乱。例如,缺少分隔不同句子的标点符号?而且您的源代码在某些部分的格式也很奇怪。不是很容易阅读输入。并且为了记录:至少据我所知,它被称为 方法引用 不是双冒号运算符。 那么这两个问题中的哪一个是重复的? ***.com/q/33052917/476716***.com/q/4732544/476716 另见What is the equivalent lambda expression for System.out::println Objects.requireNonNull 用于显示等价性。规范要求捕获的引用在被捕获时立即测试null,就像使用es::shutDown,而不是将其推迟到调用Closeable.close() 的时刻。无论哪种情况,它都会在运行时失败。 不,不,这不是编译时检查(尽管您的 IDE 可能会警告您)。我所说的是,当 进入 try 块并执行 Closeable closeable = es::shutdown 时它将失败,而不是等待离开 try 块并尝试调用 close() 的那一刻,这将调用shutdown。这与ExecutorService es = null; try(Closeable closeable = () -> es.shutdown()) 不同,后者将在退出时失败。 【参考方案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) 
    // ...

【讨论】:

你能否检查我的更新我的意思是如果 es 不是 evetively 或 final 它不应该编译但方法参考允许编译 是的,但它失败了,因为你捕获了null

以上是关于双冒号运算符 (::) 和(有效)final [重复]的主要内容,如果未能解决你的问题,请参考以下文章

js 双冒号(::)运算符

js 双冒号(::)运算符

js 双冒号(::)运算符

Java 找不到带有双冒号运算符的正确重载方法

Java 8 中的 ::(双冒号)运算符

深入理解Java双冒号(::)运算符的使用