Skip to content

Commit 2addf81

Browse files
committed
add code for chapter 5
1 parent b58c4c9 commit 2addf81

File tree

8 files changed

+387
-0
lines changed

8 files changed

+387
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package lambdasinaction.chap5;
2+
3+
import java.util.function.*;
4+
5+
import static lambdasinaction.chap5.PartitionPrimeNumbers.*;
6+
7+
public class CollectorHarness {
8+
9+
public static void main(String[] args) {
10+
System.out.println("Partitioning done in: " + execute(PartitionPrimeNumbers::partitionPrimes) + " msecs");
11+
System.out.println("Partitioning done in: " + execute(PartitionPrimeNumbers::partitionPrimesWithCustomCollector) + " msecs" );
12+
}
13+
14+
private static long execute(Consumer<Integer> primePartitioner) {
15+
long fastest = Long.MAX_VALUE;
16+
for (int i = 0; i < 10; i++) {
17+
long start = System.nanoTime();
18+
primePartitioner.accept(1_000_000);
19+
long duration = (System.nanoTime() - start) / 1_000_000;
20+
if (duration < fastest) fastest = duration;
21+
}
22+
return fastest;
23+
}
24+
}

src/main/java/lambdasinaction/chap5/Dish.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package lambdasinaction.chap5;
22

3+
import java.util.*;
4+
35
public class Dish {
6+
47
private final String name;
58
private final boolean vegetarian;
69
private final int calories;
@@ -35,4 +38,15 @@ public enum Type { MEAT, FISH, OTHER }
3538
public String toString() {
3639
return name;
3740
}
41+
42+
public static final List<Dish> menu =
43+
Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT),
44+
new Dish("beef", false, 700, Dish.Type.MEAT),
45+
new Dish("chicken", false, 400, Dish.Type.MEAT),
46+
new Dish("french fries", true, 530, Dish.Type.OTHER),
47+
new Dish("rice", true, 350, Dish.Type.OTHER),
48+
new Dish("season fruit", true, 120, Dish.Type.OTHER),
49+
new Dish("pizza", true, 550, Dish.Type.OTHER),
50+
new Dish("prawns", false, 400, Dish.Type.FISH),
51+
new Dish("salmon", false, 450, Dish.Type.FISH));
3852
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package lambdasinaction.chap5;
2+
3+
import java.util.*;
4+
import java.util.function.*;
5+
import java.util.stream.*;
6+
7+
import static java.util.stream.Collectors.*;
8+
import static lambdasinaction.chap5.Dish.menu;
9+
10+
public class Grouping {
11+
12+
enum CaloricLevel { DIET, NORMAL, FAT };
13+
14+
public static void main(String ... args) {
15+
System.out.println("Dishes grouped by type: " + groupDishesByType());
16+
System.out.println("Dishes grouped by caloric level: " + groupDishesByCaloricLevel());
17+
System.out.println("Dishes grouped by type and caloric level: " + groupDishedByTypeAndCaloricLevel());
18+
System.out.println("Count dishes in groups: " + countDishesInGroups());
19+
System.out.println("Most caloric dishes by type: " + mostCaloricDishesByType());
20+
System.out.println("Most caloric dishes by type: " + mostCaloricDishesByTypeWithoutOprionals());
21+
System.out.println("Sum calories by type: " + sumCaloriesByType());
22+
System.out.println("Caloric levels by type: " + caloricLevelsByType());
23+
}
24+
25+
private static Map<Dish.Type, List<Dish>> groupDishesByType() {
26+
return menu.stream().collect(groupingBy(Dish::getType));
27+
}
28+
29+
private static Map<CaloricLevel, List<Dish>> groupDishesByCaloricLevel() {
30+
return menu.stream().collect(
31+
groupingBy(dish -> {
32+
if (dish.getCalories() <= 400) return CaloricLevel.DIET;
33+
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
34+
else return CaloricLevel.FAT;
35+
} ));
36+
}
37+
38+
private static Map<Dish.Type, Map<CaloricLevel, List<Dish>>> groupDishedByTypeAndCaloricLevel() {
39+
return menu.stream().collect(
40+
groupingBy(Dish::getType,
41+
groupingBy(dish -> {
42+
if (dish.getCalories() <= 400) return CaloricLevel.DIET;
43+
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
44+
else return CaloricLevel.FAT;
45+
} )
46+
)
47+
);
48+
}
49+
50+
private static Map<Dish.Type, Long> countDishesInGroups() {
51+
return menu.stream().collect(groupingBy(Dish::getType, counting()));
52+
}
53+
54+
private static Map<Dish.Type, Optional<Dish>> mostCaloricDishesByType() {
55+
return menu.stream().collect(
56+
groupingBy(Dish::getType,
57+
reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2)));
58+
}
59+
60+
private static Map<Dish.Type, Dish> mostCaloricDishesByTypeWithoutOprionals() {
61+
return menu.stream().collect(
62+
groupingBy(Dish::getType,
63+
collectingAndThen(
64+
reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2),
65+
Optional::get)));
66+
}
67+
68+
private static Map<Dish.Type, Integer> sumCaloriesByType() {
69+
return menu.stream().collect(groupingBy(Dish::getType,
70+
summingInt(Dish::getCalories)));
71+
}
72+
73+
private static Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType() {
74+
return menu.stream().collect(
75+
groupingBy(Dish::getType, mapping(
76+
dish -> { if (dish.getCalories() <= 400) return CaloricLevel.DIET;
77+
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
78+
else return CaloricLevel.FAT; },
79+
toSet() )));
80+
}
81+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package lambdasinaction.chap5;
2+
3+
import java.util.*;
4+
import java.util.function.*;
5+
import java.util.stream.*;
6+
7+
import static java.util.stream.Collectors.*;
8+
import static lambdasinaction.chap5.Dish.menu;
9+
import static java.util.stream.Collector.Characteristics.*;
10+
11+
public class PartitionPrimeNumbers {
12+
13+
public static void main(String ... args) {
14+
System.out.println("Numbers partitioned in prime and non-prime: " + partitionPrimes(100));
15+
System.out.println("Numbers partitioned in prime and non-prime: " + partitionPrimesWithCustomCollector(100));
16+
17+
}
18+
19+
public static Map<Boolean, List<Integer>> partitionPrimes(int n) {
20+
return Stream.iterate(2, i -> i + 1).limit(n)
21+
.collect(partitioningBy(candidate -> isPrime(candidate)));
22+
}
23+
24+
public static boolean isPrime(int candidate) {
25+
return Stream.iterate(2, i -> i + 1)
26+
.limit((long) Math.floor(Math.sqrt((double) candidate)) - 1)
27+
.noneMatch(i -> candidate % i == 0);
28+
}
29+
30+
public static Map<Boolean, List<Integer>> partitionPrimesWithCustomCollector(int n) {
31+
return Stream.iterate(2, i -> i + 1).limit(n).collect(new PrimeNumbersCollector());
32+
}
33+
34+
public static boolean isPrime(List<Integer> primes, Integer candidate) {
35+
double candidateRoot = Math.sqrt((double) candidate);
36+
return takeWhile(primes, i -> i <= candidateRoot).stream().noneMatch(i -> candidate % i == 0);
37+
}
38+
39+
public static <A> List<A> takeWhile(List<A> list, Predicate<A> p) {
40+
int i = 0;
41+
for (A item : list) {
42+
if (!p.test(item)) {
43+
return list.subList(0, i);
44+
}
45+
i++;
46+
}
47+
return list;
48+
}
49+
50+
public static class PrimeNumbersCollector
51+
implements Collector<Integer, Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> {
52+
53+
@Override
54+
public Supplier<Map<Boolean, List<Integer>>> supplier() {
55+
return () -> new HashMap<Boolean, List<Integer>>() {{
56+
put(true, new ArrayList<Integer>());
57+
put(false, new ArrayList<Integer>());
58+
}};
59+
}
60+
61+
@Override
62+
public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
63+
return (Map<Boolean, List<Integer>> acc, Integer candidate) -> {
64+
acc.get( isPrime( acc.get(true),
65+
candidate) )
66+
.add(candidate);
67+
};
68+
}
69+
70+
@Override
71+
public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
72+
return (Map<Boolean, List<Integer>> map1, Map<Boolean, List<Integer>> map2) -> {
73+
map1.get(true).addAll(map2.get(true));
74+
map1.get(false).addAll(map2.get(false));
75+
return map1;
76+
};
77+
}
78+
79+
@Override
80+
public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() {
81+
return i -> i;
82+
}
83+
84+
@Override
85+
public Set<Characteristics> characteristics() {
86+
return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH));
87+
}
88+
}
89+
90+
public Map<Boolean, List<Integer>> partitionPrimesWithInlineCollector(int n) {
91+
return Stream.iterate(2, i -> i + 1).limit(n)
92+
.collect(
93+
() -> new HashMap<Boolean, List<Integer>>() {{
94+
put(true, new ArrayList<Integer>());
95+
put(false, new ArrayList<Integer>());
96+
}},
97+
(acc, candidate) -> {
98+
acc.get( isPrime(acc.get(true), candidate) )
99+
.add(candidate);
100+
},
101+
(map1, map2) -> {
102+
map1.get(true).addAll(map2.get(true));
103+
map1.get(false).addAll(map2.get(false));
104+
});
105+
}
106+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package lambdasinaction.chap5;
2+
3+
import java.util.*;
4+
import java.util.function.*;
5+
import java.util.stream.*;
6+
7+
import static java.util.stream.Collectors.*;
8+
import static lambdasinaction.chap5.Dish.menu;
9+
10+
public class Partitioning {
11+
12+
public static void main(String ... args) {
13+
System.out.println("Dishes partitioned by vegetarian: " + partitionByVegeterian());
14+
System.out.println("Vegetarian Dishes by type: " + vegetarianDishesByType());
15+
System.out.println("Most caloric dishes by vegetarian: " + mostCaloricPartitionedByVegetarian());
16+
}
17+
18+
private static Map<Boolean, List<Dish>> partitionByVegeterian() {
19+
return menu.stream().collect(partitioningBy(Dish::isVegetarian));
20+
}
21+
22+
private static Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType() {
23+
return menu.stream().collect(partitioningBy(Dish::isVegetarian, groupingBy(Dish::getType)));
24+
}
25+
26+
private static Object mostCaloricPartitionedByVegetarian() {
27+
return menu.stream().collect(
28+
partitioningBy(Dish::isVegetarian,
29+
collectingAndThen(
30+
reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2),
31+
Optional::get)));
32+
}
33+
}
34+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package lambdasinaction.chap5;
2+
3+
import java.util.*;
4+
import java.util.function.*;
5+
import java.util.stream.*;
6+
7+
import static java.util.stream.Collectors.*;
8+
import static lambdasinaction.chap5.Dish.menu;
9+
10+
public class Reducing {
11+
12+
public static void main(String ... args) {
13+
System.out.println("Total calories in menu: " + calculateTotalCalories());
14+
System.out.println("Total calories in menu: " + calculateTotalCaloriesWithMethodReference());
15+
System.out.println("Total calories in menu: " + calculateTotalCaloriesWithoutCollectors());
16+
System.out.println("Total calories in menu: " + calculateTotalCaloriesUsingSum());
17+
}
18+
19+
private static int calculateTotalCalories() {
20+
return menu.stream().collect(reducing(0, Dish::getCalories, (Integer i, Integer j) -> i + j));
21+
}
22+
23+
private static int calculateTotalCaloriesWithMethodReference() {
24+
return menu.stream().collect(reducing(0, Dish::getCalories, Integer::sum));
25+
}
26+
27+
private static int calculateTotalCaloriesWithoutCollectors() {
28+
return menu.stream().map(Dish::getCalories).reduce(Integer::sum).get();
29+
}
30+
31+
private static int calculateTotalCaloriesUsingSum() {
32+
return menu.stream().mapToInt(Dish::getCalories).sum();
33+
}
34+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package lambdasinaction.chap5;
2+
3+
import java.util.*;
4+
import java.util.function.*;
5+
import java.util.stream.*;
6+
7+
import static java.util.stream.Collectors.*;
8+
import static lambdasinaction.chap5.Dish.menu;
9+
10+
public class Summarizing {
11+
12+
public static void main(String ... args) {
13+
System.out.println("Nr. of dishes: " + howManyDishes());
14+
System.out.println("The most caloric dish is: " + findMostCaloricDish());
15+
System.out.println("The most caloric dish is: " + findMostCaloricDishUsingComparator());
16+
System.out.println("Total calories in menu: " + calculateTotalCalories());
17+
System.out.println("Average calories in menu: " + calculateAverageCalories());
18+
System.out.println("Menu statistics: " + calculateMenuStatistics());
19+
System.out.println("Short menu: " + getShortMenu());
20+
System.out.println("Short menu comma separated: " + getShortMenuCommaSeparated());
21+
}
22+
23+
24+
private static long howManyDishes() {
25+
return menu.stream().collect(counting());
26+
}
27+
28+
private static Dish findMostCaloricDish() {
29+
return menu.stream().collect(reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2)).get();
30+
}
31+
32+
private static Dish findMostCaloricDishUsingComparator() {
33+
Comparator<Dish> dishCaloriesComparator = Comparator.comparing(Dish::getCalories);
34+
BinaryOperator<Dish> moreCaloricOf = BinaryOperator.maxBy(dishCaloriesComparator);
35+
return menu.stream().collect(reducing(moreCaloricOf)).get();
36+
}
37+
38+
private static int calculateTotalCalories() {
39+
return menu.stream().collect(summingInt(Dish::getCalories));
40+
}
41+
42+
private static Double calculateAverageCalories() {
43+
return menu.stream().collect(averagingInt(Dish::getCalories));
44+
}
45+
46+
private static IntSummaryStatistics calculateMenuStatistics() {
47+
return menu.stream().collect(summarizingInt(Dish::getCalories));
48+
}
49+
50+
private static String getShortMenu() {
51+
return menu.stream().map(Dish::getName).collect(joining());
52+
}
53+
54+
private static String getShortMenuCommaSeparated() {
55+
return menu.stream().map(Dish::getName).collect(joining(", "));
56+
}
57+
}

0 commit comments

Comments
 (0)