I'm toying with Java8's streams and CompletableFuture
s. My pre-existing code has a class that takes a single URL and downloads it:
public class FileDownloader implements Runnable {
private URL target;
public FileDownloader(String target) {
this.target = new URL(target);
}
public void run() { /* do it */ }
}
Now, this class gets it's information from another part that emits List<String>
(a number of targets on a single host).
I've switched the surrounding code to CompletableFuture
:
public class Downloader {
public static void main(String[] args) {
List<String> hosts = fetchTargetHosts();
for (String host : hosts) {
HostDownloader worker = new HostDownloader(host);
CompletableFuture<List<String>> future =
CompletableFuture.supplyAsync(worker);
future.thenAcceptAsync((files) -> {
for (String target : files) {
new FileDownloader(target).run();
}
});
}
}
public static class HostDownloader implements Supplier<List<String>> {
/* not shown */
}
/* My implementation should either be Runnable or Consumer.
Please suggest based on a idiomatic approach to the main loop.
*/
public static class FileDownloader implements Runnable, Consumer<String> {
private String target;
public FileDownloader(String target) {
this.target = target;
}
@Override
public void run() { accept(this.target); }
@Override
public void accept(String target) {
try (Writer output = new FileWriter("/tmp/blubb")) {
output.write(new URL(target).getContent().toString());
} catch (IOException e) { /* just for demo */ }
}
}
}
Now, this doesn't feel natural. I'm producing a stream of String
s and my FileDownloader
consumes one of them at a time. Is there a readymade to enable my single value Consumer
to work with List
s or am I stuck with the for
loop here?
I know it's trivial to move the loop into the accept
and just make a Consumer<List<String>>
, that's not the point.