Esempi di collector e custom collector
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package org.gym.fp.moderjava;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
import static java.util.stream.Collector.Characteristics.IDENTITY_FINISH;
|
||||
|
||||
public class PrimeNumbersCollector implements Collector<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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public class StreamTest {
|
||||
new Transaction(mario, 2012, 710),
|
||||
new Transaction(mario, 2012, 700),
|
||||
new Transaction(alan, 2012, 950)
|
||||
);
|
||||
);
|
||||
out.println("1)");
|
||||
transactions.stream()
|
||||
.filter(t -> t.getYear() == 2011)
|
||||
@@ -183,7 +183,7 @@ public class StreamTest {
|
||||
.flatMap(a -> IntStream.rangeClosed(a, 100)
|
||||
.mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)})
|
||||
.filter(t -> t[2] % 1 == 0)
|
||||
)
|
||||
)
|
||||
.limit(5)
|
||||
.forEach(triple -> out.printf("(%.0f, %.0f, %.0f)\n", triple[0], triple[1], triple[2]));
|
||||
out.println("----------------------------------------");
|
||||
@@ -231,14 +231,14 @@ public class StreamTest {
|
||||
Map<Dish.Type, List<Dish>> caloricDishesByType =
|
||||
menu.stream()
|
||||
.collect(groupingBy(Dish::getType,
|
||||
filtering(dish -> dish.getCalories() > 500,
|
||||
toList())));
|
||||
filtering(dish -> dish.getCalories() > 500,
|
||||
toList())));
|
||||
out.println(caloricDishesByType);
|
||||
out.println("----------------------------------------");
|
||||
Map<Dish.Type, List<String>> dishNamesByType =
|
||||
menu.stream()
|
||||
.collect(groupingBy(Dish::getType,
|
||||
mapping(Dish::getName, toList())));
|
||||
mapping(Dish::getName, toList())));
|
||||
out.println(dishNamesByType);
|
||||
out.println("----------------------------------------");
|
||||
Map<String, List<String>> dishTags = Map.of(
|
||||
@@ -251,18 +251,18 @@ public class StreamTest {
|
||||
"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())));
|
||||
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 =
|
||||
@@ -278,6 +278,43 @@ public class StreamTest {
|
||||
})));
|
||||
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("----------------------------------------");
|
||||
}
|
||||
|
||||
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}
|
||||
@@ -291,7 +328,7 @@ public class StreamTest {
|
||||
new Dish("tomato", 30, Dish.Type.VEGETARIAN),
|
||||
new Dish("tunny", 120, Dish.Type.FISH),
|
||||
new Dish("potato", 70, Dish.Type.VEGETARIAN)
|
||||
);
|
||||
);
|
||||
return Collections.unmodifiableList(dishes);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.gym.fp.moderjava;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
import static java.util.stream.Collector.Characteristics.CONCURRENT;
|
||||
import static java.util.stream.Collector.Characteristics.IDENTITY_FINISH;
|
||||
|
||||
// Collector<T, 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));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user