Java Language
CompletableFuture
Zoeken…
Invoering
CompletableFuture is een klasse toegevoegd aan Java SE 8 die de Future-interface van Java SE 5 implementeert. Naast de ondersteuning van de Future-interface voegt het vele methoden toe die asynchrone callback toestaan wanneer de toekomst is voltooid.
Converteer blokkeermethode naar asynchonous
De volgende methode duurt een seconde of twee, afhankelijk van uw verbinding om een webpagina op te halen en de tekstlengte te tellen. Welke thread het ook zal blokkeren voor die periode. Ook wordt een uitzondering opnieuw gegenereerd die later handig is.
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);
}
}
Dit converteert het naar een methode die onmiddellijk zal terugkeren door de aanroep van de blokkeermethode naar een andere thread te verplaatsen. Standaard voert de methode supplyAsync de leverancier uit op de gemeenschappelijke pool. Voor een blokkeermethode is dit waarschijnlijk geen goede keuze, omdat men de threads in die pool kan uitputten, daarom heb ik de optionele serviceparameter toegevoegd.
static private ExecutorService service = Executors.newCachedThreadPool();
static public CompletableFuture<Long> asyncGetWebPageLength(String url) {
return CompletableFuture.supplyAsync(() -> blockingGetWebPageLength(url), service);
}
Om de functie op asynchrone wijze te gebruiken, moet men een van de methoden gebruiken die een te accepteren lamda accepteert met het resultaat van de leverancier wanneer deze is voltooid, zoals thenAccept. Het is ook belangrijk om uitzonderlijk te gebruiken of de methode af te handelen om eventuele uitzonderingen te registreren.
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;
});
}
Eenvoudig voorbeeld van CompletableFuture
In het onderstaande voorbeeld calculateShippingPrice
methode calculShippingPrice verzendkosten, wat enige verwerkingstijd kost. In een praktijkvoorbeeld zou dit bijvoorbeeld contact opnemen met een andere server die de prijs retourneert op basis van het gewicht van het product en de verzendmethode.
Door dit asynchroon te modelleren via CompletableFuture
, kunnen we doorgaan met ander werk in de methode (dwz de verpakkingskosten berekenen).
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!
});
}