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" />
|
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||||
<outputRelativeToContentRoot value="true" />
|
<outputRelativeToContentRoot value="true" />
|
||||||
|
<module name="modernjava" />
|
||||||
<module name="scala" />
|
<module name="scala" />
|
||||||
|
<module name="modern-java" />
|
||||||
</profile>
|
</profile>
|
||||||
</annotationProcessing>
|
</annotationProcessing>
|
||||||
<bytecodeTargetLevel>
|
<bytecodeTargetLevel>
|
||||||
<module name="fpgym" target="8" />
|
<module name="fpgym" target="8" />
|
||||||
|
<module name="modern-java" target="9" />
|
||||||
|
<module name="modernjava" target="9" />
|
||||||
<module name="scala" target="1.5" />
|
<module name="scala" target="1.5" />
|
||||||
</bytecodeTargetLevel>
|
</bytecodeTargetLevel>
|
||||||
</component>
|
</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