我正在尝试从我的CompletableFuture
返回一个列表:
public List<Provider> get() {
CompletableFuture<List<Provider>> providersResponse = getSomeData();
return providersResponse.thenAccept((List<Provider> providers) -> {
return providers;
});
}
它失败并出现“意外返回类型。如何以异步方式返回结果?
答案 0 :(得分:6)
你的目标存在根本矛盾。您只能使用get()
返回完整的,可直接使用的列表或“以异步方式返回结果”。
如果方法List<Provider> get()
应该返回一个List
,调用者可以无限制地使用它,它就不能保持异步操作,因为操作必须在{{{{}时完成1}}返回。这可以像调用get()
一样简单,等待完成并获得结果:
join()
或只是
public List<Provider> get() {
CompletableFuture<List<Provider>> providersResponse = getSomeData();
return providersResponse.join();
}
这有效地将public List<Provider> get() {
return getSomeData().join();
}
的潜在异步操作转换为同步操作。
This answer,使用
getSomeData()
不等待操作完成,但在安排public List<Provider> get() {
List<Provider> providers = new ArrayList<>();
CompletableFuture<List<Provider>> providersResponse = getSomeData();
providersResponse.thenAccept(providers::addAll);
return providers;
}
操作后返回一个新的ArrayList
,该操作的执行完全不受此方法的控制。
这是一个异步操作,因此当addAll
返回时,get()
可能仍为空,但稍后会被任意线程更新。由于List
不是线程安全的,因此感知状态不必是空的或完成的,它可以是任意的中间状态,甚至不需要是一致的。在使用该代码时,应为奇怪的异常,不可能看的情况或其他意外做好准备。
当您使用线程安全ArrayList
实现修复该代码时,仍然会遇到以下问题:返回的List
在查询时可能为空,并且在任何时间点之外的任意时间点填充来电者的控制权。这是不可修复的,正如开头所说,这是想要异步操作但返回List
的基本问题。
List
已经是潜在异步操作的封装,因此如果您希望操作保持异步,只需将CompletableFuture
返回给调用者,以便获得控制权。否则,如果您希望调用者接收可以无限制使用的CompletableFuture<List<Provider>>
,请在返回结果之前等待完成,例如通过List
。
答案 1 :(得分:1)
试试这个:
public List<Provider> get() {
List<Provider> providers = Collections.synchronizedList(new ArrayList<>());
CompletableFuture<List<Provider>> providersResponse = getSomeData();
providersResponse.thenAccept(providers::addAll);
return providers;
}
答案 2 :(得分:0)
试试这个:
[('Date', 'Wed, 19 Apr 2017 13:48:41 GMT'),
('Content-Type', 'application/octet-stream; charset=UTF-8'),
('Content-Disposition', 'attachment;filename=filename.csv.gz'),
('Content-Length', '2117014'),
('Server', 'Jetty(9.2.17.v20160517)')]