Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Technical proofing by Jean-Francois Morin
  • Loading branch information
jeffmorin committed Jun 29, 2014
commit 8fe642fb13e34e18a91b5d0d3827f08136029a53
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.