Lab 08 - Exercise 7, Asynchronous Programming

Exercise 7 Review

For this part, the implementation of each method can be found in Exercise 7 — Infinite List.

head() — Retrieve the Head Safely

Write the naive if-else statement first, then convert it into a one-line.

tail() — Retrieve the Tail

We want the tail, but we use the head to do the if-else, so a mapping is needed.

map() — How to map the List Efficiently

Use the succinct way, your this.head and this.tail are already Lazy, can just call the method.

To avoid stack overflow, try not use this.head() and this.tail().

forEach()

Traverse through the list by shrinking the tail. This is awesome!

public void forEach(Consumer<? super T> action) {
    InfiniteList<T> currList = this;
    while (!currList.isSentinel()) {
        // Consume the head
        currList.head.get().ifPresent(action); // Maybe<T>::ifPresent
        // Shrink the sublist
        currList = currList.tail.get();
    }
}

reduce()

  1. Traverse through the list

  2. If the head exists, do the function you want

General advice in writing such one-line code

  1. Start by considering the condition to use (In this exercise, we always start with this.head.get().

  2. End by using orElse()/orElseGet().

    1. Anything between the start and the end is your if branch.

    2. The "placeholder" in your end is the else branch.

Asynchronous Programming

CompletableFuture<T>

It can be interpreted as a task which will return a result of type T when completed.

Common Completable Future methods

  1. CF(f).then(g) means: start g only after f has been completed.

    1. Examples: thenRun, thenCombine, thenApply

  2. static CF.async(g) means: start g on a new thread

    1. Examples: supplyAsync, runAsync

  3. CF(f).then...async(g) means: start g only after f has been completed, but use a new thread.

    1. Examples: thenRunAsync, thenApplyAsync.

Difference between run and supply: run executes a void function while supply executes a function with a return value.

Last updated