From bb548c465431cfb37bf81fa885e47c9140a055b1 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Tue, 19 Nov 2019 21:47:06 +0100 Subject: [PATCH 01/12] Aggiunto modulo per esempi del libro "Modern Java in Action" --- .idea/compiler.xml | 2 + .idea/junitgenerator-prj-settings.xml | 6 ++ modern-java/pom.xml | 45 +++++++++++ .../main/java/org/gym/fp/moderjava/Dish.java | 26 +++++++ .../java/org/gym/fp/moderjava/StreamTest.java | 78 +++++++++++++++++++ pom.xml | 3 +- 6 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 .idea/junitgenerator-prj-settings.xml create mode 100644 modern-java/pom.xml create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/Dish.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java diff --git a/.idea/compiler.xml b/.idea/compiler.xml index ecfa399..e0472d0 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -6,11 +6,13 @@ + + diff --git a/.idea/junitgenerator-prj-settings.xml b/.idea/junitgenerator-prj-settings.xml new file mode 100644 index 0000000..d73e792 --- /dev/null +++ b/.idea/junitgenerator-prj-settings.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/modern-java/pom.xml b/modern-java/pom.xml new file mode 100644 index 0000000..6b569dd --- /dev/null +++ b/modern-java/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + modern-java + jar + + + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + + + + + + fpgym + org.gym.fp + 1.0 + + + + 9 + 9 + + + + + org.projectlombok + lombok + + + junit + junit + test + + + + diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/Dish.java b/modern-java/src/main/java/org/gym/fp/moderjava/Dish.java new file mode 100644 index 0000000..fcdfdc0 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/Dish.java @@ -0,0 +1,26 @@ +package org.gym.fp.moderjava; + +import lombok.AllArgsConstructor; +import lombok.Value; + +@Value +@AllArgsConstructor +public final class Dish { + private final String name; + private final int calories; + private final Type type; + + public enum Type { + MEAT, FISH, VEGETARIAN, OTHER + } + + public boolean isVegetarian() { + return this.type == Type.VEGETARIAN; + } + + @Override + public String toString() { + return name; + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java new file mode 100644 index 0000000..5741c61 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java @@ -0,0 +1,78 @@ +package org.gym.fp.moderjava; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static java.lang.System.out; + +public class StreamTest { + + public static void main(String[] args) { + doStreamFilterDemo(); + doStreamMappingDemo(); + } + + private static void doStreamFilterDemo() { + out.println("FILTER EXAMPLE"); + getDishes().stream() + .filter(Dish::isVegetarian) + .collect(Collectors.toList()) + .forEach(out::println); + out.println("----------------------------------------"); + out.println("DISTINCT EXAMPLE"); + getDishes().stream() + .filter(dish -> dish.getName().length() > 4) + .distinct() + .forEach(out::println); + out.println("----------------------------------------"); + out.println("TAKEWHILE EXAMPLE"); + getDishes().stream() + .takeWhile(dish -> dish.getCalories() > 40) + .forEach(out::println); + out.println("----------------------------------------"); + out.println("DROPWHILE EXAMPLE"); + getDishes().stream() + .dropWhile(dish -> dish.getCalories() > 40) + .forEach(out::println); + out.println("----------------------------------------"); + } + + private static void doStreamMappingDemo() { + List words = Arrays.asList("Hello", "World"); + List uniqueCharacters = words.stream() + .map(word -> word.split("")) + .flatMap(Arrays::stream) + .distinct() + .collect(Collectors.toList()); + out.println(uniqueCharacters); + out.println("----------------------------------------"); + List numbers1 = Arrays.asList(1, 2, 3); + List numbers2 = Arrays.asList(3, 4); + List pairs1 = numbers1.stream() + .flatMap(i -> numbers2.stream().map(j -> new int[]{i, j})) + .collect(Collectors.toList()); + pairs1.forEach(pair -> out.println(Arrays.toString(pair))); + out.println("----------------------------------------"); + List pairs2 = numbers1.stream() + .flatMap(i -> numbers2.stream().map(j -> new int[]{i, j})) + .filter(pair -> (pair[0] + pair[1]) % 3 == 0) + .collect(Collectors.toList()); + pairs2.forEach(pair -> out.println(Arrays.toString(pair))); + } + + private static List getDishes() { + List dishes = Arrays.asList( + new Dish("pork", 300, Dish.Type.MEAT), + new Dish("salad", 50, Dish.Type.VEGETARIAN), + new Dish("chicken", 100, Dish.Type.MEAT), + new Dish("chicken", 100, Dish.Type.MEAT), + new Dish("tomato", 30, Dish.Type.VEGETARIAN), + new Dish("tunny", 120, Dish.Type.FISH), + new Dish("potato", 70, Dish.Type.VEGETARIAN) + ); + return Collections.unmodifiableList(dishes); + } + +} diff --git a/pom.xml b/pom.xml index dafdb24..2c0feec 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,8 @@ scala - + modern-java + From b4ee7f85df728a7e3c062c4d783c4a37a17a454d Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Wed, 20 Nov 2019 17:46:40 +0100 Subject: [PATCH 02/12] Continuo i test sugli Stream --- .idea/compiler.xml | 2 + .../java/org/gym/fp/moderjava/StreamTest.java | 95 ++++++++++++++++++- .../java/org/gym/fp/moderjava/Trader.java | 11 +++ .../org/gym/fp/moderjava/Transaction.java | 12 +++ pom.xml | 4 +- 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/Trader.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/Transaction.java diff --git a/.idea/compiler.xml b/.idea/compiler.xml index e0472d0..98acc8b 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -8,10 +8,12 @@ + + diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java index 5741c61..18053bb 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java @@ -1,9 +1,8 @@ package org.gym.fp.moderjava; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.lang.System.out; @@ -12,6 +11,8 @@ public class StreamTest { public static void main(String[] args) { doStreamFilterDemo(); doStreamMappingDemo(); + doStreamFindOrMatchingDemo(); + doStreamReducingDemo(); } private static void doStreamFilterDemo() { @@ -48,6 +49,7 @@ public class StreamTest { .collect(Collectors.toList()); out.println(uniqueCharacters); out.println("----------------------------------------"); + out.println("Permutations"); List numbers1 = Arrays.asList(1, 2, 3); List numbers2 = Arrays.asList(3, 4); List pairs1 = numbers1.stream() @@ -60,6 +62,91 @@ public class StreamTest { .filter(pair -> (pair[0] + pair[1]) % 3 == 0) .collect(Collectors.toList()); pairs2.forEach(pair -> out.println(Arrays.toString(pair))); + out.println("----------------------------------------"); + } + + private static void doStreamFindOrMatchingDemo() { + out.println("ANYMATCH EXAMPLE"); + if (getDishes().stream().anyMatch(Dish::isVegetarian)) { + out.println("The menu is (somewhat) vegetarian friendly!!!"); + } + out.println("----------------------------------------"); + out.println("ALLMATCH EXAMPLE"); + if (getDishes().stream().allMatch(dish -> dish.getCalories() < 1000)) { + out.println("This menù is healthy"); + } + out.println("----------------------------------------"); + out.println("NONEMATCH EXAMPLE"); + if (getDishes().stream().noneMatch(dish -> dish.getCalories() >= 1000)) { + out.println("This menù is healthy"); + } + out.println("----------------------------------------"); + out.println("FINDANY EXAMPLE"); + Optional dish = getDishes().stream() + .filter(Dish::isVegetarian) + .findAny(); + dish.ifPresent(out::println); + out.println("----------------------------------------"); + out.println("FINDFIRST EXAMPLE"); + List someNumbers = Arrays.asList(1, 2, 3, 4, 5); + someNumbers.stream() + .map(n -> n * n) + .filter(n -> n % 3 == 0) + .findFirst() + .ifPresent(out::println); + out.println("----------------------------------------"); + } + + private static void doStreamReducingDemo() { + out.println("REDUCING"); + int sum = Stream.of(4, 5, 3, 9).reduce(0, Integer::sum); + out.println(sum); + out.println("----------------------------------------"); + out.println("MAX & MIN"); + Stream.of(4, 5, 3, 9).reduce(Integer::max).ifPresent(out::println); + Stream.of(4, 5, 3, 9).reduce(Integer::min).ifPresent(out::println); + out.println("----------------------------------------"); + out.println("COUNT DISHES"); + getDishes().stream() + .map(d -> 1) + .reduce(Integer::sum) + .ifPresent(out::println); + out.println("----------------------------------------"); + out.println("PUTTING ALL IN PRACTICE"); + Trader raoul = new Trader("Raoul", "Cambridge"); + Trader mario = new Trader("Mario", "Milan"); + Trader alan = new Trader("Alan", "Cambridge"); + Trader brian = new Trader("Brian", "Cambridge"); + List transactions = Arrays.asList( + new Transaction(brian, 2011, 300), + new Transaction(raoul, 2012, 1000), + new Transaction(raoul, 2011, 400), + new Transaction(mario, 2012, 710), + new Transaction(mario, 2012, 700), + new Transaction(alan, 2012, 950) + ); + out.println("1)"); + transactions.stream() + .filter(t -> t.getYear() == 2011) + .sorted(Comparator.comparing(Transaction::getValue)) + .collect(Collectors.toList()) + .forEach(out::println); + out.println("2)"); + transactions.stream() + .map(Transaction::getTrader) + .map(Trader::getCity) + .distinct() + .collect(Collectors.toList()) + .forEach(out::println); + out.println("3)"); + transactions.stream() + .map(Transaction::getTrader) + .filter(trader -> "Cambridge".equalsIgnoreCase(trader.getCity())) + .sorted(Comparator.comparing(Trader::getName)) + .collect(Collectors.toList()) + .forEach(out::println); + + out.println("----------------------------------------"); } private static List getDishes() { @@ -71,7 +158,7 @@ public class StreamTest { new Dish("tomato", 30, Dish.Type.VEGETARIAN), new Dish("tunny", 120, Dish.Type.FISH), new Dish("potato", 70, Dish.Type.VEGETARIAN) - ); + ); return Collections.unmodifiableList(dishes); } diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/Trader.java b/modern-java/src/main/java/org/gym/fp/moderjava/Trader.java new file mode 100644 index 0000000..8315453 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/Trader.java @@ -0,0 +1,11 @@ +package org.gym.fp.moderjava; + +import lombok.AllArgsConstructor; +import lombok.Value; + +@Value +@AllArgsConstructor +public class Trader { + private final String name; + private final String city; +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/Transaction.java b/modern-java/src/main/java/org/gym/fp/moderjava/Transaction.java new file mode 100644 index 0000000..b5a0aa5 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/Transaction.java @@ -0,0 +1,12 @@ +package org.gym.fp.moderjava; + +import lombok.AllArgsConstructor; +import lombok.Value; + +@Value +@AllArgsConstructor +public class Transaction { + private final Trader trader; + private final int year; + private final int value; +} diff --git a/pom.xml b/pom.xml index 2c0feec..11f7a65 100644 --- a/pom.xml +++ b/pom.xml @@ -11,8 +11,8 @@ scala - modern-java - + modern-java + From 0f0ae0ccec98c2f30efc6ec2a82aa56f5d77cefd Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Wed, 20 Nov 2019 20:54:13 +0100 Subject: [PATCH 03/12] Terminato capitolo 5 sulle operazioni degli Stream --- .../java/org/gym/fp/moderjava/StreamTest.java | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java index 18053bb..032cb6a 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java @@ -2,6 +2,7 @@ package org.gym.fp.moderjava; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; import static java.lang.System.out; @@ -124,7 +125,7 @@ public class StreamTest { new Transaction(mario, 2012, 710), new Transaction(mario, 2012, 700), new Transaction(alan, 2012, 950) - ); + ); out.println("1)"); transactions.stream() .filter(t -> t.getYear() == 2011) @@ -142,10 +143,51 @@ public class StreamTest { transactions.stream() .map(Transaction::getTrader) .filter(trader -> "Cambridge".equalsIgnoreCase(trader.getCity())) + .distinct() // anche se sul testo non è specificato che dovevano essere diversi .sorted(Comparator.comparing(Trader::getName)) .collect(Collectors.toList()) .forEach(out::println); - + out.println("4)"); + String result = transactions.stream() + .map(Transaction::getTrader) + .map(Trader::getName) + .distinct() + .sorted() + .reduce("", (acc, name) -> acc + name); + out.println(result); + out.println("5)"); + boolean anyTraderInMilan = transactions.stream() + .map(Transaction::getTrader) + .anyMatch(trader -> "Milan".equalsIgnoreCase(trader.getCity())); + out.println(anyTraderInMilan); + out.println("6)"); + transactions.stream() + .filter(transaction -> "Cambridge".equalsIgnoreCase(transaction.getTrader().getCity())) + .forEach(transaction -> out.println(transaction.getValue())); + out.println("7)"); + transactions.stream() + .mapToInt(Transaction::getValue) + .max() + .ifPresent(out::println); + out.println("8)"); + transactions.stream() + .mapToInt(Transaction::getValue) + .min() + .ifPresent(out::println); + out.println("----------------------------------------"); + IntStream.rangeClosed(1, 100) + .boxed() + .flatMap(a -> IntStream.rangeClosed(a, 100) + .mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)}) + .filter(t -> t[2] % 1 == 0) + ) + .limit(5) + .forEach(triple -> out.printf("(%.0f, %.0f, %.0f)\n", triple[0], triple[1], triple[2])); + out.println("----------------------------------------"); + Stream.iterate(new int[] {0, 1}, t -> new int[] {t[1], t[0] + t[1]}) + .limit(20) + .forEach(pair -> out.printf("(%d, %d) ", pair[0], pair[1])); + out.println(); out.println("----------------------------------------"); } @@ -158,7 +200,7 @@ public class StreamTest { new Dish("tomato", 30, Dish.Type.VEGETARIAN), new Dish("tunny", 120, Dish.Type.FISH), new Dish("potato", 70, Dish.Type.VEGETARIAN) - ); + ); return Collections.unmodifiableList(dishes); } From 60630cd7f11e3cfea5e3a0c6d301a787d6c2fa3e Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Thu, 21 Nov 2019 17:43:50 +0100 Subject: [PATCH 04/12] Algoritmi di collector --- .../java/org/gym/fp/moderjava/StreamTest.java | 127 +++++++++++++++--- 1 file changed, 109 insertions(+), 18 deletions(-) diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java index 032cb6a..5046252 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java @@ -1,11 +1,13 @@ package org.gym.fp.moderjava; import java.util.*; -import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import static java.lang.System.out; +import static java.util.Arrays.asList; +import static java.util.Comparator.comparingInt; +import static java.util.stream.Collectors.*; public class StreamTest { @@ -14,13 +16,14 @@ public class StreamTest { doStreamMappingDemo(); doStreamFindOrMatchingDemo(); doStreamReducingDemo(); + doStreamCollectingDemo(); } private static void doStreamFilterDemo() { out.println("FILTER EXAMPLE"); getDishes().stream() .filter(Dish::isVegetarian) - .collect(Collectors.toList()) + .collect(toList()) .forEach(out::println); out.println("----------------------------------------"); out.println("DISTINCT EXAMPLE"); @@ -42,26 +45,26 @@ public class StreamTest { } private static void doStreamMappingDemo() { - List words = Arrays.asList("Hello", "World"); + List words = asList("Hello", "World"); List uniqueCharacters = words.stream() .map(word -> word.split("")) .flatMap(Arrays::stream) .distinct() - .collect(Collectors.toList()); + .collect(toList()); out.println(uniqueCharacters); out.println("----------------------------------------"); out.println("Permutations"); - List numbers1 = Arrays.asList(1, 2, 3); - List numbers2 = Arrays.asList(3, 4); + List numbers1 = asList(1, 2, 3); + List numbers2 = asList(3, 4); List pairs1 = numbers1.stream() .flatMap(i -> numbers2.stream().map(j -> new int[]{i, j})) - .collect(Collectors.toList()); + .collect(toList()); pairs1.forEach(pair -> out.println(Arrays.toString(pair))); out.println("----------------------------------------"); List pairs2 = numbers1.stream() .flatMap(i -> numbers2.stream().map(j -> new int[]{i, j})) .filter(pair -> (pair[0] + pair[1]) % 3 == 0) - .collect(Collectors.toList()); + .collect(toList()); pairs2.forEach(pair -> out.println(Arrays.toString(pair))); out.println("----------------------------------------"); } @@ -89,7 +92,7 @@ public class StreamTest { dish.ifPresent(out::println); out.println("----------------------------------------"); out.println("FINDFIRST EXAMPLE"); - List someNumbers = Arrays.asList(1, 2, 3, 4, 5); + List someNumbers = asList(1, 2, 3, 4, 5); someNumbers.stream() .map(n -> n * n) .filter(n -> n % 3 == 0) @@ -118,26 +121,26 @@ public class StreamTest { Trader mario = new Trader("Mario", "Milan"); Trader alan = new Trader("Alan", "Cambridge"); Trader brian = new Trader("Brian", "Cambridge"); - List transactions = Arrays.asList( + List transactions = asList( new Transaction(brian, 2011, 300), new Transaction(raoul, 2012, 1000), new Transaction(raoul, 2011, 400), new Transaction(mario, 2012, 710), new Transaction(mario, 2012, 700), new Transaction(alan, 2012, 950) - ); + ); out.println("1)"); transactions.stream() .filter(t -> t.getYear() == 2011) .sorted(Comparator.comparing(Transaction::getValue)) - .collect(Collectors.toList()) + .collect(toList()) .forEach(out::println); out.println("2)"); transactions.stream() .map(Transaction::getTrader) .map(Trader::getCity) .distinct() - .collect(Collectors.toList()) + .collect(toList()) .forEach(out::println); out.println("3)"); transactions.stream() @@ -145,7 +148,7 @@ public class StreamTest { .filter(trader -> "Cambridge".equalsIgnoreCase(trader.getCity())) .distinct() // anche se sul testo non è specificato che dovevano essere diversi .sorted(Comparator.comparing(Trader::getName)) - .collect(Collectors.toList()) + .collect(toList()) .forEach(out::println); out.println("4)"); String result = transactions.stream() @@ -180,19 +183,107 @@ public class StreamTest { .flatMap(a -> IntStream.rangeClosed(a, 100) .mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)}) .filter(t -> t[2] % 1 == 0) - ) + ) .limit(5) .forEach(triple -> out.printf("(%.0f, %.0f, %.0f)\n", triple[0], triple[1], triple[2])); out.println("----------------------------------------"); - Stream.iterate(new int[] {0, 1}, t -> new int[] {t[1], t[0] + t[1]}) + Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]}) .limit(20) .forEach(pair -> out.printf("(%d, %d) ", pair[0], pair[1])); out.println(); out.println("----------------------------------------"); } + private static void doStreamCollectingDemo() { + List menu = getDishes(); + long howManyDishes = menu.stream().count(); + out.println(howManyDishes); + out.println("----------------------------------------"); + Comparator dishCaloriesComparator = comparingInt(Dish::getCalories); + menu.stream() + .collect(maxBy(dishCaloriesComparator)) + .ifPresent(out::println); + out.println("----------------------------------------"); + int totalCalories = menu.stream().collect(summingInt(Dish::getCalories)); + out.println(totalCalories); + out.println("----------------------------------------"); + double avgCalories = menu.stream().collect(averagingInt(Dish::getCalories)); + out.println(avgCalories); + out.println("----------------------------------------"); + IntSummaryStatistics menuStatistics = menu.stream().collect(summarizingInt(Dish::getCalories)); + out.println(menuStatistics); + out.println("----------------------------------------"); + String shortMenu = menu.stream() + .map(Dish::getName) + .collect(joining(", ")); + out.println(shortMenu); + out.println("----------------------------------------"); + Map> dishesByType = menu.stream().collect(groupingBy(Dish::getType)); + out.println(dishesByType); + out.println("----------------------------------------"); + Map> dishesByCaloricLevel = menu.stream().collect(groupingBy(dish -> { + if (dish.getCalories() <= 400) return CaloricLevel.DIET; + else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL; + else return CaloricLevel.FAT; + })); + out.println(dishesByCaloricLevel); + out.println("----------------------------------------"); + Map> caloricDishesByType = + menu.stream() + .collect(groupingBy(Dish::getType, + filtering(dish -> dish.getCalories() > 500, + toList()))); + out.println(caloricDishesByType); + out.println("----------------------------------------"); + Map> dishNamesByType = + menu.stream() + .collect(groupingBy(Dish::getType, + mapping(Dish::getName, toList()))); + out.println(dishNamesByType); + out.println("----------------------------------------"); + Map> dishTags = Map.of( + "pork", asList("greasy", "salty"), + "beef", asList("salty", "roasted"), + "chicken", asList("fried", "crisp"), + "french fries", asList("greasy", "fried"), + "rice", asList("light", "natural"), + "season fruit", asList("fresh", "natural"), + "pizza", asList("tasty", "salty"), + "prawns", asList("tasty", "roasted"), + "salmon", asList("delicious", "fresh") + ); + Map> dishNamesByType2 = + menu.stream() + .collect(groupingBy(Dish::getType, + flatMapping(dish -> { + // FIXME: The example of book is not safety + List tags = dishTags.get(dish.getName()); + if (tags != null) { + return tags.stream(); + } + return Stream.empty(); + }, toSet()))); + out.println(dishNamesByType2); + out.println("----------------------------------------"); + Map>> dishesByTypeCaloricLevel = + menu.stream() + .collect(groupingBy(Dish::getType, groupingBy(dish -> { + if (dish.getCalories() <= 400) + return CaloricLevel.DIET; + else if (dish + .getCalories() <= 700) + return CaloricLevel.NORMAL; + else + return CaloricLevel.FAT; + }))); + out.println(dishesByTypeCaloricLevel); + out.println("----------------------------------------"); + } + + enum CaloricLevel {DIET, NORMAL, FAT} + private static List getDishes() { - List dishes = Arrays.asList( + List dishes = asList( new Dish("pork", 300, Dish.Type.MEAT), new Dish("salad", 50, Dish.Type.VEGETARIAN), new Dish("chicken", 100, Dish.Type.MEAT), @@ -200,7 +291,7 @@ public class StreamTest { new Dish("tomato", 30, Dish.Type.VEGETARIAN), new Dish("tunny", 120, Dish.Type.FISH), new Dish("potato", 70, Dish.Type.VEGETARIAN) - ); + ); return Collections.unmodifiableList(dishes); } From ab75cb8f6b0e18346b868221ed59f14e0286592e Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Sat, 23 Nov 2019 15:13:54 +0100 Subject: [PATCH 05/12] Esempi di collector e custom collector --- .../fp/moderjava/PrimeNumbersCollector.java | 56 +++++++++++++++ .../java/org/gym/fp/moderjava/StreamTest.java | 67 ++++++++++++++---- .../org/gym/fp/moderjava/ToListCollector.java | 68 +++++++++++++++++++ 3 files changed, 176 insertions(+), 15 deletions(-) create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/PrimeNumbersCollector.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/ToListCollector.java diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/PrimeNumbersCollector.java b/modern-java/src/main/java/org/gym/fp/moderjava/PrimeNumbersCollector.java new file mode 100644 index 0000000..7c37896 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/PrimeNumbersCollector.java @@ -0,0 +1,56 @@ +package org.gym.fp.moderjava; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +import static java.util.stream.Collector.Characteristics.IDENTITY_FINISH; + +public class PrimeNumbersCollector implements Collector>, Map>> { + + @Override + public Supplier>> supplier() { + return () -> new HashMap<>() {{ + put(true, new ArrayList<>()); + put(false, new ArrayList<>()); + }}; + } + + @Override + public BiConsumer>, Integer> accumulator() { + return (Map> acc, Integer candidate) -> { + acc.get(isPrime(acc.get(true), candidate)) + .add(candidate); + }; + } + + @Override + public BinaryOperator>> combiner() { + return (Map> map1, Map> map2) -> { + map1.get(true).addAll(map2.get(true)); + map1.get(false).addAll(map2.get(false)); + return map1; + }; + } + + @Override + public Function>, Map>> finisher() { + return Function.identity(); + } + + @Override + public Set characteristics() { + return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH)); + } + + private boolean isPrime(List primes, int candidate) { + int candidateRoot = (int) Math.sqrt(candidate); + return primes.stream() + .takeWhile(i -> i <= candidateRoot) + .noneMatch(i -> candidate % i == 0); + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java index 5046252..aec6962 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java @@ -128,7 +128,7 @@ public class StreamTest { new Transaction(mario, 2012, 710), new Transaction(mario, 2012, 700), new Transaction(alan, 2012, 950) - ); + ); out.println("1)"); transactions.stream() .filter(t -> t.getYear() == 2011) @@ -183,7 +183,7 @@ public class StreamTest { .flatMap(a -> IntStream.rangeClosed(a, 100) .mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)}) .filter(t -> t[2] % 1 == 0) - ) + ) .limit(5) .forEach(triple -> out.printf("(%.0f, %.0f, %.0f)\n", triple[0], triple[1], triple[2])); out.println("----------------------------------------"); @@ -231,14 +231,14 @@ public class StreamTest { Map> caloricDishesByType = menu.stream() .collect(groupingBy(Dish::getType, - filtering(dish -> dish.getCalories() > 500, - toList()))); + filtering(dish -> dish.getCalories() > 500, + toList()))); out.println(caloricDishesByType); out.println("----------------------------------------"); Map> dishNamesByType = menu.stream() .collect(groupingBy(Dish::getType, - mapping(Dish::getName, toList()))); + mapping(Dish::getName, toList()))); out.println(dishNamesByType); out.println("----------------------------------------"); Map> dishTags = Map.of( @@ -251,18 +251,18 @@ public class StreamTest { "pizza", asList("tasty", "salty"), "prawns", asList("tasty", "roasted"), "salmon", asList("delicious", "fresh") - ); + ); Map> dishNamesByType2 = menu.stream() .collect(groupingBy(Dish::getType, - flatMapping(dish -> { - // FIXME: The example of book is not safety - List tags = dishTags.get(dish.getName()); - if (tags != null) { - return tags.stream(); - } - return Stream.empty(); - }, toSet()))); + flatMapping(dish -> { + // FIXME: The example of book is not safety + List tags = dishTags.get(dish.getName()); + if (tags != null) { + return tags.stream(); + } + return Stream.empty(); + }, toSet()))); out.println(dishNamesByType2); out.println("----------------------------------------"); Map>> dishesByTypeCaloricLevel = @@ -278,6 +278,43 @@ public class StreamTest { }))); out.println(dishesByTypeCaloricLevel); out.println("----------------------------------------"); + Map> partitionedMenu = menu.stream().collect(partitioningBy(Dish::isVegetarian)); + out.println(partitionedMenu); + out.println("----------------------------------------"); + Map>> vegetarianDishesByType = + menu.stream().collect(partitioningBy(Dish::isVegetarian, groupingBy(Dish::getType))); + out.println(vegetarianDishesByType); + out.println("----------------------------------------"); + Map mostCaloricPartitionedByVegetarian = + menu.stream() + .collect(partitioningBy(Dish::isVegetarian, + collectingAndThen(maxBy(comparingInt(Dish::getCalories)), Optional::get))); + out.println(mostCaloricPartitionedByVegetarian); + out.println("----------------------------------------"); + out.println(partitionPrimes(100)); + out.println("----------------------------------------"); + List dishes = menu.stream() + .filter(Dish::isVegetarian) + .collect(new ToListCollector<>()); + out.println(dishes); + out.println("----------------------------------------"); + out.println(partitionPrimesWithCustomCollector(100)); + out.println("----------------------------------------"); + } + + public static Map> partitionPrimes(int n) { + return IntStream.rangeClosed(2, n).boxed() + .collect(partitioningBy(candidate -> isPrime(candidate))); + } + + public static boolean isPrime(int candidate) { + return IntStream.rangeClosed(2, candidate - 1) + .limit((long) Math.floor(Math.sqrt(candidate)) - 1) + .noneMatch(i -> candidate % i == 0); + } + + static Map> partitionPrimesWithCustomCollector(int n) { + return IntStream.rangeClosed(2, n).boxed().collect(new PrimeNumbersCollector()); } enum CaloricLevel {DIET, NORMAL, FAT} @@ -291,7 +328,7 @@ public class StreamTest { new Dish("tomato", 30, Dish.Type.VEGETARIAN), new Dish("tunny", 120, Dish.Type.FISH), new Dish("potato", 70, Dish.Type.VEGETARIAN) - ); + ); return Collections.unmodifiableList(dishes); } diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/ToListCollector.java b/modern-java/src/main/java/org/gym/fp/moderjava/ToListCollector.java new file mode 100644 index 0000000..f163a3e --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/ToListCollector.java @@ -0,0 +1,68 @@ +package org.gym.fp.moderjava; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +import static java.util.stream.Collector.Characteristics.CONCURRENT; +import static java.util.stream.Collector.Characteristics.IDENTITY_FINISH; + +// Collector => +// T = tipo generico degli elementi nello stream +// A = tipo dell'accumulatore, risultato parziale della riduzione +// R = tipo dell'oggetto risultato dall'operazione +public class ToListCollector implements Collector, List> { + + /** + * @return l'accumulatore vuoto + */ + @Override + public Supplier> supplier() { + return ArrayList::new; + } + + /** + * @return la funzione che accumula gli elementi T in A + */ + @Override + public BiConsumer, T> accumulator() { + return List::add; + } + + /** + * Questo metodo è invocato per combinare gli accumulatori + * elaborati da diversi sotto-stream + * + * @return la combinazione degli accumulatori + */ + @Override + public BinaryOperator> combiner() { + return (list1, list2) -> { + list1.addAll(list2); + return list1; + }; + } + + /** + * Questo metodo viene invocato al termine del processo + * di accumulazione degli elementi dello {@link java.util.stream.Stream} + * + * @return la funzione che trasforma A in R + */ + @Override + public Function, List> finisher() { + return Function.identity(); + } + + /** + * @return insieme dei comportamenti che il collector deve assumere + */ + @Override + public Set characteristics() { + return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT)); + } + +} From 5aac09213ad3b257ce5421096e21d5a82216079f Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Tue, 26 Nov 2019 19:33:42 +0100 Subject: [PATCH 06/12] Esempi sugli stream paralleli --- .../fp/moderjava/ForkJoinSumCalculator.java | 44 ++++++++++++++++++ .../java/org/gym/fp/moderjava/StreamTest.java | 34 ++++++++++++++ .../org/gym/fp/moderjava/WordCounter.java | 25 +++++++++++ .../fp/moderjava/WordCounterSpliterator.java | 45 +++++++++++++++++++ 4 files changed, 148 insertions(+) create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/ForkJoinSumCalculator.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/WordCounter.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/WordCounterSpliterator.java diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/ForkJoinSumCalculator.java b/modern-java/src/main/java/org/gym/fp/moderjava/ForkJoinSumCalculator.java new file mode 100644 index 0000000..ae57bfd --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/ForkJoinSumCalculator.java @@ -0,0 +1,44 @@ +package org.gym.fp.moderjava; + +import java.util.concurrent.RecursiveTask; + +public class ForkJoinSumCalculator extends RecursiveTask { + public static final long THRESHOLD = 10_000; + + private final long[] numbers; + private final int start; + private final int end; + + public ForkJoinSumCalculator(long[] numbers) { + this(numbers, 0, numbers.length); + } + + private ForkJoinSumCalculator(long[] numbers, int start, int end) { + this.numbers = numbers; + this.start = start; + this.end = end; + } + + @Override + protected Long compute() { + int length = end - start; + if (length <= THRESHOLD) { + return computeSequentially(); + } + ForkJoinSumCalculator leftTask = new ForkJoinSumCalculator(numbers, start, start + length / 2); + leftTask.fork(); + ForkJoinSumCalculator rightTask = new ForkJoinSumCalculator(numbers, start + length / 2, end); + Long rightResult = rightTask.compute(); + Long leftResult = leftTask.join(); + return leftResult + rightResult; + } + + private Long computeSequentially() { + long sum = 0; + for (int i = start; i < end; i++) { + sum += numbers[i]; + } + return sum; + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java index aec6962..42860c1 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java @@ -1,8 +1,12 @@ package org.gym.fp.moderjava; import java.util.*; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; import java.util.stream.IntStream; +import java.util.stream.LongStream; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import static java.lang.System.out; import static java.util.Arrays.asList; @@ -10,6 +14,10 @@ import static java.util.Comparator.comparingInt; import static java.util.stream.Collectors.*; public class StreamTest { + private static final String SENTENCE = + " Nel mezzo del cammin di nostra vita " + + "mi ritrovia in una selva oscura" + + " ché la dritta via era smarrita "; public static void main(String[] args) { doStreamFilterDemo(); @@ -17,6 +25,7 @@ public class StreamTest { doStreamFindOrMatchingDemo(); doStreamReducingDemo(); doStreamCollectingDemo(); + doStreamParallelDemo(); } private static void doStreamFilterDemo() { @@ -302,6 +311,31 @@ public class StreamTest { out.println("----------------------------------------"); } + private static void doStreamParallelDemo() { + out.println("ForkJoin result (1, 100) = " + forkJoinSum(100)); + out.println("----------------------------------------"); + Stream stream1 = IntStream.range(0, SENTENCE.length()).mapToObj(SENTENCE::charAt); + out.printf("Found %d words\n", countWords(stream1)); + out.println("----------------------------------------"); + Spliterator spliterator = new WordCounterSpliterator(SENTENCE); + Stream stream2 = StreamSupport.stream(spliterator, true); + out.printf("Found %d words\n", countWords(stream2)); + out.println("----------------------------------------"); + } + + private static int countWords(Stream stream) { + WordCounter wordCounter = stream.reduce(new WordCounter(0, true), + WordCounter::accumulate, + WordCounter::combine); + return wordCounter.getCounter(); + } + + private static long forkJoinSum(int n) { + long[] numbers = LongStream.rangeClosed(1, n).toArray(); + ForkJoinTask task = new ForkJoinSumCalculator(numbers); + return new ForkJoinPool().invoke(task); + } + public static Map> partitionPrimes(int n) { return IntStream.rangeClosed(2, n).boxed() .collect(partitioningBy(candidate -> isPrime(candidate))); diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/WordCounter.java b/modern-java/src/main/java/org/gym/fp/moderjava/WordCounter.java new file mode 100644 index 0000000..38aa1b3 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/WordCounter.java @@ -0,0 +1,25 @@ +package org.gym.fp.moderjava; + +public class WordCounter { + private final int counter; + private final boolean lastSpace; + + public WordCounter(int counter, boolean lastSpace) { + this.counter = counter; + this.lastSpace = lastSpace; + } + + public WordCounter accumulate(Character c) { + if (Character.isWhitespace(c)) return lastSpace ? this : new WordCounter(counter, true); + else return lastSpace ? new WordCounter(counter + 1, false) : this; + } + + public WordCounter combine(WordCounter wordCounter) { + return new WordCounter(this.counter + wordCounter.getCounter(), wordCounter.lastSpace); + } + + public int getCounter() { + return this.counter; + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/WordCounterSpliterator.java b/modern-java/src/main/java/org/gym/fp/moderjava/WordCounterSpliterator.java new file mode 100644 index 0000000..b122de1 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/WordCounterSpliterator.java @@ -0,0 +1,45 @@ +package org.gym.fp.moderjava; + +import java.util.Spliterator; +import java.util.function.Consumer; + +public class WordCounterSpliterator implements Spliterator { + private final String string; + private int currentChar = 0; + + public WordCounterSpliterator(String string) { + this.string = string; + } + + @Override + public boolean tryAdvance(Consumer action) { + action.accept(string.charAt(currentChar++)); + return currentChar < string.length(); + } + + @Override + public Spliterator trySplit() { + int currentSize = string.length() - currentChar; + if (currentSize < 10) return null; + for (int splitPos = currentSize / 2 + currentChar; splitPos < string.length(); splitPos++) { + if (Character.isWhitespace(string.charAt(splitPos))) { + Spliterator spliterator = new WordCounterSpliterator( + string.substring(currentChar, splitPos)); + currentChar = splitPos; + return spliterator; + } + } + return null; + } + + @Override + public long estimateSize() { + return string.length() - currentChar; + } + + @Override + public int characteristics() { + return ORDERED + SIZED + SUBSIZED + NONNULL + IMMUTABLE; + } + +} From 4995879731d5861957640e55af1b4a5c6d8568fa Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Thu, 28 Nov 2019 11:17:24 +0100 Subject: [PATCH 07/12] Refactoring della struttura dei package --- modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java | 2 ++ .../src/main/java/org/gym/fp/moderjava/{ => stream}/Dish.java | 2 +- .../gym/fp/moderjava/{ => stream}/ForkJoinSumCalculator.java | 2 +- .../gym/fp/moderjava/{ => stream}/PrimeNumbersCollector.java | 2 +- .../java/org/gym/fp/moderjava/{ => stream}/ToListCollector.java | 2 +- .../src/main/java/org/gym/fp/moderjava/{ => stream}/Trader.java | 2 +- .../java/org/gym/fp/moderjava/{ => stream}/Transaction.java | 2 +- .../java/org/gym/fp/moderjava/{ => stream}/WordCounter.java | 2 +- .../gym/fp/moderjava/{ => stream}/WordCounterSpliterator.java | 2 +- 9 files changed, 10 insertions(+), 8 deletions(-) rename modern-java/src/main/java/org/gym/fp/moderjava/{ => stream}/Dish.java (92%) rename modern-java/src/main/java/org/gym/fp/moderjava/{ => stream}/ForkJoinSumCalculator.java (97%) rename modern-java/src/main/java/org/gym/fp/moderjava/{ => stream}/PrimeNumbersCollector.java (97%) rename modern-java/src/main/java/org/gym/fp/moderjava/{ => stream}/ToListCollector.java (98%) rename modern-java/src/main/java/org/gym/fp/moderjava/{ => stream}/Trader.java (82%) rename modern-java/src/main/java/org/gym/fp/moderjava/{ => stream}/Transaction.java (84%) rename modern-java/src/main/java/org/gym/fp/moderjava/{ => stream}/WordCounter.java (94%) rename modern-java/src/main/java/org/gym/fp/moderjava/{ => stream}/WordCounterSpliterator.java (97%) diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java index 42860c1..9bd4fd6 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java @@ -1,5 +1,7 @@ package org.gym.fp.moderjava; +import org.gym.fp.moderjava.stream.*; + import java.util.*; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/Dish.java b/modern-java/src/main/java/org/gym/fp/moderjava/stream/Dish.java similarity index 92% rename from modern-java/src/main/java/org/gym/fp/moderjava/Dish.java rename to modern-java/src/main/java/org/gym/fp/moderjava/stream/Dish.java index fcdfdc0..3aa4235 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/Dish.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/stream/Dish.java @@ -1,4 +1,4 @@ -package org.gym.fp.moderjava; +package org.gym.fp.moderjava.stream; import lombok.AllArgsConstructor; import lombok.Value; diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/ForkJoinSumCalculator.java b/modern-java/src/main/java/org/gym/fp/moderjava/stream/ForkJoinSumCalculator.java similarity index 97% rename from modern-java/src/main/java/org/gym/fp/moderjava/ForkJoinSumCalculator.java rename to modern-java/src/main/java/org/gym/fp/moderjava/stream/ForkJoinSumCalculator.java index ae57bfd..f291003 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/ForkJoinSumCalculator.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/stream/ForkJoinSumCalculator.java @@ -1,4 +1,4 @@ -package org.gym.fp.moderjava; +package org.gym.fp.moderjava.stream; import java.util.concurrent.RecursiveTask; diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/PrimeNumbersCollector.java b/modern-java/src/main/java/org/gym/fp/moderjava/stream/PrimeNumbersCollector.java similarity index 97% rename from modern-java/src/main/java/org/gym/fp/moderjava/PrimeNumbersCollector.java rename to modern-java/src/main/java/org/gym/fp/moderjava/stream/PrimeNumbersCollector.java index 7c37896..e29e486 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/PrimeNumbersCollector.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/stream/PrimeNumbersCollector.java @@ -1,4 +1,4 @@ -package org.gym.fp.moderjava; +package org.gym.fp.moderjava.stream; import java.util.*; import java.util.function.BiConsumer; diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/ToListCollector.java b/modern-java/src/main/java/org/gym/fp/moderjava/stream/ToListCollector.java similarity index 98% rename from modern-java/src/main/java/org/gym/fp/moderjava/ToListCollector.java rename to modern-java/src/main/java/org/gym/fp/moderjava/stream/ToListCollector.java index f163a3e..c88f807 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/ToListCollector.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/stream/ToListCollector.java @@ -1,4 +1,4 @@ -package org.gym.fp.moderjava; +package org.gym.fp.moderjava.stream; import java.util.*; import java.util.function.BiConsumer; diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/Trader.java b/modern-java/src/main/java/org/gym/fp/moderjava/stream/Trader.java similarity index 82% rename from modern-java/src/main/java/org/gym/fp/moderjava/Trader.java rename to modern-java/src/main/java/org/gym/fp/moderjava/stream/Trader.java index 8315453..6acaf23 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/Trader.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/stream/Trader.java @@ -1,4 +1,4 @@ -package org.gym.fp.moderjava; +package org.gym.fp.moderjava.stream; import lombok.AllArgsConstructor; import lombok.Value; diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/Transaction.java b/modern-java/src/main/java/org/gym/fp/moderjava/stream/Transaction.java similarity index 84% rename from modern-java/src/main/java/org/gym/fp/moderjava/Transaction.java rename to modern-java/src/main/java/org/gym/fp/moderjava/stream/Transaction.java index b5a0aa5..b1afa49 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/Transaction.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/stream/Transaction.java @@ -1,4 +1,4 @@ -package org.gym.fp.moderjava; +package org.gym.fp.moderjava.stream; import lombok.AllArgsConstructor; import lombok.Value; diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/WordCounter.java b/modern-java/src/main/java/org/gym/fp/moderjava/stream/WordCounter.java similarity index 94% rename from modern-java/src/main/java/org/gym/fp/moderjava/WordCounter.java rename to modern-java/src/main/java/org/gym/fp/moderjava/stream/WordCounter.java index 38aa1b3..3ef5cee 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/WordCounter.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/stream/WordCounter.java @@ -1,4 +1,4 @@ -package org.gym.fp.moderjava; +package org.gym.fp.moderjava.stream; public class WordCounter { private final int counter; diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/WordCounterSpliterator.java b/modern-java/src/main/java/org/gym/fp/moderjava/stream/WordCounterSpliterator.java similarity index 97% rename from modern-java/src/main/java/org/gym/fp/moderjava/WordCounterSpliterator.java rename to modern-java/src/main/java/org/gym/fp/moderjava/stream/WordCounterSpliterator.java index b122de1..5a7e4b7 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/WordCounterSpliterator.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/stream/WordCounterSpliterator.java @@ -1,4 +1,4 @@ -package org.gym.fp.moderjava; +package org.gym.fp.moderjava.stream; import java.util.Spliterator; import java.util.function.Consumer; From 1dcc63c2846e5cd850fbe3f13299a51067ae65ce Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Thu, 28 Nov 2019 13:37:22 +0100 Subject: [PATCH 08/12] Esempi di creazione di un DSL interno con Java con diversi pattern --- .../java/org/gym/fp/moderjava/DslTest.java | 141 ++++++++++++++++++ .../gym/fp/moderjava/dsl/GroupingBuilder.java | 29 ++++ .../fp/moderjava/dsl/LambdaOrderBuilder.java | 65 ++++++++ .../dsl/MethodChainingOrderBuilder.java | 31 ++++ .../gym/fp/moderjava/dsl/MixedBuilder.java | 68 +++++++++ .../dsl/NestedFunctionOrderBuilder.java | 46 ++++++ .../java/org/gym/fp/moderjava/dsl/Order.java | 31 ++++ .../java/org/gym/fp/moderjava/dsl/Stock.java | 25 ++++ .../gym/fp/moderjava/dsl/StockBuilder.java | 21 +++ .../java/org/gym/fp/moderjava/dsl/Tax.java | 17 +++ .../gym/fp/moderjava/dsl/TaxCalculator.java | 17 +++ .../java/org/gym/fp/moderjava/dsl/Trade.java | 50 +++++++ .../gym/fp/moderjava/dsl/TradeBuilder.java | 18 +++ .../moderjava/dsl/TradeBuilderWithStock.java | 17 +++ 14 files changed, 576 insertions(+) create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/DslTest.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/GroupingBuilder.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/LambdaOrderBuilder.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/MethodChainingOrderBuilder.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/MixedBuilder.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/NestedFunctionOrderBuilder.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/Order.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/Stock.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/StockBuilder.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/Tax.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/TaxCalculator.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/Trade.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/TradeBuilder.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/dsl/TradeBuilderWithStock.java diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/DslTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/DslTest.java new file mode 100644 index 0000000..70c7959 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/DslTest.java @@ -0,0 +1,141 @@ +package org.gym.fp.moderjava; + +import org.gym.fp.moderjava.dsl.*; + +import static java.lang.System.out; +import static org.gym.fp.moderjava.dsl.LambdaOrderBuilder.order; +import static org.gym.fp.moderjava.dsl.MethodChainingOrderBuilder.forCustomer; +import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.at; +import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.buy; +import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.on; +import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.order; +import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.sell; +import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.stock; + +public class DslTest { + + public static void main(String[] args) { + doUnacceptableDslTest(); + doMethodChainingPatternTest(); + doNestedFunctionsPatternTest(); + doLambdaSequencingPatternTest(); + doMixedPatternTest(); + doUsingMethodReferenceDslTest(); + } + + private static void doUnacceptableDslTest() { + Order order = new Order(); + order.setCustomer("BigBank"); + + Trade trade1 = new Trade(); + trade1.setType(Trade.Type.BUY); + + Stock stock1 = new Stock(); + stock1.setSymbol("IBM"); + stock1.setMarket("NYSE"); + + trade1.setStock(stock1); + trade1.setPrice(125.00); + trade1.setQuantity(80); + order.addTrade(trade1); + + Trade trade2 = new Trade(); + trade2.setType(Trade.Type.BUY); + + Stock stock2 = new Stock(); + stock2.setSymbol("GOOGLE"); + stock2.setMarket("NASDAQ"); + + trade2.setStock(stock2); + trade2.setPrice(375.00); + trade2.setQuantity(50); + order.addTrade(trade2); + } + + private static void doMethodChainingPatternTest() { + Order order = forCustomer("BigBank") + .buy(80) + .stock("IBM") + .on("NYSE") + .at(125.00) + .sell(50) + .stock("Google") + .on("NASDAQ") + .at(375.00) + .end(); + out.println("Order: " + order.toString()); + out.println("----------------------------------------"); + } + + private static void doNestedFunctionsPatternTest() { + Order order = order("BigBank", + buy(80, + stock("IBM", on("NYSE")), + at(125.00)), + sell(50, + stock("Google", on("NASDAQ")), + at(375.00)) + ); + out.println("Order: " + order.toString()); + out.println("----------------------------------------"); + } + + private static void doLambdaSequencingPatternTest() { + Order order = order(o -> { + o.forCustomer("BigBank"); + o.buy(t -> { + t.quantity(80); + t.price(125.00); + t.stock(s -> { + s.symbol("IBM"); + s.market("NYSE"); + }); + }); + o.sell(t -> { + t.quantity(50); + t.price(375.00); + t.stock(s -> { + s.symbol("GOOGLE"); + s.market("NASDAQ"); + }); + }); + }); + out.println("Order: " + order.toString()); + out.println("----------------------------------------"); + } + + private static void doMixedPatternTest() { + Order order = MixedBuilder.forCustomer("BigBank", + MixedBuilder.buy(t -> t.quantity(80) + .stock("IBM") + .on("NYSE") + .at(125.00)), + MixedBuilder.sell(t -> t.quantity(50) + .stock("Google") + .on("NASDAQ") + .at(375.00)) + ); + out.println("Order: " + order.toString()); + out.println("----------------------------------------"); + } + + private static void doUsingMethodReferenceDslTest() { + Order order = MixedBuilder.forCustomer("BigBank", + MixedBuilder.buy(t -> t.quantity(80) + .stock("IBM") + .on("NYSE") + .at(125.00)), + MixedBuilder.sell(t -> t.quantity(50) + .stock("Google") + .on("NASDAQ") + .at(375.00)) + ); + double value = new TaxCalculator() + .with(Tax::regional) + .with(Tax::surcharge) + .calculate(order); + out.printf("Calculate value order with taxes: %.2f\n", value); + out.println("----------------------------------------"); + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/GroupingBuilder.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/GroupingBuilder.java new file mode 100644 index 0000000..65aadbd --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/GroupingBuilder.java @@ -0,0 +1,29 @@ +package org.gym.fp.moderjava.dsl; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collector; + +import static java.util.stream.Collectors.groupingBy; + +public class GroupingBuilder { + private final Collector> collector; + + public GroupingBuilder(Collector> collector) { + this.collector = collector; + } + + public Collector> get() { + return collector; + } + + public GroupingBuilder, J> after(Function classifier) { + return new GroupingBuilder<>(groupingBy(classifier, collector)); + } + + public static GroupingBuilder, K> groupOn(Function classifier) { + return new GroupingBuilder<>(groupingBy(classifier)); + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/LambdaOrderBuilder.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/LambdaOrderBuilder.java new file mode 100644 index 0000000..c75e32e --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/LambdaOrderBuilder.java @@ -0,0 +1,65 @@ +package org.gym.fp.moderjava.dsl; + +import java.util.function.Consumer; + +public class LambdaOrderBuilder { + private Order order = new Order(); + + public static Order order(Consumer consumer) { + LambdaOrderBuilder builder = new LambdaOrderBuilder(); + consumer.accept(builder); + return builder.order; + } + + public void forCustomer(String customer) { + order.setCustomer(customer); + } + + public void buy(Consumer consumer) { + trade(consumer, Trade.Type.BUY); + } + + public void sell(Consumer consumer) { + trade(consumer, Trade.Type.SELL); + } + + private void trade(Consumer consumer, Trade.Type type) { + TradeBuilder builder = new TradeBuilder(); + builder.trade.setType(type); + consumer.accept(builder); + order.addTrade(builder.trade); + } + + public static class TradeBuilder { + private Trade trade = new Trade(); + + public void quantity(int quantity) { + trade.setQuantity(quantity); + } + + public void price(double price) { + trade.setPrice(price); + } + + public void stock(Consumer consumer) { + StockBuilder builder = new StockBuilder(); + consumer.accept(builder); + trade.setStock(builder.stock); + } + + } + + public static class StockBuilder { + private Stock stock = new Stock(); + + public void symbol(String symbol) { + stock.setSymbol(symbol); + } + + public void market(String market) { + stock.setMarket(market); + } + + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/MethodChainingOrderBuilder.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/MethodChainingOrderBuilder.java new file mode 100644 index 0000000..bf76c09 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/MethodChainingOrderBuilder.java @@ -0,0 +1,31 @@ +package org.gym.fp.moderjava.dsl; + +public class MethodChainingOrderBuilder { + public final Order order = new Order(); + + private MethodChainingOrderBuilder(String customer) { + order.setCustomer(customer); + } + + public static MethodChainingOrderBuilder forCustomer(String customer) { + return new MethodChainingOrderBuilder(customer); + } + + public TradeBuilder buy(int quantity) { + return new TradeBuilder(this, Trade.Type.BUY, quantity); + } + + public TradeBuilder sell(int quantity) { + return new TradeBuilder(this, Trade.Type.SELL, quantity); + } + + public MethodChainingOrderBuilder addTrade(Trade trade) { + order.addTrade(trade); + return this; + } + + public Order end() { + return order; + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/MixedBuilder.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/MixedBuilder.java new file mode 100644 index 0000000..573a6f4 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/MixedBuilder.java @@ -0,0 +1,68 @@ +package org.gym.fp.moderjava.dsl; + +import java.util.function.Consumer; +import java.util.stream.Stream; + +public class MixedBuilder { + + public static Order forCustomer(String customer, TradeBuilder... builders) { + Order order = new Order(); + order.setCustomer(customer); + Stream.of(builders).forEach(b -> order.addTrade(b.trade)); + return order; + } + + public static TradeBuilder buy(Consumer consumer) { + return buildTrade(consumer, Trade.Type.BUY); + } + + public static TradeBuilder sell(Consumer consumer) { + return buildTrade(consumer, Trade.Type.SELL); + } + + private static TradeBuilder buildTrade(Consumer consumer, Trade.Type type) { + TradeBuilder builder = new TradeBuilder(); + builder.trade.setType(type); + consumer.accept(builder); + return builder; + } + + public static class TradeBuilder { + private Trade trade = new Trade(); + + public TradeBuilder quantity(int quantity) { + trade.setQuantity(quantity); + return this; + } + + public TradeBuilder at(double price) { + trade.setPrice(price); + return this; + } + + public StockBuilder stock(String symbol) { + return new StockBuilder(this, trade, symbol); + } + + } + + public static class StockBuilder { + private final TradeBuilder builder; + private final Trade trade; + private final Stock stock = new Stock(); + + public StockBuilder(TradeBuilder tradeBuilder, Trade trade, String symbol) { + this.builder = tradeBuilder; + this.trade = trade; + this.stock.setSymbol(symbol); + } + + public TradeBuilder on(String market) { + this.stock.setMarket(market); + trade.setStock(this.stock); + return builder; + } + + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/NestedFunctionOrderBuilder.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/NestedFunctionOrderBuilder.java new file mode 100644 index 0000000..41f2231 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/NestedFunctionOrderBuilder.java @@ -0,0 +1,46 @@ +package org.gym.fp.moderjava.dsl; + +import java.util.stream.Stream; + +public class NestedFunctionOrderBuilder { + + public static Order order(String customer, Trade... trades) { + Order order = new Order(); + order.setCustomer(customer); + Stream.of(trades).forEach(order::addTrade); + return order; + } + + public static Trade buy(int quantity, Stock stock, double price) { + return buildTrade(quantity, stock, price, Trade.Type.BUY); + } + + public static Trade sell(int quantity, Stock stock, double price) { + return buildTrade(quantity, stock, price, Trade.Type.SELL); + } + + private static Trade buildTrade(int quantity, Stock stock, double price, Trade.Type buy) { + Trade trade = new Trade(); + trade.setQuantity(quantity); + trade.setType(buy); + trade.setStock(stock); + trade.setPrice(price); + return trade; + } + + public static double at(double price) { + return price; + } + + public static Stock stock(String symbol, String market) { + Stock stock = new Stock(); + stock.setSymbol(symbol); + stock.setMarket(market); + return stock; + } + + public static String on(String market) { + return market; + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Order.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Order.java new file mode 100644 index 0000000..54960f3 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Order.java @@ -0,0 +1,31 @@ +package org.gym.fp.moderjava.dsl; + +import lombok.ToString; + +import java.util.ArrayList; +import java.util.List; + +@ToString +public class Order { + private String customer; + private List trades = new ArrayList<>(); + + public void addTrade(Trade trade) { + trades.add(trade); + } + + public String getCustomer() { + return customer; + } + + public void setCustomer(String customer) { + this.customer = customer; + } + + public double getValue() { + return trades.stream() + .mapToDouble(Trade::getValue) + .sum(); + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Stock.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Stock.java new file mode 100644 index 0000000..4b3b31d --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Stock.java @@ -0,0 +1,25 @@ +package org.gym.fp.moderjava.dsl; + +import lombok.ToString; + +@ToString +public class Stock { + private String symbol; + private String market; + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public String getMarket() { + return market; + } + + public void setMarket(String market) { + this.market = market; + } +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/StockBuilder.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/StockBuilder.java new file mode 100644 index 0000000..36e885a --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/StockBuilder.java @@ -0,0 +1,21 @@ +package org.gym.fp.moderjava.dsl; + +public class StockBuilder { + private final MethodChainingOrderBuilder builder; + private final Trade trade; + private final Stock stock = new Stock(); + + public StockBuilder(MethodChainingOrderBuilder builder, + Trade trade, String symbol) { + this.builder = builder; + this.trade = trade; + this.stock.setSymbol(symbol); + } + + public TradeBuilderWithStock on(String market) { + this.stock.setMarket(market); + trade.setStock(this.stock); + return new TradeBuilderWithStock(builder, trade); + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Tax.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Tax.java new file mode 100644 index 0000000..98a798a --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Tax.java @@ -0,0 +1,17 @@ +package org.gym.fp.moderjava.dsl; + +public class Tax { + + public static double regional(double value) { + return value * 1.1; + } + + public static double general(double value) { + return value * 1.3; + } + + public static double surcharge(double value) { + return value * 1.05; + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TaxCalculator.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TaxCalculator.java new file mode 100644 index 0000000..5c808a2 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TaxCalculator.java @@ -0,0 +1,17 @@ +package org.gym.fp.moderjava.dsl; + +import java.util.function.DoubleUnaryOperator; + +public class TaxCalculator { + private DoubleUnaryOperator taxFunction = d -> d; + + public TaxCalculator with(DoubleUnaryOperator f) { + this.taxFunction = taxFunction.andThen(f); + return this; + } + + public double calculate(Order order) { + return this.taxFunction.applyAsDouble(order.getValue()); + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Trade.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Trade.java new file mode 100644 index 0000000..b4cdead --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/Trade.java @@ -0,0 +1,50 @@ +package org.gym.fp.moderjava.dsl; + +import lombok.ToString; + +@ToString +public class Trade { + public enum Type {BUY, SELL} + + private Type type; + private Stock stock; + private int quantity; + private double price; + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public Stock getStock() { + return stock; + } + + public void setStock(Stock stock) { + this.stock = stock; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public double getValue() { + return quantity * price; + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TradeBuilder.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TradeBuilder.java new file mode 100644 index 0000000..8996310 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TradeBuilder.java @@ -0,0 +1,18 @@ +package org.gym.fp.moderjava.dsl; + +public class TradeBuilder { + private final MethodChainingOrderBuilder builder; + private final Trade trade = new Trade(); + + public TradeBuilder(MethodChainingOrderBuilder builder, + Trade.Type buy, int quantity) { + this.builder = builder; + this.trade.setType(buy); + this.trade.setQuantity(quantity); + } + + public StockBuilder stock(String symbol) { + return new StockBuilder(builder, trade, symbol); + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TradeBuilderWithStock.java b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TradeBuilderWithStock.java new file mode 100644 index 0000000..2651bf6 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/dsl/TradeBuilderWithStock.java @@ -0,0 +1,17 @@ +package org.gym.fp.moderjava.dsl; + +public class TradeBuilderWithStock { + private final MethodChainingOrderBuilder builder; + private final Trade trade; + + public TradeBuilderWithStock(MethodChainingOrderBuilder builder, Trade trade) { + this.builder = builder; + this.trade = trade; + } + + public MethodChainingOrderBuilder at(double price) { + this.trade.setPrice(price); + return builder.addTrade(trade); + } + +} From e968f0352f6d2c29665311ca215550fa16d90fe5 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Thu, 28 Nov 2019 18:13:31 +0100 Subject: [PATCH 09/12] Esempi con gli Optional --- .../org/gym/fp/moderjava/OptionalTest.java | 33 +++++++++++++++++++ .../org/gym/fp/moderjava/optional/Car.java | 17 ++++++++++ .../gym/fp/moderjava/optional/Insurance.java | 16 +++++++++ .../org/gym/fp/moderjava/optional/Person.java | 18 ++++++++++ 4 files changed, 84 insertions(+) create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/OptionalTest.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/optional/Car.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/optional/Insurance.java create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/optional/Person.java diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/OptionalTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/OptionalTest.java new file mode 100644 index 0000000..18793be --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/OptionalTest.java @@ -0,0 +1,33 @@ +package org.gym.fp.moderjava; + +import org.gym.fp.moderjava.optional.Car; +import org.gym.fp.moderjava.optional.Insurance; +import org.gym.fp.moderjava.optional.Person; + +import java.util.Optional; + +import static java.lang.System.out; + +public class OptionalTest { + + public static void main(String[] args) { + Insurance myInsurance1 = new Insurance("Allianz"); + Car myCar1 = new Car(Optional.of(myInsurance1)); + Person person1 = new Person(Optional.of(myCar1)); + out.println("My insurance's name is " + getCarInsuranceName(Optional.ofNullable(person1))); + out.println("----------------------------------------"); + Car myCar2 = new Car(Optional.ofNullable(null)); + Person person2 = new Person(Optional.ofNullable(myCar2)); + out.println("My insurance's name is " + getCarInsuranceName(Optional.ofNullable(person2))); + out.println("----------------------------------------"); + } + + static String getCarInsuranceName(Optional maybePerson) { + return maybePerson + .flatMap(Person::getCar) + .flatMap(Car::getInsurance) + .map(Insurance::getName) + .orElse("Unknown"); + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/optional/Car.java b/modern-java/src/main/java/org/gym/fp/moderjava/optional/Car.java new file mode 100644 index 0000000..9bf9f79 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/optional/Car.java @@ -0,0 +1,17 @@ +package org.gym.fp.moderjava.optional; + +import lombok.Getter; +import lombok.ToString; + +import java.util.Optional; + +@ToString +public class Car { + + @Getter + private Optional insurance; + + public Car(Optional insurance) { + this.insurance = insurance; + } +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/optional/Insurance.java b/modern-java/src/main/java/org/gym/fp/moderjava/optional/Insurance.java new file mode 100644 index 0000000..4ea8ded --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/optional/Insurance.java @@ -0,0 +1,16 @@ +package org.gym.fp.moderjava.optional; + +import lombok.Getter; +import lombok.ToString; + +@ToString +public class Insurance { + + @Getter + private String name; + + public Insurance(String name) { + this.name = name; + } + +} diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/optional/Person.java b/modern-java/src/main/java/org/gym/fp/moderjava/optional/Person.java new file mode 100644 index 0000000..4ec0b32 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/optional/Person.java @@ -0,0 +1,18 @@ +package org.gym.fp.moderjava.optional; + +import lombok.Getter; +import lombok.ToString; + +import java.util.Optional; + +@ToString +public class Person { + + @Getter + private Optional car; + + public Person(Optional car) { + this.car = car; + } + +} From 561c9d11815b0fd06764ae8e1cb9a98143c68a29 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Thu, 28 Nov 2019 20:00:58 +0100 Subject: [PATCH 10/12] Nuovi metodo sui Optional --- .../java/org/gym/fp/moderjava/OptionalTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/OptionalTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/OptionalTest.java index 18793be..9557bb7 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/OptionalTest.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/OptionalTest.java @@ -20,6 +20,8 @@ public class OptionalTest { Person person2 = new Person(Optional.ofNullable(myCar2)); out.println("My insurance's name is " + getCarInsuranceName(Optional.ofNullable(person2))); out.println("----------------------------------------"); + + out.println("----------------------------------------"); } static String getCarInsuranceName(Optional maybePerson) { @@ -30,4 +32,17 @@ public class OptionalTest { .orElse("Unknown"); } + static Insurance findCheapestInsurance(Person person, Car car) { + Insurance cheapestInsurance = new Insurance("Allianz"); + return cheapestInsurance; + } + + static Optional nullSafeFindCheapestInsurance(Optional person, Optional car) { + return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c))); +// if (person.isPresent() && car.isPresent()) { +// return Optional.of(findCheapestInsurance(person.get(), car.get())); +// } +// return Optional.empty(); + } + } From 1c11be5ab06461c3db0d482fd83f43bdb7095bd6 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Mon, 2 Dec 2019 18:26:54 +0100 Subject: [PATCH 11/12] Inizio esempi sulla concorrenza --- .../org/gym/fp/moderjava/ConcurrencyTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/ConcurrencyTest.java diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/ConcurrencyTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/ConcurrencyTest.java new file mode 100644 index 0000000..c801026 --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/ConcurrencyTest.java @@ -0,0 +1,33 @@ +package org.gym.fp.moderjava; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static java.lang.System.out; + +public class ConcurrencyTest { + + public static void main(String[] args) throws Exception { + doExecutorsServiceTest(); + } + + private static void doExecutorsServiceTest() throws ExecutionException, InterruptedException { + int x = 1337; + ExecutorService executorService = Executors.newFixedThreadPool(2); + Future y = executorService.submit(() -> f(x)); + Future z = executorService.submit(() -> g(x)); + out.println("Result y + z = " + (y.get() + z.get())); + executorService.shutdown(); + } + + static int f(int x) { + return 42; + } + + static int g(int x) { + return x; + } + +} From 040f33ff04d912912b66433d7b58c559b2b6025d Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Wed, 4 Dec 2019 18:15:58 +0100 Subject: [PATCH 12/12] Prove sulla concorrenza con ComposableFuture --- .../org/gym/fp/moderjava/ConcurrencyTest.java | 37 +++++++++++++++--- .../org/gym/fp/moderjava/concurrent/Shop.java | 39 +++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 modern-java/src/main/java/org/gym/fp/moderjava/concurrent/Shop.java diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/ConcurrencyTest.java b/modern-java/src/main/java/org/gym/fp/moderjava/ConcurrencyTest.java index c801026..4f90cbd 100644 --- a/modern-java/src/main/java/org/gym/fp/moderjava/ConcurrencyTest.java +++ b/modern-java/src/main/java/org/gym/fp/moderjava/ConcurrencyTest.java @@ -1,9 +1,10 @@ package org.gym.fp.moderjava; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import org.gym.fp.moderjava.concurrent.Shop; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.*; import static java.lang.System.out; @@ -11,9 +12,10 @@ public class ConcurrencyTest { public static void main(String[] args) throws Exception { doExecutorsServiceTest(); + doFutureTest(); } - private static void doExecutorsServiceTest() throws ExecutionException, InterruptedException { + private static void doExecutorsServiceTest() throws Exception { int x = 1337; ExecutorService executorService = Executors.newFixedThreadPool(2); Future y = executorService.submit(() -> f(x)); @@ -22,6 +24,18 @@ public class ConcurrencyTest { executorService.shutdown(); } + private static void doFutureTest() throws Exception { + Collection shops = getShops(); + Future future = CompletableFuture.supplyAsync(() -> { + out.println("Primo completable future"); + return 10; + }).thenCombine(CompletableFuture.supplyAsync(() -> { + out.println("Secondo completable future"); + return 30; + }), (first, second) -> first + second); + out.println(future.get(1, TimeUnit.NANOSECONDS)); + } + static int f(int x) { return 42; } @@ -30,4 +44,17 @@ public class ConcurrencyTest { return x; } + static Collection getShops() { + return Arrays.asList( + new Shop("BestShop1"), + new Shop("BestShop2"), + new Shop("BestShop3"), + new Shop("BestShop4"), + new Shop("BestShop5"), + new Shop("BestShop6"), + new Shop("BestShop7"), + new Shop("BestShop8") + ); + } + } diff --git a/modern-java/src/main/java/org/gym/fp/moderjava/concurrent/Shop.java b/modern-java/src/main/java/org/gym/fp/moderjava/concurrent/Shop.java new file mode 100644 index 0000000..8475b6c --- /dev/null +++ b/modern-java/src/main/java/org/gym/fp/moderjava/concurrent/Shop.java @@ -0,0 +1,39 @@ +package org.gym.fp.moderjava.concurrent; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +@ToString +@AllArgsConstructor +public class Shop { + + @Getter + private String name; + + public double getPrice(String product) { + return calculatePrice(product); + } + + public Future getPriceAsync(String product) { + return CompletableFuture.supplyAsync(() -> calculatePrice(product)); + } + + private double calculatePrice(String product) { + delay(); + return new Random().nextDouble() * product.charAt(0) + product.charAt(1); + } + + static void delay() { + try { + Thread.sleep(1000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + +}