如何访问 Thread lambda 中的非最终变量?
How can I access a non-final variable in a Thread lambda?
我有一个自定义对象需要在 Thread lambda 中修改,因为我需要执行一个操作并为其分配一些值。
问题是当我在 Thread() 中声明变量时,它无法从封闭函数返回。然后,如果我试图使它成为一个全局变量并在线程内为其分配一些值,则无法完成,因为 lambda 只允许在其中使用 final 或有效的 final 变量。
什么是 workaround/solution?
// 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
}
所以我想在方法本身内部声明 response
,但由于只有 final 变量可用,所以我不能这样做。
// 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;
假设这是允许的?您希望它达到什么效果 return?
// 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(endpoint);
语句会在 return response;
语句之前执行。事实上,它可能 不会 直到一段时间后才被执行。
你真正想要的是;
- 你的
get(endpoint)
方法到 return 一个 可变 对象,并且
- 调用者等待直到新值被其他线程存储到可变对象中的方法。
Java 标准库为这种可变对象定义了一个接口:它叫做 java.util.concurrent.Future
。 Future
有一个 get()
方法,如有必要,该方法将等待,直到其他线程通过给它一个值 完成 Future ,然后 get()
将 return 值。
最简单的使用方法是通过 CompletableFuture
class:
import java.util.concurrent.Future;
import java.util.concurrent.CompletableFuture;
...
public Future<Response> get(String endpoint) {
return CompletableFuture.supplyAsync(() -> {
return OffredUtil.makeGetRequest(endpoint);
});
}
调用此 get(endpoint)
方法会将任务提交给 built-in 线程池,该线程池将执行给定的 lambda 表达式,然后它将 return 一个 Future
将由任务完成。
如果 lambda 产生一个值,那么它将成为 Future
的值。如果 lambda 抛出一个异常,那么就会被捕获,异常对象会被存储在 Future
get(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());
}
我有一个自定义对象需要在 Thread lambda 中修改,因为我需要执行一个操作并为其分配一些值。
问题是当我在 Thread() 中声明变量时,它无法从封闭函数返回。然后,如果我试图使它成为一个全局变量并在线程内为其分配一些值,则无法完成,因为 lambda 只允许在其中使用 final 或有效的 final 变量。
什么是 workaround/solution?
// 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
}
所以我想在方法本身内部声明 response
,但由于只有 final 变量可用,所以我不能这样做。
// 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;
假设这是允许的?您希望它达到什么效果 return?
// 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(endpoint);
语句会在 return response;
语句之前执行。事实上,它可能 不会 直到一段时间后才被执行。
你真正想要的是;
- 你的
get(endpoint)
方法到 return 一个 可变 对象,并且 - 调用者等待直到新值被其他线程存储到可变对象中的方法。
Java 标准库为这种可变对象定义了一个接口:它叫做 java.util.concurrent.Future
。 Future
有一个 get()
方法,如有必要,该方法将等待,直到其他线程通过给它一个值 完成 Future ,然后 get()
将 return 值。
最简单的使用方法是通过 CompletableFuture
class:
import java.util.concurrent.Future;
import java.util.concurrent.CompletableFuture;
...
public Future<Response> get(String endpoint) {
return CompletableFuture.supplyAsync(() -> {
return OffredUtil.makeGetRequest(endpoint);
});
}
调用此 get(endpoint)
方法会将任务提交给 built-in 线程池,该线程池将执行给定的 lambda 表达式,然后它将 return 一个 Future
将由任务完成。
如果 lambda 产生一个值,那么它将成为 Future
的值。如果 lambda 抛出一个异常,那么就会被捕获,异常对象会被存储在 Future
get(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());
}