Java 是否保证放置在 thenApply 中的代码始终可以访问方法参数的正确示例?

问题描述

import java.util.ArrayList;
import java.util.concurrent.CompletionStage;
import play.libs.concurrent.HttpExecutionContext;
import play.libs.ws.WSClient;
import play.libs.ws.WSRequest;
import play.libs.ws.WSResponse;

class CustomerDetailedData {
    private String id;
    private String role;
    private String customerData;
}

class CustomrestClient {
    private final WSClient ws;
    private final HttpExecutionContext httpExecutionContext;

    @javax.inject.Inject
    public CustomrestClient(final WSClient ws,final HttpExecutionContext httpExecutionContext) {
        this.ws = ws;
        this.httpExecutionContext = httpExecutionContext;
    }

    public CompletionStage<RestResponse> get(final RestMessage restMessage) {
        return ws.url(restMessage).get()
                .thenApplyAsync(wsResponse -> {
                    return new RestResponse().setMsgBody(Json.parse(wsResponse.getBody()));
                },httpExecutionContext.current());
    }
}

public class CompletionStagesExample {
    @Inject
    private CustomrestClient customrestClient;

    public static CompletionStage<CustomerDetailedData > getData(String url,String role,String id) {
        return customrestClient.get(new RestMessage(url,role,id))
                .thenApply(restResponse -> {
                    CustomerDetailedData customerData = convertToCustomerData(restResponse);
                    //here the role arg does not match response received by the get method 
                    //(we got here response for roleC,but role argument of getData method has "roleB" value on the current step)
                    customerData.setRole(role); 
                    return customerData;
                });
    }

    public static void main(String[] args) {
        final List<CompletableFuture<CustomerDetailedData>> futures = new ArrayList<>();

        futures.add(getData("url for role A","RoleA","123123a").toCompletableFuture());
        futures.add(getData("url for role B","RoleB","123123b").toCompletableFuture());
        futures.add(getData("url for role C","RoleC","123123c").toCompletableFuture());

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .thenApply(aVoid -> {
                    final List<CustomerDetailedData> detailList = new ArrayList<>();
                    futures.stream()
                            .map(CompletableFuture::join)
                            .forEach(System.out::println);
                });
    }
}

输出看起来像这样(每次都可能不同):

[id = "123123a",role = "roleB",customerData = "角色 A 的一些数据 服务器返回"],[id = "123123b",role = "roleC",customerData = "服务器返回的角色 B 的一些数据"],[id = "123123c",role = "roleA",customerData = "服务器返回的角色 C 的一些数据"]

预期结果:

[id = "123123a",role = "roleA",role = "roleC",customerData = "服务器返回的角色 C 的一些数据"]

我建议 thenApply 主体中的 getData 方法中的角色混乱(与 id 不匹配),因为 thenApply 访问了 getData 方法参数的错误示例(它们正在更改顺序,因为 thenApply 在 WSRequest 返回的另一个线程中执行)。

请看我在代码中的评论

有谁知道 Java 是否保证放置在 thenApply 中的代码始终可以访问方法参数的正确示例(在我的例子中是 getData 方法的参数)?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)