java 8 completablefutures imagestreamgang example (part 2)schmidt/cs891f/2018-pdfs/...asynchronously...

Post on 15-Jul-2020

6 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Java 8 CompletableFutures

ImageStreamGang Example (Part 2)

Douglas C. Schmidtd.schmidt@vanderbilt.edu

www.dre.vanderbilt.edu/~schmidt

Professor of Computer Science

Institute for Software

Integrated Systems

Vanderbilt University

Nashville, Tennessee, USA

2

Learning Objectives in this Part of the Lesson• Understand the design of the

Java 8 completable futureversion of ImageStreamGang

• Know how to apply completablefutures to ImageStreamGang

SocketSocket

List of URLs to Download

List of Filters to Apply

Persistent

Data Store

3

Learning Objectives in this Part of the Lesson• Understand the design of the

Java 8 completable futureversion of ImageStreamGang

• Know how to apply completablefutures to ImageStreamGang, e.g.

• Factory methods & completionstage methods

4

Applying CompletableFutures to ImageStreamGang

5

• Focus on processStream()

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

...See imagestreamgang/streams/ImageStreamCompletableFuture1.java

6

• Focus on processStream()

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Get the list of URLs input by the user

7

• Focus on processStream()

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Combines a Java 8 sequential stream with

completable futures

8

• Focus on processStream()

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Factory method creates a stream of URLs

9

• Focus on processStream()

• This implementation is verydifferent from parallel streams

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Asynchronously check if images are already cached locally

map() converts a stream of URLs to a stream of futures to optional URLs

10

• Focus on processStream()

• This implementation is verydifferent from parallel streams

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Asynchronously download an image at each given URL

map() converts URL futures (completed) to image futures (downloading)

11

• Focus on processStream()

• This implementation is verydifferent from parallel streams

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Asynchronously filter & store downloaded images on the local file system

flatMap() converts image futures (completed) to filtered image futures (xforming/storing)

12

• Focus on processStream()

• This implementation is verydifferent from parallel streams

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Create a future used to wait for all async operations associated w/the

stream of futures to complete

See next part on “arbitrary-arity” methods in CompletableFuture

13

• Focus on processStream()

• This implementation is verydifferent from parallel streams

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

This lambda logs the results when all the futures in stream

complete their async processing

14

• Focus on processStream()

• This implementation is verydifferent from parallel streams

Applying Completable Futures to ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Wait until all the images have been downloaded,

processed, & stored

This is the one & only call to join() in this implementation strategy

15

Applying Factory Methods in ImageStreamGang

16

• Initiate an async check to see if images are cached locally

Applying Factory Methods in ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

map() calls the behavior checkUrlCachedAsync()

17

• Initiate an async check to see if images are cached locally

Applying Factory Methods in ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Asynchronously check if a URL is already downloaded

18

• Initiate an async check to see if images are cached locally

Applying Factory Methods in ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Returns a stream of completablefutures to optional URLs, which have a value if the URL is not

cached or are empty if it is cached

Later behaviors simply ignore “empty” optional URL values

19

• checkUrlCachedAsync() uses the supplyAsync() factory method internally

Applying Factory Methods in ImageStreamGang

See imagestreamgang/streams/ImageStreamCompletableFutureBase.java

CompletableFuture<Optional<URL>> checkUrlCachedAsync(URL url) {

return CompletableFuture

.supplyAsync(() ->

Optional.ofNullable(urlCached(url)

? null

: url),

getExecutor());

}

20

• checkUrlCachedAsync() uses the supplyAsync() factory method internally

Applying Factory Methods in ImageStreamGang

CompletableFuture<Optional<URL>> checkUrlCachedAsync(URL url) {

return CompletableFuture

.supplyAsync(() ->

Optional.ofNullable(urlCached(url)

? null

: url),

getExecutor());

}

This factory method registers an action that runs asynchronously

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#supplyAsync

21

void initiateStream() {

// Set the executor to the common fork-join pool.

setExecutor(ForkJoinPool.commonPool());

...

}

• checkUrlCachedAsync() uses the supplyAsync() factory method internally

Applying Factory Methods in ImageStreamGang

CompletableFuture<Optional<URL>> checkUrlCachedAsync(URL url) {

return CompletableFuture

.supplyAsync(() ->

Optional.ofNullable(urlCached(url)

? null

: url),

getExecutor());

}

supplyAsync() runs action in a worker thread from the common fork-join pool

See dzone.com/articles/common-fork-join-pool-and-streams

22

• checkUrlCachedAsync() uses the supplyAsync() factory method internally

Applying Factory Methods in ImageStreamGang

CompletableFuture<Optional<URL>> checkUrlCachedAsync(URL url) {

return CompletableFuture

.supplyAsync(() ->

Optional.ofNullable(urlCached(url)

? null

: url),

getExecutor());

}

ofNullable() is a factory method that returns a completable future to an optional URL, which has a value if the URL is not cached or is empty if it is cached

See docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ofNullable

23

• checkUrlCachedAsync() uses the supplyAsync() factory method internally

Applying Factory Methods in ImageStreamGang

See imagestreamgang/streams/ImageStreamGang.java

boolean urlCached(URL url) {

return mFilters.stream()

.filter(filter -> urlCached(url, filter.getName()))

.count() > 0;

}

CompletableFuture<Optional<URL>> checkUrlCachedAsync(URL url) {

return CompletableFuture

.supplyAsync(() ->

Optional.ofNullable(urlCached(url)

? null

: url),

getExecutor());

}

Returns true if the image has already been filtered before

24

• checkUrlCachedAsync() uses the supplyAsync() factory method internally

Applying Factory Methods in ImageStreamGang

See imagestreamgang/streams/ImageStreamGang.java

CompletableFuture<Optional<URL>> checkUrlCachedAsync(URL url) {

return CompletableFuture

.supplyAsync(() ->

Optional.ofNullable(urlCached(url)

? null

: url),

getExecutor());

}

boolean urlCached(URL url, String filterName) {

File file = new File(getPath(), filterName);

File imageFile = new File(file, getNameForUrl(url));

return !imageFile.createNewFile();

}

Returns true if image file already exists

25

• checkUrlCachedAsync() uses the supplyAsync() factory method internally

Applying Factory Methods in ImageStreamGang

CompletableFuture<Optional<URL>> checkUrlCachedAsync(URL url) {

return CompletableFuture

.supplyAsync(() ->

Optional.ofNullable(urlCached(url)

? null

: url),

getExecutor());

}

There are clearly better ways of implementing an image cache!

boolean urlCached(URL url, String filterName) {

File file = new File(getPath(), filterName);

File imageFile = new File(file, getNameForUrl(url));

return !imageFile.createNewFile();

}

26

Applying Completion Stage Methods in ImageStreamGang

27

• Asynchronously download an image at each given URL

Applying Completion Stage Methods in ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

map() calls the behaviordownloadImageAsync()

28

• Asynchronously download an image at each given URL

Applying Completion Stage Methods in ImageStreamGang

Asynchronously downloads an image & stores it in memory

void processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Later behaviors simply ignore “empty” optional images

29

• Asynchronously download an image at each given URL

Applying Completion Stage Methods in ImageStreamGang

Returns a stream of futures to optional images, which have a value if the image is being downloaded or

are empty if it is already cached

void processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

30

• downloadImageAsync() uses the thenApplyAsync() method internally

CompletableFuture<Optional<Image>> downloadImageAsync

(CompletableFuture<Optional<URL>> urlFuture) {

return urlFuture

.thenApplyAsync(urlOpt ->

urlOpt

.map(this::blockingDownload),

getExecutor());

}

Asynchronously download image when future completes

Applying Completion Stage Methods in ImageStreamGang

See imagestreamgang/streams/ImageStreamCompletableFuture1.java

31

Applying Completion Stage Methods in ImageStreamGang• downloadImageAsync() uses the thenApplyAsync() method internally

CompletableFuture<Optional<Image>> downloadImageAsync

(CompletableFuture<Optional<URL>> urlFuture) {

return urlFuture

.thenApplyAsync(urlOpt ->

urlOpt

.map(this::blockingDownload),

getExecutor());

}

This completion stage method registers an action that’s not executed immediately, but only after the future completes

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenApplyAsync

32

Applying Completion Stage Methods in ImageStreamGang• downloadImageAsync() uses the thenApplyAsync() method internally

CompletableFuture<Optional<Image>> downloadImageAsync

(CompletableFuture<Optional<URL>> urlFuture) {

return urlFuture

.thenApplyAsync(urlOpt ->

urlOpt

.map(this::blockingDownload),

getExecutor());

}

If a url is present when the future completes download it & return an optional describing the result; otherwise return an empty optional

See docs.oracle.com/javase/8/docs/api/java/util/Optional.html#map

33

Asynchronously run blockingDownload() if the url is non-empty

Applying Completion Stage Methods in ImageStreamGang• downloadImageAsync() uses the thenApplyAsync() method internally

CompletableFuture<Optional<Image>> downloadImageAsync

(CompletableFuture<Optional<URL>> urlFuture) {

return urlFuture

.thenApplyAsync(urlOpt ->

urlOpt

.map(this::blockingDownload),

getExecutor());

}

34You could also use a ThreadPoolExecutor (fixed-size or cached)

Applying Completion Stage Methods in ImageStreamGang

CompletableFuture<Optional<Image>> downloadImageAsync

(CompletableFuture<Optional<URL>> urlFuture) {

return urlFuture

.thenApplyAsync(urlOpt ->

urlOpt

.map(this::blockingDownload),

getExecutor());

}

• downloadImageAsync() uses the thenApplyAsync() method internally

Use the common fork-join pool & its ManagedBlocker mechanism

35

Applying Completion Stage Methods in ImageStreamGang

Image blockingDownload(URL url) {

return BlockingTask

.callInManagedBlock(() ->

downloadImage(url));

}

• downloadImageAsync() uses the thenApplyAsync() method internally

See imagestreamgang/streams/ImageStreamGang.java

Transform a URL into an Image by downloading each image via the URL

36

Applying Completion Stage Methods in ImageStreamGang

Image blockingDownload(URL url) {

return BlockingTask

.callInManagedBlock(() ->

downloadImage(url));

}

• downloadImageAsync() uses the thenApplyAsync() method internally

BlockingTask.callInManagedBlock() wraps the ManagedBlocker interface, which expands the common fork/join thread pool to handle the blocking image download

See imagestreamgang/utils/BlockingTask.java

37

Returns a future to an image that completes when the image is finished downloading

Applying Completion Stage Methods in ImageStreamGang

CompletableFuture<Optional<Image>> downloadImageAsync

(CompletableFuture<Optional<URL>> urlFuture) {

return urlFuture

.thenApplyAsync(urlOpt ->

urlOpt

.map(this::blockingDownload),

getExecutor());

}

• downloadImageAsync() uses the thenApplyAsync() method internally

38

• Asynchronously filter & store downloaded images on the local file system

Applying Completion Stage Methods in ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

flatMap() calls behavior applyFiltersAsync()

39

• Asynchronously filter & store downloaded images on the local file system

Applying Completion Stage Methods in ImageStreamGang

Asynchronous filter images & store them into files

void processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Later operations ignore “empty” optional images

40

• Asynchronously filter & store downloaded images on the local file system

Applying Completion Stage Methods in ImageStreamGang

“Flatten” all filtered/stored images into a single output stream

void processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

See docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#flatMap

41

• Asynchronously filter & store downloaded images on the local file system

Applying Completion Stage Methods in ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

Returns a stream of futures to optional images, which have a

value if the image is being filtered or are empty if it is already cached

42

• applyFiltersAsync() uses the thenApplyAsync() method internally

See imagestreamgang/streams/ImageStreamCompletableFuture1.java

Applying Completion Stage Methods in ImageStreamGang

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));

}

Asynchronously filter images & then store them into files

43

Applying Completion Stage Methods in ImageStreamGang• applyFiltersAsync() uses the thenApplyAsync() method internally

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));

}

Convert the list of filters into a stream

44

Applying Completion Stage Methods in ImageStreamGang

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));

}

• applyFiltersAsync() uses the thenApplyAsync() method internally

Asynchronously apply a filter action after the previous stage completes

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenApplyAsync

45

Applying Completion Stage Methods in ImageStreamGang

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));

}

• applyFiltersAsync() uses the thenApplyAsync() method internally

This completion stage method registers an action that’s not executed immediately, but runs only after the future completes

46

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));}

If an image is present then perform the action & return optional containing result;

otherwise return an empty optional

Applying Completion Stage Methods in ImageStreamGang• applyFiltersAsync() uses the thenApplyAsync() method internally

See docs.oracle.com/javase/8/docs/api/java/util/Optional.html#map

47

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));}

If an image is non-null then asynchronously filter the image & store it in an output file

Applying Completion Stage Methods in ImageStreamGang• applyFiltersAsync() uses the thenApplyAsync() method internally

48

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));}

thenApplyAsync() runs the actions in a thread from the common fork-join pool

Applying Completion Stage Methods in ImageStreamGang• applyFiltersAsync() uses the thenApplyAsync() method internally

49

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));

}

It also returns a new completable future that will trigger when the image has been filtered/stored

Applying Completion Stage Methods in ImageStreamGang• applyFiltersAsync() uses the thenApplyAsync() method internally

50

Applying Completion Stage Methods in ImageStreamGang• applyFiltersAsync() uses the thenApplyAsync() method internally

Stream<CompletableFuture<Optional<Image>>> applyFiltersAsync

(CompletableFuture<Optional<Image>> imageFuture) {

return mFilters

.stream()

.map(filter -> imageFuture

.thenApplyAsync(imageOpt ->

imageOpt

.map(image ->

makeFilterDecoratorWithImage

(filter, image).run()),

getExecutor()));

}

applyFiltersAsync() returns a stream of completable

futures to optional images

51

• Asynchronously filter & store downloaded images on the local file system

Applying Completion Stage Methods in ImageStreamGangvoid processStream() {

List<URL> urls = getInput();

CompletableFuture<Stream<Image>>

resultsFuture = urls

.stream()

.map(this::checkUrlCachedAsync)

.map(this::downloadImageAsync)

.flatMap(this::applyFiltersAsync)

.collect(toFuture())

.thenApply(stream ->

log(stream.flatMap

(Optional::stream),

urls.size()))

.join();

flatMap() merges the stream of futures returned by applyFilters

Async() into a single stream

This stream is processed by collect(), as discussed in the next part of the lesson

52

End of Java 8 CompletableFutures ImageStreamGang

Example (Part 2)

top related