Merge branch 'develop'
This commit is contained in:
4
.idea/compiler.xml
generated
4
.idea/compiler.xml
generated
@@ -6,11 +6,15 @@
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="modernjava" />
|
||||
<module name="scala" />
|
||||
<module name="modern-java" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel>
|
||||
<module name="fpgym" target="8" />
|
||||
<module name="modern-java" target="9" />
|
||||
<module name="modernjava" target="9" />
|
||||
<module name="scala" target="1.5" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
|
||||
6
.idea/junitgenerator-prj-settings.xml
generated
Normal file
6
.idea/junitgenerator-prj-settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JUnitGeneratorProjectSettings">
|
||||
<option name="selectedTemplateKey" value="JUnit 4" />
|
||||
</component>
|
||||
</project>
|
||||
45
modern-java/pom.xml
Normal file
45
modern-java/pom.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>modern-java</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>9</source>
|
||||
<target>9</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<parent>
|
||||
<artifactId>fpgym</artifactId>
|
||||
<groupId>org.gym.fp</groupId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>9</maven.compiler.source>
|
||||
<maven.compiler.target>9</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.gym.fp.moderjava;
|
||||
|
||||
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;
|
||||
|
||||
public class ConcurrencyTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
doExecutorsServiceTest();
|
||||
doFutureTest();
|
||||
}
|
||||
|
||||
private static void doExecutorsServiceTest() throws Exception {
|
||||
int x = 1337;
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(2);
|
||||
Future<Integer> y = executorService.submit(() -> f(x));
|
||||
Future<Integer> z = executorService.submit(() -> g(x));
|
||||
out.println("Result y + z = " + (y.get() + z.get()));
|
||||
executorService.shutdown();
|
||||
}
|
||||
|
||||
private static void doFutureTest() throws Exception {
|
||||
Collection<Shop> shops = getShops();
|
||||
Future<Integer> 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;
|
||||
}
|
||||
|
||||
static int g(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
static Collection<Shop> 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")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
141
modern-java/src/main/java/org/gym/fp/moderjava/DslTest.java
Normal file
141
modern-java/src/main/java/org/gym/fp/moderjava/DslTest.java
Normal file
@@ -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("----------------------------------------");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
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("----------------------------------------");
|
||||
|
||||
out.println("----------------------------------------");
|
||||
}
|
||||
|
||||
static String getCarInsuranceName(Optional<Person> maybePerson) {
|
||||
return maybePerson
|
||||
.flatMap(Person::getCar)
|
||||
.flatMap(Car::getInsurance)
|
||||
.map(Insurance::getName)
|
||||
.orElse("Unknown");
|
||||
}
|
||||
|
||||
static Insurance findCheapestInsurance(Person person, Car car) {
|
||||
Insurance cheapestInsurance = new Insurance("Allianz");
|
||||
return cheapestInsurance;
|
||||
}
|
||||
|
||||
static Optional<Insurance> nullSafeFindCheapestInsurance(Optional<Person> person, Optional<Car> 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();
|
||||
}
|
||||
|
||||
}
|
||||
371
modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java
Normal file
371
modern-java/src/main/java/org/gym/fp/moderjava/StreamTest.java
Normal file
@@ -0,0 +1,371 @@
|
||||
package org.gym.fp.moderjava;
|
||||
|
||||
import org.gym.fp.moderjava.stream.*;
|
||||
|
||||
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;
|
||||
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();
|
||||
doStreamMappingDemo();
|
||||
doStreamFindOrMatchingDemo();
|
||||
doStreamReducingDemo();
|
||||
doStreamCollectingDemo();
|
||||
doStreamParallelDemo();
|
||||
}
|
||||
|
||||
private static void doStreamFilterDemo() {
|
||||
out.println("FILTER EXAMPLE");
|
||||
getDishes().stream()
|
||||
.filter(Dish::isVegetarian)
|
||||
.collect(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<String> words = asList("Hello", "World");
|
||||
List<String> uniqueCharacters = words.stream()
|
||||
.map(word -> word.split(""))
|
||||
.flatMap(Arrays::stream)
|
||||
.distinct()
|
||||
.collect(toList());
|
||||
out.println(uniqueCharacters);
|
||||
out.println("----------------------------------------");
|
||||
out.println("Permutations");
|
||||
List<Integer> numbers1 = asList(1, 2, 3);
|
||||
List<Integer> numbers2 = asList(3, 4);
|
||||
List<int[]> pairs1 = numbers1.stream()
|
||||
.flatMap(i -> numbers2.stream().map(j -> new int[]{i, j}))
|
||||
.collect(toList());
|
||||
pairs1.forEach(pair -> out.println(Arrays.toString(pair)));
|
||||
out.println("----------------------------------------");
|
||||
List<int[]> pairs2 = numbers1.stream()
|
||||
.flatMap(i -> numbers2.stream().map(j -> new int[]{i, j}))
|
||||
.filter(pair -> (pair[0] + pair[1]) % 3 == 0)
|
||||
.collect(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> dish = getDishes().stream()
|
||||
.filter(Dish::isVegetarian)
|
||||
.findAny();
|
||||
dish.ifPresent(out::println);
|
||||
out.println("----------------------------------------");
|
||||
out.println("FINDFIRST EXAMPLE");
|
||||
List<Integer> someNumbers = 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<Transaction> 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(toList())
|
||||
.forEach(out::println);
|
||||
out.println("2)");
|
||||
transactions.stream()
|
||||
.map(Transaction::getTrader)
|
||||
.map(Trader::getCity)
|
||||
.distinct()
|
||||
.collect(toList())
|
||||
.forEach(out::println);
|
||||
out.println("3)");
|
||||
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(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("----------------------------------------");
|
||||
}
|
||||
|
||||
private static void doStreamCollectingDemo() {
|
||||
List<Dish> menu = getDishes();
|
||||
long howManyDishes = menu.stream().count();
|
||||
out.println(howManyDishes);
|
||||
out.println("----------------------------------------");
|
||||
Comparator<Dish> 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<Dish.Type, List<Dish>> dishesByType = menu.stream().collect(groupingBy(Dish::getType));
|
||||
out.println(dishesByType);
|
||||
out.println("----------------------------------------");
|
||||
Map<CaloricLevel, List<Dish>> 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<Dish.Type, List<Dish>> caloricDishesByType =
|
||||
menu.stream()
|
||||
.collect(groupingBy(Dish::getType,
|
||||
filtering(dish -> dish.getCalories() > 500,
|
||||
toList())));
|
||||
out.println(caloricDishesByType);
|
||||
out.println("----------------------------------------");
|
||||
Map<Dish.Type, List<String>> dishNamesByType =
|
||||
menu.stream()
|
||||
.collect(groupingBy(Dish::getType,
|
||||
mapping(Dish::getName, toList())));
|
||||
out.println(dishNamesByType);
|
||||
out.println("----------------------------------------");
|
||||
Map<String, List<String>> 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<Dish.Type, Set<String>> dishNamesByType2 =
|
||||
menu.stream()
|
||||
.collect(groupingBy(Dish::getType,
|
||||
flatMapping(dish -> {
|
||||
// FIXME: The example of book is not safety
|
||||
List<String> tags = dishTags.get(dish.getName());
|
||||
if (tags != null) {
|
||||
return tags.stream();
|
||||
}
|
||||
return Stream.empty();
|
||||
}, toSet())));
|
||||
out.println(dishNamesByType2);
|
||||
out.println("----------------------------------------");
|
||||
Map<Dish.Type, Map<CaloricLevel, List<Dish>>> 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("----------------------------------------");
|
||||
Map<Boolean, List<Dish>> partitionedMenu = menu.stream().collect(partitioningBy(Dish::isVegetarian));
|
||||
out.println(partitionedMenu);
|
||||
out.println("----------------------------------------");
|
||||
Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType =
|
||||
menu.stream().collect(partitioningBy(Dish::isVegetarian, groupingBy(Dish::getType)));
|
||||
out.println(vegetarianDishesByType);
|
||||
out.println("----------------------------------------");
|
||||
Map<Boolean, Dish> 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<Dish> dishes = menu.stream()
|
||||
.filter(Dish::isVegetarian)
|
||||
.collect(new ToListCollector<>());
|
||||
out.println(dishes);
|
||||
out.println("----------------------------------------");
|
||||
out.println(partitionPrimesWithCustomCollector(100));
|
||||
out.println("----------------------------------------");
|
||||
}
|
||||
|
||||
private static void doStreamParallelDemo() {
|
||||
out.println("ForkJoin result (1, 100) = " + forkJoinSum(100));
|
||||
out.println("----------------------------------------");
|
||||
Stream<Character> stream1 = IntStream.range(0, SENTENCE.length()).mapToObj(SENTENCE::charAt);
|
||||
out.printf("Found %d words\n", countWords(stream1));
|
||||
out.println("----------------------------------------");
|
||||
Spliterator<Character> spliterator = new WordCounterSpliterator(SENTENCE);
|
||||
Stream<Character> stream2 = StreamSupport.stream(spliterator, true);
|
||||
out.printf("Found %d words\n", countWords(stream2));
|
||||
out.println("----------------------------------------");
|
||||
}
|
||||
|
||||
private static int countWords(Stream<Character> 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<Long> task = new ForkJoinSumCalculator(numbers);
|
||||
return new ForkJoinPool().invoke(task);
|
||||
}
|
||||
|
||||
public static Map<Boolean, List<Integer>> 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<Boolean, List<Integer>> partitionPrimesWithCustomCollector(int n) {
|
||||
return IntStream.rangeClosed(2, n).boxed().collect(new PrimeNumbersCollector());
|
||||
}
|
||||
|
||||
enum CaloricLevel {DIET, NORMAL, FAT}
|
||||
|
||||
private static List<Dish> getDishes() {
|
||||
List<Dish> dishes = 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Double> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<T, D, K> {
|
||||
private final Collector<? super T, ?, Map<K, D>> collector;
|
||||
|
||||
public GroupingBuilder(Collector<? super T, ?, Map<K, D>> collector) {
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
public Collector<? super T, ?, Map<K, D>> get() {
|
||||
return collector;
|
||||
}
|
||||
|
||||
public <J> GroupingBuilder<T, Map<K, D>, J> after(Function<? super T, ? extends J> classifier) {
|
||||
return new GroupingBuilder<>(groupingBy(classifier, collector));
|
||||
}
|
||||
|
||||
public static <T, D, K> GroupingBuilder<T, List<T>, K> groupOn(Function<? super T, ? extends K> classifier) {
|
||||
return new GroupingBuilder<>(groupingBy(classifier));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<LambdaOrderBuilder> consumer) {
|
||||
LambdaOrderBuilder builder = new LambdaOrderBuilder();
|
||||
consumer.accept(builder);
|
||||
return builder.order;
|
||||
}
|
||||
|
||||
public void forCustomer(String customer) {
|
||||
order.setCustomer(customer);
|
||||
}
|
||||
|
||||
public void buy(Consumer<TradeBuilder> consumer) {
|
||||
trade(consumer, Trade.Type.BUY);
|
||||
}
|
||||
|
||||
public void sell(Consumer<TradeBuilder> consumer) {
|
||||
trade(consumer, Trade.Type.SELL);
|
||||
}
|
||||
|
||||
private void trade(Consumer<TradeBuilder> 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<StockBuilder> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<TradeBuilder> consumer) {
|
||||
return buildTrade(consumer, Trade.Type.BUY);
|
||||
}
|
||||
|
||||
public static TradeBuilder sell(Consumer<TradeBuilder> consumer) {
|
||||
return buildTrade(consumer, Trade.Type.SELL);
|
||||
}
|
||||
|
||||
private static TradeBuilder buildTrade(Consumer<TradeBuilder> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Trade> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
17
modern-java/src/main/java/org/gym/fp/moderjava/dsl/Tax.java
Normal file
17
modern-java/src/main/java/org/gym/fp/moderjava/dsl/Tax.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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> insurance;
|
||||
|
||||
public Car(Optional<Insurance> insurance) {
|
||||
this.insurance = insurance;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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> car;
|
||||
|
||||
public Person(Optional<Car> car) {
|
||||
this.car = car;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.gym.fp.moderjava.stream;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.gym.fp.moderjava.stream;
|
||||
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
|
||||
public class ForkJoinSumCalculator extends RecursiveTask<Long> {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.gym.fp.moderjava.stream;
|
||||
|
||||
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<Integer, Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> {
|
||||
|
||||
@Override
|
||||
public Supplier<Map<Boolean, List<Integer>>> supplier() {
|
||||
return () -> new HashMap<>() {{
|
||||
put(true, new ArrayList<>());
|
||||
put(false, new ArrayList<>());
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
|
||||
return (Map<Boolean, List<Integer>> acc, Integer candidate) -> {
|
||||
acc.get(isPrime(acc.get(true), candidate))
|
||||
.add(candidate);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
|
||||
return (Map<Boolean, List<Integer>> map1, Map<Boolean, List<Integer>> map2) -> {
|
||||
map1.get(true).addAll(map2.get(true));
|
||||
map1.get(false).addAll(map2.get(false));
|
||||
return map1;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() {
|
||||
return Function.identity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Characteristics> characteristics() {
|
||||
return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH));
|
||||
}
|
||||
|
||||
private boolean isPrime(List<Integer> primes, int candidate) {
|
||||
int candidateRoot = (int) Math.sqrt(candidate);
|
||||
return primes.stream()
|
||||
.takeWhile(i -> i <= candidateRoot)
|
||||
.noneMatch(i -> candidate % i == 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.gym.fp.moderjava.stream;
|
||||
|
||||
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, A, R> =>
|
||||
// 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<T> implements Collector<T, List<T>, List<T>> {
|
||||
|
||||
/**
|
||||
* @return l'accumulatore vuoto
|
||||
*/
|
||||
@Override
|
||||
public Supplier<List<T>> supplier() {
|
||||
return ArrayList::new;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return la funzione che accumula gli elementi T in A
|
||||
*/
|
||||
@Override
|
||||
public BiConsumer<List<T>, 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<List<T>> 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<T>, List<T>> finisher() {
|
||||
return Function.identity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return insieme dei comportamenti che il collector deve assumere
|
||||
*/
|
||||
@Override
|
||||
public Set<Characteristics> characteristics() {
|
||||
return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.gym.fp.moderjava.stream;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
@AllArgsConstructor
|
||||
public class Trader {
|
||||
private final String name;
|
||||
private final String city;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.gym.fp.moderjava.stream;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
@AllArgsConstructor
|
||||
public class Transaction {
|
||||
private final Trader trader;
|
||||
private final int year;
|
||||
private final int value;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.gym.fp.moderjava.stream;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.gym.fp.moderjava.stream;
|
||||
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class WordCounterSpliterator implements Spliterator<Character> {
|
||||
private final String string;
|
||||
private int currentChar = 0;
|
||||
|
||||
public WordCounterSpliterator(String string) {
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super Character> action) {
|
||||
action.accept(string.charAt(currentChar++));
|
||||
return currentChar < string.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<Character> 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<Character> 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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user