我的异步通话怎么了?

时间:2018-07-21 07:06:11

标签: java asynchronous callback asynccallback

我有这段代码:

public static void main(String[] args) throws UnirestException {
    ArrayList<Stock> listStock 
             = getAllAvailableStocks("https://api.iextrading.com/1.0/ref-data/symbols");
    //doing more actions after the one before, using the data from the listStock etc.
}


private static ArrayList<Stock> getAllAvailableStocks(String url) {
    ArrayList<Stock> stocks = new ArrayList<Stock>();
    Future<HttpResponse<JsonNode>> future = Unirest.get(url)
              .header("accept", "application/json")
              .asJsonAsync(new Callback<JsonNode>() {
                public void failed(UnirestException e) {
                    System.out.println("The request has failed");
                }

                public void completed(HttpResponse<JsonNode> response) {
                     ObjectMapper objectMapper = new ObjectMapper();
                    try {
                        listStock = objectMapper.readValue(response.getRawBody(), new TypeReference<List<Stock>>(){});
                    } catch (Exception e) {
                        System.out.println("all is fucked");
                    }   
                    return listStock;
                }

                public void cancelled() {
                    System.out.println("The request has been cancelled");
                }

            });
}

我是Java的新手,我想执行以下操作:

1)我想进行异步调用,以获取并提取股票清单,仅在请求完成后,我才想在main方法中进行下一步操作。

2)如何从构建的方法中提取数据,以便可以在方法之外使用数据?

3)如果我需要执行以下操作:

getAllAvailableStocks("https://api.iextrading.com/1.0/ref-data/symbols",new Callback<JsonNode>() {
            public void failed(UnirestException e) {
                System.out.println("The request has failed");
            }

        public void completed(HttpResponse<JsonNode> response) {
             ArrayList<Stock> listStock = new ArrayList<Stock>();
             ObjectMapper objectMapper = new ObjectMapper();
             int code = response.getStatus();
             System.out.println(code);
            try {
                listStock = objectMapper.readValue(response.getRawBody(), new TypeReference<List<Stock>>(){});
            } catch (Exception e) {

            }   
            System.out.println(listStock);
        }

        public void cancelled() {
            System.out.println("The request has been cancelled");
        }

    });
}



private static Future<HttpResponse<JsonNode>> getAllAvailableStocks(String url,Callback<JsonNode> cb) {
    return Unirest.get(url)
              .header("accept", "application/json")
              .asJsonAsync(cb);
}

或者类似的东西,它会使代码变得可怕,当我想在之后执行更多异步请求时,在这里有一个回调地狱,有什么办法可以避免它?我在这里有什么选择?

1 个答案:

答案 0 :(得分:1)

我认为您混淆了异步同步

如果您

  

想要进行异步调用以获取并提取股票清单,仅在请求完成后,我才想在main方法中进行下一步操作

然后您实际上要执行同步调用。

异步调用将是执行请求,然后执行其他操作(与请求无关),并在将来的某个时候获得请求的结果并进行处理。 / p>

要执行 synchronous 调用(这可能是您想要的),请尝试调整代码,如下所示:

private static ArrayList<Stock> getAllAvailableStocks(String url) {
    ArrayList<Stock> stocks = new ArrayList<Stock>();
    Future<HttpResponse<JsonNode>> future = Unirest.get(url)
              .header("accept", "application/json")
              .asJsonAsync(new Callback<JsonNode>() {
                public void failed(UnirestException e) {
                    System.out.println("The request has failed");
                }

                public void completed(HttpResponse<JsonNode> response) {
                    System.out.println("The request succeeded");
                }

                public void cancelled() {
                    System.out.println("The request has been cancelled");
                }
            });

    HttpResponse<JsonNode> response = future.get(); // NOTE: This call is blocking until the request is finished
    if (response != null && response.getStatus() == 200) {
        JsonNode body = response.getBody();
        // TODO Parse body and add items to `stocks`
    }
    return stocks;
}

这种方法可以像这样使用:

ArrayList<Stock> stocks = getAllAvailableStocks(...);
stocks.forEach(x -> System.out.println(x));

修改

如果要异步处理结果而不提供回调,则可以使用CompletableFuture。将以下代码段作为不会处理失败呼叫的起点。

private static CompletableFuture<ArrayList<Stock>> getAllAvailableStocks(String url) {
    CompletableFuture<ArrayList<Stock>> result = new CompletableFuture<>();
    Future<HttpResponse<JsonNode>> future = Unirest.get(url)
              .header("accept", "application/json")
              .asJsonAsync(new Callback<JsonNode>() {
                public void failed(UnirestException e) {
                    System.out.println("The request has failed");
                }

                public void completed(HttpResponse<JsonNode> response) {
                    System.out.println("The request succeeded");
                    ArrayList<Stock> stocks = new ArrayList<Stock>();
                    if (response != null && response.getStatus() == 200) {
                        JsonNode body = response.getBody();
                        // TODO Parse body and add items to `stocks`
                    }
                    result.complete(stocks);
                }

                public void cancelled() {
                    System.out.println("The request has been cancelled");
                }
            });

    return result;
}

该方法可以如下使用:

CompletableFuture<ArrayList<Stock>> stocksFuture = getAllAvailableStocks(...);
stocksFuture.thenAccept((stocks) -> {
    // NOTE: This will be called after and only if the request succeeded
    stocks.forEach(x -> System.out.println(x));
});

System.out.println("This is probably executed before the above request finished.");

Thread.sleep(10000); // If you are calling from your `main` method: Prevent JVM exit