Java 如何访问线程lambda中的非final变量?
我需要在线程lambda中修改一个自定义对象,因为我需要执行一个操作并为其赋值 问题是,当我在Thread()中声明变量时,它不能从封闭函数返回。然后,如果我尝试将其设置为全局变量,并在线程内部为其分配一些值,则无法实现,因为lambdas只允许在它们内部使用final或final变量 对此,什么是解决方法/解决方案Java 如何访问线程lambda中的非final变量?,java,android,multithreading,lambda,final,Java,Android,Multithreading,Lambda,Final,我需要在线程lambda中修改一个自定义对象,因为我需要执行一个操作并为其赋值 问题是,当我在Thread()中声明变量时,它不能从封闭函数返回。然后,如果我尝试将其设置为全局变量,并在线程内部为其分配一些值,则无法实现,因为lambdas只允许在它们内部使用final或final变量 对此,什么是解决方法/解决方案 // Gives an undesired result public class MeClass { public static Response response
// Gives an undesired result
public class MeClass {
public static Response response = new Response();
// TODO: Make response specific to a method and not global
public Response get(String endpoint) {
new Thread(() -> {
try {
this.response = OffredUtil.makeGetRequest(endpoint);
} catch (Exception e) {
this.response.isException = true;
Log.d(TAG, e.getMessage());
}
}).start();
return this.response;
}
// Another method with similar function accessing response
}
所以我想在方法本身内部声明响应
,但是我不能这样做,因为只有最终变量可用
// Gives an error
public Response get(String endpoint) {
Response response = new Response();
new Thread(() -> {
try {
response = OffredUtil.makeGetRequest(endpoint);
} catch (Exception e) {
this.response.isException = true;
Log.d(TAG, e.getMessage());
}
}).start();
return response;
假设这是允许的?你希望它会回来什么
// Warning! This is an example of what *NOT* to do.
//
public Response get(String endpoint) {
Response response = new Response();
new Thread(() -> {
response = OffredUtil.makeGetRequest(endpoint);
}).start();
return response;
}
没有理由认为response=OffredUtil.makeGetRequest(端点)代码>语句将一直执行到返回响应之前代码>语句。事实上,它可能要过一段时间才会执行
你真正想要的是
- 让您的
get(endpoint)
方法返回可变对象,以及
- 调用方等待新值被其他线程存储到可变对象中的一种方法
Java标准库为这种可变对象定义了一个接口:称为。Future
有一个get()
方法,如果需要,它将等待其他线程通过给它一个值来完成Future,然后get()
将返回该值
最简单的使用方法是通过类:
即使代码可以编译,它仍然不能工作,因为返回响应代码>语句在响应=…]之前执行代码>线程的语句。重新思考您正在尝试做什么,例如,为什么您要创建一个线程在后台运行代码,但仍然希望结果立即可用?这毫无意义,是吗?如果你愿意等待完成,那么启动一个新线程有什么意义?Re,“…Android…UI可能会冻结…”唯一“冻结”UI的是,如果UI线程中调用的某个函数花费太多时间。如果对makeGetRequest(endpoint)
的直接调用冻结了UI,那么这意味着需要花费太多时间。您无法通过请求其他线程调用它然后等待结果来修复此问题。这只会花费更多的时间。你必须找到一些方法让你的UI显示你现在已经开始了makeGetRequest(…)
调用,然后当结果出来时,再次更新UI以显示它。我投票结束这个问题,因为它是一个问题。OP没有告诉我们真正的问题是什么,而是要求我们帮助实现一个糟糕的解决方案。我可以在类本身中创建一个方法,执行public Future get(String endpoint){return CompletableFuture.supplyAsync(()->{return OffredUtil.makeGetRequest(endpoint);}}
获取响应并返回该响应。反过来,我将从实际调用方调用这个新方法,并获取响应,而不需要在实际调用方中使用Future
对象?@nietzsche,我不明白你为什么要这样做。如果调用方在等待OffredUtil.makeGetRequest(endpoint)
的结果时从不做任何其他事情,那么在不同的线程中这样做又有什么意义呢?为什么不直接调用这个函数呢?我基本上只希望实际的调用方访问我的类,而不必显式地使用java.util.concurrent
对象,比如Future
。尼采,“工作”是什么意思?你的意思是,Java编译器会让你这么做吗?是的,编译器会让你这么做。你是说,打电话的人会得到预期的结果吗?是的,调用者将得到预期的结果。你的意思是,调用者会及时得到预期的结果以防止你的Android用户界面冻结吗?那就不行了,这根本没用。
import java.util.concurrent.Future;
import java.util.concurrent.CompletableFuture;
...
public Future<Response> get(String endpoint) {
return CompletableFuture.supplyAsync(() -> {
return OffredUtil.makeGetRequest(endpoint);
});
}
...
Future<Response> fr = myClassInstance.get(endpoint);
doSomethingElseConcurrentlyWithThe_makeGetRequest_call(...);
try {
Response r = fr.get();
...
} catch (Exception e) {
o.response.isException = true;
Log.d(TAG, e.getMessage());
}