Java 改造 |在 lambda 表达式中调用方法的 return
Java Retrofit | Calling a method's return in a lambda expression
假设我有这段代码
public String userName(){
//Retrofit setup here
MyAPI service = retrofit.create(MyAPI.class);
Call<Users> call = service.getUser();
call.enqueue(new Callback<>() {
@Override
public void onResponse(Call<Users> call, Response<Users> response) {
//suppose I get what I want here:
response.body().getUserName();
}
@Override
public void onFailure(Call<Users> call, Throwable throwable) {
//let's just say we return "User not found" onFailure
}
});
//return statement here
}
有没有办法让 userName() 方法的 String return 语句出现在 lambda 表达式中?如果没有,我可以使用什么最简单的方法(处理量最少)来实现这一点。
Retrofit 有一个 isExecuted
调用方法,所以我考虑在 while 循环中使用它。但我只是想知道在我继续之前是否有更简单的方法来做到这一点。
谢谢。
不,那是不可能的。 enqueue
表示:异步执行此操作。就像,不是现在,以后。
你在哪里写的return statement here
?在 onResponse/onFailure 方法之前 运行s,所以你不能 'move' 那里的 return 语句 - 你的方法必须 return (因此,知道什么到 return) 在你想要 return 语句的地方甚至有 运行,这使得那不可能。
这是异步的问题API:他们很讨厌编写代码。当您说 'callback hell' 时,这就是人们在谈论的内容:您需要重新设计所有代码,以便该方法不需要 return 任何东西;相反,所有作用于 return 值的代码都需要打包在一个 lambda 中并传送到这个方法,这样你就可以调用那个 lambda(并将你想要的东西传递给 return,例如 "User not found"
,作为参数代替)。
这里可能有不使用入队的方法,我会先看一下。
当然可以。您可以创建一个适用于任何请求的通用回调 class,而不是使用匿名回调 class。
private class RetroCallback<T> implements Callback<T>{
private Consumer<Response<T>> acceptFn;
public RetroCallback(Consumer<Response<T>> acceptFn){
this.acceptFn = acceptFn;
}
@Override
public void onResponse(Call<T> call, Response<T> response) {
Log.d(LOG_TAG, "Request was: " + call.request().toString());
if(response.isSuccessful()){
Log.d(LOG_TAG, "Response SUCCESS: " + response.toString());
}else{
Log.d(LOG_TAG, "Response FAILED: " + response.toString());
//TODO: print error message or similar
return;
}
//TODO: Do stuff that you would normally do on every callback, e.g. print message of "payload DTO" or similar
// Call the lambda
if(acceptFn != null)
acceptFn.accept(response);
}
@Override
public void onFailure(Call<T> call, Throwable t) {
Log.d(LOG_TAG, "Request failed: " + call.request().toString() + " -> " + t.getMessage());
//TODO: Do your error handling
}
}
然后:
在定义回调 class 之后,您仍然需要为您的网络服务调用添加额外的包装器。这些包装器会生成一些额外的 boiletplate-code,但是我更喜欢在定义的上下文中使用样板代码,而不必在我的项目中到处处理它:
public void getAllCustomer(final Consumer<Response<List<CustomerDTO>>> onResponseFn){
customerController.getAllCustomer().enqueue(new RetroCallback(onResponseFn));
}
并使用干净的 lambda 在代码中的任何位置调用该方法:
WebController.with(getApplicationContext()).getAllCustomer(payloadDtoResponse -> {
if (payloadDtoResponse.isSuccessful()) {
//TODO: Do your stuff
}
});
或:
如果您不想添加这些包装器,只需直接调用入队方法并使用您的 lambda 传递 RetroCallback:
WebController.with(getApplicationContext()).customerController.getAllCustomer().enqueue(new RetroCallback(responseDto ->
{
//YOUR CODE...
}
));
假设我有这段代码
public String userName(){
//Retrofit setup here
MyAPI service = retrofit.create(MyAPI.class);
Call<Users> call = service.getUser();
call.enqueue(new Callback<>() {
@Override
public void onResponse(Call<Users> call, Response<Users> response) {
//suppose I get what I want here:
response.body().getUserName();
}
@Override
public void onFailure(Call<Users> call, Throwable throwable) {
//let's just say we return "User not found" onFailure
}
});
//return statement here
}
有没有办法让 userName() 方法的 String return 语句出现在 lambda 表达式中?如果没有,我可以使用什么最简单的方法(处理量最少)来实现这一点。
Retrofit 有一个 isExecuted
调用方法,所以我考虑在 while 循环中使用它。但我只是想知道在我继续之前是否有更简单的方法来做到这一点。
谢谢。
不,那是不可能的。 enqueue
表示:异步执行此操作。就像,不是现在,以后。
你在哪里写的return statement here
?在 onResponse/onFailure 方法之前 运行s,所以你不能 'move' 那里的 return 语句 - 你的方法必须 return (因此,知道什么到 return) 在你想要 return 语句的地方甚至有 运行,这使得那不可能。
这是异步的问题API:他们很讨厌编写代码。当您说 'callback hell' 时,这就是人们在谈论的内容:您需要重新设计所有代码,以便该方法不需要 return 任何东西;相反,所有作用于 return 值的代码都需要打包在一个 lambda 中并传送到这个方法,这样你就可以调用那个 lambda(并将你想要的东西传递给 return,例如 "User not found"
,作为参数代替)。
这里可能有不使用入队的方法,我会先看一下。
当然可以。您可以创建一个适用于任何请求的通用回调 class,而不是使用匿名回调 class。
private class RetroCallback<T> implements Callback<T>{
private Consumer<Response<T>> acceptFn;
public RetroCallback(Consumer<Response<T>> acceptFn){
this.acceptFn = acceptFn;
}
@Override
public void onResponse(Call<T> call, Response<T> response) {
Log.d(LOG_TAG, "Request was: " + call.request().toString());
if(response.isSuccessful()){
Log.d(LOG_TAG, "Response SUCCESS: " + response.toString());
}else{
Log.d(LOG_TAG, "Response FAILED: " + response.toString());
//TODO: print error message or similar
return;
}
//TODO: Do stuff that you would normally do on every callback, e.g. print message of "payload DTO" or similar
// Call the lambda
if(acceptFn != null)
acceptFn.accept(response);
}
@Override
public void onFailure(Call<T> call, Throwable t) {
Log.d(LOG_TAG, "Request failed: " + call.request().toString() + " -> " + t.getMessage());
//TODO: Do your error handling
}
}
然后: 在定义回调 class 之后,您仍然需要为您的网络服务调用添加额外的包装器。这些包装器会生成一些额外的 boiletplate-code,但是我更喜欢在定义的上下文中使用样板代码,而不必在我的项目中到处处理它:
public void getAllCustomer(final Consumer<Response<List<CustomerDTO>>> onResponseFn){
customerController.getAllCustomer().enqueue(new RetroCallback(onResponseFn));
}
并使用干净的 lambda 在代码中的任何位置调用该方法:
WebController.with(getApplicationContext()).getAllCustomer(payloadDtoResponse -> {
if (payloadDtoResponse.isSuccessful()) {
//TODO: Do your stuff
}
});
或: 如果您不想添加这些包装器,只需直接调用入队方法并使用您的 lambda 传递 RetroCallback:
WebController.with(getApplicationContext()).customerController.getAllCustomer().enqueue(new RetroCallback(responseDto ->
{
//YOUR CODE...
}
));