danilo.pianini@unibo.itgianluca.aguzzi@unibo.itangelo.filaseta@unibo.itCompiled on: 2025-12-05 — versione stampabile
List<Persona> con proprietà reddito e città, ottenere la somma dei redditi di tutte le persone di CesenaPerson – equals, hashCode e toString omessiimport java.util.Set;
public final class Person {
private final String name;
private final String city;
private final double income;
private final Set<String> jobs;
public Person(String name, String city, double income, String... jobs) {
this.name = Objects.requireNonNull(name);
this.city = city; // null in ingresso indica città assente
this.income = income;
this.jobs = Set.copyOf(Arrays.asList(jobs)); // conversione a set
}
// Getters
public String getName() { return this.name; }
public String getCity() { return this.city; }
public double getIncome() { return this.income; }
public Set<String> getJobs() { return this.jobs; } // Set immutabile, non serve copia
// Hashcode, equals, toString
@Override public int hashCode() { return Objects.hash(name, city, income, jobs); }
@Override public boolean equals(Object obj) {
return this == obj
|| obj instanceof Person person
&& Objects.equals(name, person.name)
&& Objects.equals(city, person.city)
&& Double.compare(income, person.income) == 0
&& Objects.equals(jobs, person.jobs);
}
@Override public String toString() {
return "Person [name=" + name + ", city=" + city + ", income=" + income + ", jobs=" + jobs + "]";
public class UseStreamsOnPerson {
static void main() {
final List<Person> list = List.of(
new Person("Mario", "Cesena", 20000, "Teacher"),
new Person("Rino", "Forlì", 50000, "Professor"),
new Person("Lino", "Cesena", 110000, "Professor", "Dean"),
new Person("Ugo", "Cesena", 20000, "Secretary"),
new Person("Marco", null, 4000, "Contractor")
);
final double result = list.stream()
.filter(it -> "Cesena".equals(it.getCity())) // Tieni solo i cesenati
.mapToDouble(Person::getIncome) // Prendi il loro reddito
.sum(); // Somma
System.out.println(result);
// alternativa con iteratore: qual è la più leggibile?
double totalIncome = 0; // inizializza somma
for (final Person p: list) { // per ogni persona nella lista
if ("Cesena".equals(p.getCity())) { // se la città è cesena
totalIncome = totalIncome + p.getIncome(); // allora la somma aumenta del suo reddito
}
}
System.out.println(totalIncome);
}
}
java.util.stream: interfacce e classi per gli streamStream<X>: stream e metodi statici di “factory”BaseStream<X,B>: sopra-interfaccia di Stream con i metodi baseDoubleStream: stream di double, con metodi base e specificiIntStream, LongStream: similiCollector<T,A,R>: rappresenta una operazione di riduzioneCollectors: fornisce una serie di collettoripublic interface Collection<E> extends Iterable<E> {
..
Iterator<E> iterator();
default boolean removeIf(Predicate<? super E> filter) {..}
default Spliterator<E> spliterator() {..}
default Stream<E> stream() {..}
default Stream<E> parallelStream() {..}
}
java.util.BaseStreampublic interface BaseStream<T, S extends BaseStream<T, S>> extends ... {
// Torna un iteratore sugli elementi rimasti dello stream, e lo chiude
Iterator<T> iterator();
// spliterator è un iteratore che supporta parallelismo..
Spliterator<T> spliterator();
// è uno stream gestibili in modalità parallela
boolean isParallel();
// torna una variante sequenziale dello stream
S sequential();
// torna una variante parallela dello stream
S parallel();
// torna una variante non ordinata dello stream
S unordered();
// associa un handler chiamato alla chiusura dello stream
S onClose(Runnable closeHandler);
void close();
}
Stream<X>empty, of, iterate, generate, concatfilter, map, flatMap, distinct, sorted, peek, limit, skip, mapToXYZ,..forEach, forEachOrdered, toArray, reduce, collect, min, max, count, anyMatch, allMatch, noneMatch, findFirst, findAny,..DoubleStream e similiStream<X> con un trasformatore mapToObj() o boxed()sumjava.util.Stream: costruzione stream, 1/3public interface Stream<T> extends BaseStream<T, Stream<T>> {
// Static factories
public static<T> Stream<T> empty() {..}
public static<T> Stream<T> of(T t) {..}
public static<T> Stream<T> of(T... values) {..}
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {..}
public static<T> Stream<T> generate(Supplier<T> s) {..}
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {..}
// also recall method Collection.stream() and Collection.parallelStream()
public static<T> Builder<T> builder() {..}
public interface Builder<T> extends Consumer<T> {
void accept(T t);
default Builder<T> add(T t) {
accept(t);
return this;
}
Stream<T> build();
}
java.util.Stream: trasformazione stream, 2/3
// Stream transformation
Stream<T> filter(Predicate<? super T> predicate);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Stream<T> distinct();
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
Stream<T> peek(Consumer<? super T> action);
Stream<T> limit(long maxSize);
Stream<T> skip(long n);
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
java.util.Stream: terminazione stream, 3/3 // Terminal Operations
void forEach(Consumer<? super T> action);
void forEachOrdered(Consumer<? super T> action);
Object[] toArray();
<A> A[] toArray(IntFunction<A[]> generator);
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
<R, A> R collect(Collector<? super T, A, R> collector);
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
long count();
boolean anyMatch(Predicate<? super T> predicate);
boolean allMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);
Optional<T> findFirst();
Optional<T> findAny();
}
public class UseTransformations {
public static void main(String[] args) {
final List<Integer> li = List.of(10, 20, 30, 5, 6, 7, 10, 20, 100);
System.out.print("All\t\t :");
li.stream().forEach(i -> System.out.print(" " + i));
System.out.print("\nFilter(>10)\t :");
li.stream()
.filter(i -> i > 10) // fa passare solo certi elementi
.forEach(i -> System.out.print(" " + i));
System.out.print("\nMap(N:i+1)\t :");
li.stream()
.map(i -> "N:" + (i + 1)) // trasforma ogni elemento
.forEach(i -> System.out.print(" " + i));
System.out.print("\nflatMap(i,i+1)\t :");
li.stream()
.flatMap(i -> List.of(i, i + 1).stream()) // trasforma e appiattisce
.map(String::valueOf) // invece del forEach..
.map(" "::concat)
.forEach(System.out::print);
}
}
public class UseTransformations2 {
public static void main(String[] args) {
final List<Integer> li = List.of(10,20,30,5,6,7,10,20,100);
System.out.print("\nDistinct\t :");
li.stream().distinct() // elimina le ripetizioni
.forEach(i->System.out.print(" "+i));
System.out.print("\nSorted(down)\t :");
li.stream().sorted((i,j)->j-i) // ordina
.forEach(i->System.out.print(" "+i));
System.out.print("\nPeek(.)\t\t :");
li.stream().peek(i->System.out.print(".")) // esegue una azione per ognuno
.forEach(i->System.out.print(" "+i));
System.out.print("\nLimit(5)\t :");
li.stream().limit(5) // solo i primi 5
.forEach(i->System.out.print(" "+i));
System.out.print("\nSkip(5)\t\t :");
li.stream().skip(5) // salta i primi 5
.forEach(i->System.out.print(" "+i));
}
}
public class UseFactories {
public static void main(String[] args) {
final List<Integer> li = List.of(10,20,30,5,6,7,10,20,100);
System.out.print("Collection: ");
li.stream()
.forEach(i->System.out.print(" "+i));
System.out.print("\nEmpty: ");
Stream.empty()
.forEach(i->System.out.print(" "+i));
System.out.print("\nFromValues: ");
Stream.of("a","b","c")
.forEach(i->System.out.print(" "+i));
System.out.print("\nIterate(+1): ");
Stream.iterate(0,i->i+1) // 0,1,2,3,...
.limit(20)
.forEach(i->System.out.print(" "+i));
}
}
public class UseFactories2 {
public static void main(String[] args) {
System.out.print("\nSuppl(random): ");
Stream.generate(()->Math.random()) // rand,rand,rand,...
.limit(5)
.forEach(i->System.out.print(" "+i));
//DoubleStream.generate(()->Math.random())... stream unboxed
System.out.print("\nConcat: ");
Stream.concat(Stream.of("a","b"),Stream.of(1,2))
.forEach(i->System.out.print(" "+i));
System.out.print("\nBuilder: ");
Stream.builder()
.add(1)
.add(2)
.build()
.forEach(i->System.out.print(" "+i));
System.out.print("\nRange: ");
IntStream.range(0,20) // 0,1,..,19
.forEach(i->System.out.print(" "+i));
}
}
public class UseOtherFactories {
private final static String aDir = "/home/mirko/aula";
private final static String aFile = "/home/mirko/aula/oop/17/Counter.java";
public static void main(String[] args) throws Exception {
final Path dirPath = FileSystems.getDefault().getPath(aDir);
System.out.println("Found below "+aDir);
Files.find(dirPath, 2, (a,b)->true).forEach(System.out::println);
System.out.println("List directory "+aDir);
Files.list(dirPath).forEach(System.out::println);
final Path filePath = FileSystems.getDefault().getPath(aFile);
System.out.println("Contenuto of "+aFile);
Files.lines(filePath).forEach(System.out::println);
System.out.println("Contenuto of "+aFile+" in altra codifica");
Files.lines(filePath,StandardCharsets.ISO_8859_1).forEach(System.out::println);
// Si veda il sorgente di BufferedReader.lines() per capire come si realizza
// uno stream a partire da un iteratore
System.out.println("Stream da una stringa..");
"Hellò!".chars().mapToObj(i->(char)i).forEach(System.out::println);
}
}
public class UseTerminations {
public static void main(String[] args) {
final List<Integer> li = List.of(10,20,30,5,6,7,10,20,100);
System.out.print("ForEach:\t ");
li.stream().forEach(i->System.out.print(" "+i));
System.out.print("\nForEachOrdered: ");
li.stream().forEachOrdered(i->System.out.print(" "+i));
final Integer[] array = li.stream().toArray(i->new Integer[i]);
System.out.println("\nToArray:\t "+Arrays.toString(array));
//Integer sum = li.stream().reduce(0,(x,y)->x+y);
final Integer sum = li.stream().reduce(0,Integer::sum);
System.out.println("Sum:\t\t "+sum);
//Optional<Integer> max = li.stream().max((x,y)->x-y);
final Optional<Integer> max = li.stream().max(Integer::compare);
System.out.println("Max:\t\t "+max);
final long count = li.stream().count();
System.out.println("Count:\t\t "+count);
final boolean anyMatch = li.stream().anyMatch(x -> x==100);
System.out.println("AnyMatch:\t "+anyMatch);
final Optional<Integer> findAny = li.stream().findAny();
System.out.println("FindAny:\t "+findAny);
}
}
Stream.collectpublic class UseGeneralizedCollectors {
public static void main(String[] args) {
final List<Integer> li = List.of(10,20,30,5,6,7,10,20,100);
// Uso collect a tre argomenti
final Set<Integer> set = li.stream().collect(
()->new HashSet<>(), // oggetto collettore
(h,i)->h.add(i), // aggiunta di un elemento
(h,h2)->h.addAll(h2)); // concatenazione due collettori
System.out.println("Set: "+set); // un HashSet coi valori dello stream
// Più frequente: uso collect passandogli un collettore general-purpose
final Set<Integer> set2 = li.stream().collect(Collector.of(
HashSet::new, // oggetto collettore
HashSet::add, // aggiunta di un elemento
(h,h2)->{h.addAll(h2); return h;})); // concatenazione due collettori
System.out.println("Set: "+set2);
// cosa fa questo collettore? (.. un po' complicato)
final int res=li.stream().collect(Collector.of(
()->Arrays.<Integer>asList(0), // oggetto collettore
(l,i)->l.set(0,i+l.get(0)), // aggiunta di un elemento
(l,l2)->{l.set(0,l.get(0)+l2.get(0)); return l;})) // concatenazione
.get(0); // estrazione risultato
System.out.println("Res: "+res);
}
}
Collectorsclass Collectors { // some methods, all public static and generic..
Collector<T, ?, C> toCollection(Supplier<C> collectionFactory)
Collector<T, ?, List<T>> toList()
Collector<T, ?, Set<T>> toSet()
Collector<CharSequence, ?, String> joining(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix)
Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator)
Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator)
Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper)
Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper)
Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream)
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper)
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
Collector<T, ?, DoubleSummaryStatistics>
summarizingDouble(ToDoubleFunction<? super T> mapper)
}
UseCollectors: collettori di baseimport static java.util.stream.Collectors.*;
public class UseCollectors {
public static void main(String[] args) {
final List<Integer> li = List.of(10,20,30,5,6,7,10,20,100);
// una List
System.out.println(li.stream().collect(toList()));
// un Set
System.out.println(li.stream().collect(toSet()));
// un TreeSet
// System.out.println(li.stream().collect(toCollection(TreeSet::new)));
System.out.println(li.stream().collect(minBy(Integer::compare)));
System.out.println(li.stream().collect(summingInt(Number::intValue)).toString());
System.out.println(li.stream().map(i->i.toString())
.collect(joining(",","(",")")));
// (10,20,30,5,6,7,10,20,100)
}
}
UseCollectors: collettori di base pt 2import static java.util.stream.Collectors.*;
public class UseCollectors2 {
public static void main(String[] args) {
final List<Integer> li = List.of(10,20,30,5,6,7,10,20,100);
final Map<Integer,List<Integer>> map = li.stream()
.collect(groupingBy(x -> x/10));
System.out.println(map); // {0=[5,6,7], 1=[10,10], ..}
final Map<Boolean,Optional<Integer>> map2 = li.stream()
.collect(groupingBy(x->x%2==0,minBy(Integer::compare)));
System.out.println(map2); // minimo dei pari e minimo dei dispari
final Map<Integer,Integer> map3 = li.stream()
.distinct()
.collect(toMap(x->x,x->x+1));
System.out.println(map3); // mappa ogni x in x+1
final Map<Integer,Integer> map4 = li.stream().collect(toMap(x->x/10,x->x,(x,y)->x+y));
System.out.println(map4); // somma degli elementi in ogni decina
System.out.println(li.stream().collect(summarizingInt(Number::intValue)).toString());
}
}
Person static void main() {
final List<Person> list = new ArrayList<>();
list.add(new Person("Mario","Cesena",20000,"Teacher"));
list.add(new Person("Rino","Forlì",50000,"Professor"));
list.add(new Person("Lino","Cesena",110000,"Professor","Dean","Secretary"));
list.add(new Person("Ugo","Cesena",20000,"Secretary"));
list.add(new Person("Marco",null,4000,"Contractor"));
// Jobs of people from Cesena
final String res = list.stream()
.filter(p -> p.getCity().equals("Cesena"))
.flatMap(p->p.getJobs().stream())
.distinct()
.collect(Collectors.joining("|", "[[", "]]"));
System.out.println(res);
// Average income of professors
final double avg =
list.stream()
.filter(p->p.getJobs().contains("Professor"))
.mapToDouble(Person::getIncome)
.average().getAsDouble();
System.out.println(avg);
System.out.println(
list.stream()
.filter(p->p.getJobs().contains("Professor"))
.mapToDouble(Person::getIncome).average());
}
}
public class UseStreamsForAlgorithms {
public static void main(String[] args) {
System.out.println(
LongStream.iterate(2, x->x+1)
.filter((i)->LongStream.range(2, i/2+1).noneMatch(j -> i%j==0))
.limit(1000)
.mapToObj(String::valueOf)
.collect(Collectors.joining(",","[","]")));
final Random r = new Random();
System.out.println(
IntStream.range(0, 10000)
.map(i->r.nextInt(6)+r.nextInt(6)+2)
.boxed() // da int a Integer
.collect(groupingBy(x->x, collectingAndThen(counting(), d->d/10000.0))));
System.out.println(
"Prova di testo: indovina cosa produce la seguente computazione......"
.chars()
.mapToObj(x->String.valueOf((char)x))
.collect(groupingBy(x->x,counting()))
.entrySet()
.stream()
.sorted((e1,e2)->-Long.compare(e1.getValue(),e2.getValue()))
.limit(3)
.map(String::valueOf)
.collect(Collectors.joining(",","[","]")));
}
}
danilo.pianini@unibo.itgianluca.aguzzi@unibo.itangelo.filaseta@unibo.itCompiled on: 2025-12-05 — versione stampabile