等待CompletableFuture完成,然后返回其他值?

时间:2018-12-13 01:16:18

标签: java asynchronous completable-future

我有一个CompletableFuture<Void>,它调用一个我不能更改其返回类型的异步方法,或有关它的任何事情。

我要等待此方法完成(手动完成),然后返回String值,我该怎么做?

public String getServer(Player p) {
    FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
        sendUTF(p, "GetServer");
        try {
            Thread.sleep(10000); //so the future doesnt complete itself
        } catch (Exception e) {
            e.printStackTrace();
        }
    }), p.getUniqueId().toString());
    serverSet.add(f);
    String server = "";

    //server isn't final so I can't use it in the lambda
    f.getFutureVoid().whenComplete(v -> server = f.getServer()); 

    return server;
}

public class FutureServer {

    private CompletableFuture<Void> futureVoid;
    private String s;
    private String uuid;

    public FutureServer(CompletableFuture<Void> futureVoid, String uuid) {
        this.futureVoid = futureVoid;
        this.uuid = uuid;
    }

    public String getUuid() {
        return uuid;
    }

    public CompletableFuture<Void> getFutureVoid() {
        return futureVoid;
    }

    public boolean hasServer() {
        return s != null;
    }

    public void setServer(String s) {
        this.s = s;
    }

    public String getServer() {
        return s;
    }
}

我想将字符串设置为等于FutureServer#getServer()(自己的方法),但是我需要等到CompletableFuture<Void>完成。我该怎么办?

这是被称为异步且不可更改的方法...我使用的异步调用此另一方法的方法是sendUTF()

@Override
public void onPluginMessageReceived(String s, Player p, byte[] bytes) {
    if (!s.equals("BungeeCord")) return;

    ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
    String subChannel = in.readUTF();

    switch(subChannel) {
        case "GetServer":
            String server = in.readUTF();
            serverSet.stream().filter(f -> f.getUuid().equals(p.getUniqueId().toString())).findFirst().ifPresent(f -> {
                f.setServer(server); //getting the string I need and placing it into this object
                f.getFutureVoid().complete(null); //completing the void future manually
            });
            break;
    }

}

2 个答案:

答案 0 :(得分:1)

您可以这样做:

final AtomicReference<String> server = new AtomicReference<>("");

f.getFutureVoid().whenComplete(v -> server.set(f.getServer())).get(/* maybe add a timeout */); 

return server.get();

答案 1 :(得分:0)

最简单的解决方案就是在未来实现join(),或者:

public String getServer(Player p) {
    FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
        sendUTF(p, "GetServer");
        try {
            Thread.sleep(10000); //so the future doesnt complete itself
        } catch (Exception e) {
            e.printStackTrace();
        }
    }), p.getUniqueId().toString());
    serverSet.add(f);

    return f.getFutureVoid().thenApply(v -> f.getServer()).join(); 
}

,可以轻松地将其转换为返回CompletableFuture<String>的方式,而无需删除.join(),或者:

public String getServer(Player p) {
    FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
        sendUTF(p, "GetServer");
        try {
            Thread.sleep(10000); //so the future doesnt complete itself
        } catch (Exception e) {
            e.printStackTrace();
        }
    }), p.getUniqueId().toString());
    serverSet.add(f);

    f.getFutureVoid().join();
    return f.getServer();
}