双冒号运算符 (::) 和(有效)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 forSystem.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 [重复]的主要内容,如果未能解决你的问题,请参考以下文章