我正在学习Java,而且我有一个相对简单的Java程序,它从API端点获取数据,如下所示:
public class Main {
public static String getJSON(String u) {
if (u == null) throw new IllegalArgumentException("URL is null.");
try {
URL url = new URL(u);
URLConnection site = url.openConnection();
InputStream is = site.getInputStream();
Scanner scanner = new Scanner(
new BufferedInputStream(is),
"UTF-8");
String resp = "";
while (scanner.hasNextLine()) {
resp = resp + scanner.nextLine();
}
return resp;
} catch (Exception e) {
System.out.println(e);
return null;
}
}
public static void main(String[] args) {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() ->
getJSON("https://jsonplaceholder.typicode.com/posts/1")
);
cf.thenAcceptAsync(System.out::println);
// System.out.println(cf.join()); <=== Commenting out this line
}
}
我希望上面的代码可以打印出原始的JSON,但是它没有做任何事情。但是,如果我包含上面已注释掉的行,则代码可以正常工作,但它会打印两次原始JSON。
我的猜测是程序在thenAcceptAsync
有机会完成之前终止,而当包含阻塞.join()
函数时则不然。我的猜测是正确的,如果是的话,我该如何解决这个问题?
答案 0 :(得分:3)
您的主要线程没有等待服务电话的完成。您应该在CompletableFuture上调用join以等待其执行完成:
TestContext
您可以使用以下修改版本的代码检查行为(只需在VM退出时添加关闭挂钩以打印文本):
cf.thenAcceptAsync(System.out::println).join();
运行上面的代码时,输出以下内容:
Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("Shutting down")));
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println("running...");
String result = getJSON("https://jsonplaceholder.typicode.com/posts/1");
System.out.println("Completed service call");
return result;
});
cf.thenAcceptAsync(System.out::println).join();
但是,如果没有running...
Completed service call
{ "result json here"}
Shutting down
,则会立即显示以下输出:
Ë
运行...
关闭
简而言之,.join()
立即返回,主线程完成,在这种情况下,在HTTP调用完成之前。如果你之后有工作要做,那就像是:
thenAcceptAsync(System.out::println)
最终应该调用 cf = cf.thenAcceptAsync(System.out::println);
doSomethingElse();
doYetAnotherThing();
cf.join()
,以防止过早终止VM,或者在必要时等待结果准备好。
答案 1 :(得分:1)
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;
import java.util.concurrent.CompletableFuture;
public class Main {
public static String getJSON(String u) {
if (u == null) throw new IllegalArgumentException("URL is null.");
try {
URL url = new URL(u);
URLConnection site = url.openConnection();
InputStream is = site.getInputStream();
Scanner scanner = new Scanner(
new BufferedInputStream(is),
"UTF-8");
String resp = "";
while (scanner.hasNextLine()) {
resp = resp + scanner.nextLine();
}
return resp;
} catch (Exception e) {
System.out.println(e);
return null;
}
}
public static void main(String[] args) {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() ->
getJSON("https://jsonplaceholder.typicode.com/posts/1")
);
//cf.thenAcceptAsync(System.out::println);
System.out.println(cf.join());
}
}
只需评论并在下面打开它就会打印一行