The following method will take a second or two depending on your connection to retrieve a web page and count the text length. Whatever thread calls it will block for that period of time. Also it rethrows an exception which is useful later on.
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);
}
}
This converts it to a method that will return immediately by moving the blocking method call to another thread. By default the supplyAsync method will run the supplier on the common pool. For a blocking method this is probably not a good choice since one might exhaust the threads in that pool which is why I added the optional service parameter.
static private ExecutorService service = Executors.newCachedThreadPool();
static public CompletableFuture<Long> asyncGetWebPageLength(String url) {
return CompletableFuture.supplyAsync(() -> blockingGetWebPageLength(url), service);
}
To use the function in an asynchronous fashion one should use on of the methods that accepts a lamda to be called with the result of the of the supplier when it completes such as thenAccept. Also it is important to use exceptionally or handle method to log any exceptions that might have happened.
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;
});
}