Skip to content

Commit

Permalink
Technical proofing by Jean-Francois Morin
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffmorin committed Jun 29, 2014
1 parent b040637 commit 8fe642f
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 34 deletions.
13 changes: 13 additions & 0 deletions src/main/java/lambdasinaction/appa/Author.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package lambdasinaction.appa;

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Repeatable(Authors.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {

String name();

}
11 changes: 11 additions & 0 deletions src/main/java/lambdasinaction/appa/Authors.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package lambdasinaction.appa;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {

Author[] value();

}
17 changes: 17 additions & 0 deletions src/main/java/lambdasinaction/appa/Book.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lambdasinaction.appa;

import java.util.Arrays;

@Author(name = "Raoul")
@Author(name = "Mario")
@Author(name = "Alan")
public class Book {

public static void main(String[] args) {
Author[] authors = Book.class.getAnnotationsByType(Author.class);
Arrays.asList(authors).stream().forEach(a -> {
System.out.println(a.name());
});
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package lambdasinaction.chap6;
package lambdasinaction.appc;

import java.util.*;
import java.util.concurrent.*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package lambdasinaction.chap6;
package lambdasinaction.appc;

import lambdasinaction.chap5.*;

Expand Down
12 changes: 12 additions & 0 deletions src/main/java/lambdasinaction/appd/InnerClass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package lambdasinaction.appd;

import java.util.function.Function;

public class InnerClass {
Function<Object, String> f = new Function<Object, String>() {
@Override
public String apply(Object obj) {
return obj.toString();
}
};
}
7 changes: 7 additions & 0 deletions src/main/java/lambdasinaction/appd/Lambda.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package lambdasinaction.appd;

import java.util.function.Function;

public class Lambda {
Function<Object, String> f = obj -> obj.toString();
}
163 changes: 163 additions & 0 deletions src/main/java/lambdasinaction/chap10/v1/BestPriceFinder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package lambdasinaction.chap10.v1;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import lambdasinaction.chap10.ExchangeService;
import lambdasinaction.chap10.ExchangeService.Money;

public class BestPriceFinder {

private final List<Shop> shops = Arrays.asList(new Shop("BestPrice"),
new Shop("LetsSaveBig"),
new Shop("MyFavoriteShop"),
new Shop("BuyItAll")/*,
new Shop("ShopEasy")*/);

private final Executor executor = Executors.newFixedThreadPool(shops.size(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
});

public List<String> findPricesSequential(String product) {
return shops.stream()
.map(shop -> shop.getName() + " price is " + shop.getPrice(product))
.collect(Collectors.toList());
}

public List<String> findPricesParallel(String product) {
return shops.parallelStream()
.map(shop -> shop.getName() + " price is " + shop.getPrice(product))
.collect(Collectors.toList());
}

public List<String> findPricesFuture(String product) {
List<CompletableFuture<String>> priceFutures =
shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is "
+ shop.getPrice(product), executor))
.collect(Collectors.toList());

List<String> prices = priceFutures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
return prices;
}

public List<String> findPricesInUSD(String product) {
List<CompletableFuture<Double>> priceFutures = new ArrayList<>();
for (Shop shop : shops) {
// Start of Listing 10.20.
// Only the type of futurePriceInUSD has been changed to
// CompletableFuture so that it is compatible with the
// CompletableFuture::join operation below.
CompletableFuture<Double> futurePriceInUSD =
CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombine(
CompletableFuture.supplyAsync(
() -> ExchangeService.getRate(Money.EUR, Money.USD)),
(price, rate) -> price * rate
);
priceFutures.add(futurePriceInUSD);
}
// Drawback: The shop is not accessible anymore outside the loop,
// so the getName() call below has been commented out.
List<String> prices = priceFutures
.stream()
.map(CompletableFuture::join)
.map(price -> /*shop.getName() +*/ " price is " + price)
.collect(Collectors.toList());
return prices;
}

public List<String> findPricesInUSDJava7(String product) {
ExecutorService executor = Executors.newCachedThreadPool();
List<Future<Double>> priceFutures = new ArrayList<>();
for (Shop shop : shops) {
final Future<Double> futureRate = executor.submit(new Callable<Double>() {
public Double call() {
return ExchangeService.getRate(Money.EUR, Money.USD);
}
});
Future<Double> futurePriceInUSD = executor.submit(new Callable<Double>() {
public Double call() {
try {
double priceInEUR = shop.getPrice(product);
return priceInEUR * futureRate.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
});
priceFutures.add(futurePriceInUSD);
}
List<String> prices = new ArrayList<>();
for (Future<Double> priceFuture : priceFutures) {
try {
prices.add(/*shop.getName() +*/ " price is " + priceFuture.get());
}
catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
return prices;
}

public List<String> findPricesInUSD2(String product) {
List<CompletableFuture<String>> priceFutures = new ArrayList<>();
for (Shop shop : shops) {
// Here, an extra operation has been added so that the shop name
// is retrieved within the loop. As a result, we now deal with
// CompletableFuture<String> instances.
CompletableFuture<String> futurePriceInUSD =
CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombine(
CompletableFuture.supplyAsync(
() -> ExchangeService.getRate(Money.EUR, Money.USD)),
(price, rate) -> price * rate
).thenApply(price -> shop.getName() + " price is " + price);
priceFutures.add(futurePriceInUSD);
}
List<String> prices = priceFutures
.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
return prices;
}

public List<String> findPricesInUSD3(String product) {
// Here, the for loop has been replaced by a mapping function...
Stream<CompletableFuture<String>> priceFuturesStream = shops
.stream()
.map(shop -> CompletableFuture
.supplyAsync(() -> shop.getPrice(product))
.thenCombine(
CompletableFuture.supplyAsync(() -> ExchangeService.getRate(Money.EUR, Money.USD)),
(price, rate) -> price * rate)
.thenApply(price -> shop.getName() + " price is " + price));
// However, we should gather the CompletableFutures into a List so that the asynchronous
// operations are triggered before being "joined."
List<CompletableFuture<String>> priceFutures = priceFuturesStream.collect(Collectors.toList());
List<String> prices = priceFutures
.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
return prices;
}

}
25 changes: 25 additions & 0 deletions src/main/java/lambdasinaction/chap10/v1/BestPriceFinderMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package lambdasinaction.chap10.v1;

import java.util.List;
import java.util.function.Supplier;

public class BestPriceFinderMain {

private static BestPriceFinder bestPriceFinder = new BestPriceFinder();

public static void main(String[] args) {
execute("sequential", () -> bestPriceFinder.findPricesSequential("myPhone27S"));
execute("parallel", () -> bestPriceFinder.findPricesParallel("myPhone27S"));
execute("composed CompletableFuture", () -> bestPriceFinder.findPricesFuture("myPhone27S"));
execute("combined USD CompletableFuture", () -> bestPriceFinder.findPricesInUSD("myPhone27S"));
execute("combined USD CompletableFuture v2", () -> bestPriceFinder.findPricesInUSD2("myPhone27S"));
execute("combined USD CompletableFuture v3", () -> bestPriceFinder.findPricesInUSD3("myPhone27S"));
}

private static void execute(String msg, Supplier<List<String>> s) {
long start = System.nanoTime();
System.out.println(s.get());
long duration = (System.nanoTime() - start) / 1_000_000;
System.out.println(msg + " done in " + duration + " msecs");
}
}
41 changes: 41 additions & 0 deletions src/main/java/lambdasinaction/chap10/v1/Shop.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package lambdasinaction.chap10.v1;

import static lambdasinaction.chap10.Util.delay;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

public class Shop {

private final String name;
private final Random random;

public Shop(String name) {
this.name = name;
random = new Random(name.charAt(0) * name.charAt(1) * name.charAt(2));
}

public double getPrice(String product) {
return calculatePrice(product);
}

private double calculatePrice(String product) {
delay();
return random.nextDouble() * product.charAt(0) + product.charAt(1);
}

public Future<Double> getPriceAsync(String product) {
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
new Thread( () -> {
double price = calculatePrice(product);
futurePrice.complete(price);
}).start();
return futurePrice;
}

public String getName() {
return name;
}

}
32 changes: 32 additions & 0 deletions src/main/java/lambdasinaction/chap10/v1/ShopMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package lambdasinaction.chap10.v1;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class ShopMain {

public static void main(String[] args) {
Shop shop = new Shop("BestShop");
long start = System.nanoTime();
Future<Double> futurePrice = shop.getPriceAsync("my favorite product");
long invocationTime = ((System.nanoTime() - start) / 1_000_000);
System.out.println("Invocation returned after " + invocationTime
+ " msecs");
// Do some more tasks, like querying other shops
doSomethingElse();
// while the price of the product is being calculated
try {
double price = futurePrice.get();
System.out.printf("Price is %.2f%n", price);
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
long retrievalTime = ((System.nanoTime() - start) / 1_000_000);
System.out.println("Price returned after " + retrievalTime + " msecs");
}

private static void doSomethingElse() {
System.out.println("Doing something else...");
}

}
32 changes: 0 additions & 32 deletions src/main/java/lambdasinaction/chap13/PersistentDataStructures.java

This file was deleted.

0 comments on commit 8fe642f

Please sign in to comment.