Java Language
CompletableFuture
Sök…
Introduktion
CompletableFuture är en klass som läggs till Java SE 8 som implementerar Future-gränssnittet från Java SE 5. Förutom att stödja Future-gränssnittet lägger det till många metoder som tillåter asynkron återuppringning när framtiden är klar.
Konvertera blockeringsmetod till asynkron
Följande metod tar en sekund eller två beroende på din anslutning för att hämta en webbsida och räkna textlängden. Oavsett vilken tråd som kallas kommer den att blockeras under den perioden. Dessutom återkallar det ett undantag som är användbart senare.
public static long blockingGetWebPageLength(String urlString) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new URL(urlString).openConnection().getInputStream()))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString().length();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
Detta konverterar det till en metod som omedelbart kommer att återgå genom att flytta blockeringsmetodens samtal till en annan tråd. Som standard kör metoden supplyAsync leverantören i den gemensamma poolen. För en blockeringsmetod är detta förmodligen inte ett bra val eftersom man kan ta ut trådarna i den poolen och det är därför jag har lagt till den valfria serviceparametern.
static private ExecutorService service = Executors.newCachedThreadPool();
static public CompletableFuture<Long> asyncGetWebPageLength(String url) {
return CompletableFuture.supplyAsync(() -> blockingGetWebPageLength(url), service);
}
För att använda funktionen på asynkron sätt bör man använda på de metoder som accepterar en lamda som ska kallas med resultatet av leverantören när den är klar så som dåAccept. Det är också viktigt att använda exceptionellt eller hantera metod för att logga alla undantag som kan ha hänt.
public static void main(String[] args) {
asyncGetWebPageLength("https://stackoverflow.com/")
.thenAccept(l -> {
System.out.println("Stack Overflow returned " + l);
})
.exceptionally((Throwable throwable) -> {
Logger.getLogger("myclass").log(Level.SEVERE, "", throwable);
return null;
});
}
Enkelt exempel på CompletableFuture
I exemplet nedan calculateShippingPrice
metoden calculShippingPrice fraktkostnader, vilket tar lite behandlingstid. I ett verkligt exempel skulle detta t.ex. vara att kontakta en annan server som returnerar priset baserat på produktens vikt och leveransmetoden.
Genom att modellera detta på ett asynkiskt sätt via CompletableFuture
, kan vi fortsätta olika arbeten i metoden (dvs. beräkna förpackningskostnader).
public static void main(String[] args) {
int price = 15; // Let's keep it simple and work with whole number prices here
int weightInGrams = 900;
calculateShippingPrice(weightInGrams) // Here, we get the future
.thenAccept(shippingPrice -> { // And then immediately work on it!
// This fluent style is very useful for keeping it concise
System.out.println("Your total price is: " + (price + shippingPrice));
});
System.out.println("Please stand by. We are calculating your total price.");
}
public static CompletableFuture<Integer> calculateShippingPrice(int weightInGrams) {
return CompletableFuture.supplyAsync(() -> {
// supplyAsync is a factory method that turns a given
// Supplier<U> into a CompletableFuture<U>
// Let's just say each 200 grams is a new dollar on your shipping costs
int shippingCosts = weightInGrams / 200;
try {
Thread.sleep(2000L); // Now let's simulate some waiting time...
} catch(InterruptedException e) { /* We can safely ignore that */ }
return shippingCosts; // And send the costs back!
});
}