StreamBasicsExamples.java
package fr.univtln.bruno.samples.java101.tp3.functional;
import fr.univtln.bruno.samples.java101.tp3.Person;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* Basic Stream API examples focused on collections: creation, intermediate operations and common idioms.
*/
@Slf4j
public class StreamBasicsExamples {
/**
* Private constructor to prevent instantiation.
*/
private StreamBasicsExamples() {
}
/**
* Demonstrates various ways to create streams from collections and primitives.
*/
public static void streamCreationExample() {
log.info("=== Stream Creation ===");
List<String> fromList = List.of("A", "B", "C");
log.debug("fromList snapshot: {}", fromList);
log.info("From list: {}", fromList.stream().toList());
log.info("From array: {}", Arrays.stream(new String[]{"X", "Y"}).toList());
log.info("From values: {}", Stream.of("1", "2", "3").toList());
log.info("Empty count: {}", Stream.empty().count());
log.info("Iterate limit: {}", Stream.iterate(0, n -> n + 1).limit(5).toList());
log.info("Generate random: {}", Stream.generate(Math::random).limit(3).toList());
log.info("Range: {}", IntStream.range(1, 5).boxed().toList());
log.info("RangeClosed: {}", IntStream.rangeClosed(1, 5).boxed().toList());
// Student note: infinite streams (Stream.generate / Stream.iterate without limit) can exhaust memory
// or run indefinitely if not limited. Always apply limit() or takeWhile() when experimenting.
}
/**
* Demonstrates filtering a collection using stream filters.
*/
public static void filterExample() {
log.info("=== Filter Example ===");
List<Person> people = List.of(
Person.of("Alice", "Smith", 30),
Person.of("Bob", "Jones", 25),
Person.of("Charlie", "Brown", 35),
Person.of("David", "Wilson", 28)
);
log.debug("people snapshot: {}", people);
List<String> age30 = people.stream().filter(p -> p.age() >= 30).map(Person::getFullName).toList();
log.debug("Filtered age>=30 count: {}", age30.size());
log.info("Age >=30: {}", age30);
List<String> complex = people.stream().filter(p -> p.age() >= 25).filter(p -> p.lastName().length() > 5).map(Person::getFullName).toList();
log.debug("Filtered complex pipeline count: {}", complex.size());
log.info("Age>=25 & long lastName: {}", complex);
}
/**
* Demonstrates mapping operations on streams (map, method references).
*/
public static void mapExample() {
log.info("=== Map Example ===");
List<Person> people = List.of(Person.of("Alice", "Smith", 30), Person.of("Bob", "Jones", 25));
log.info("Full names: {}", people.stream().map(Person::getFullName).toList());
log.info("Ages: {}", people.stream().map(Person::age).toList());
log.info("Upper: {}", people.stream().map(Person::getFullName).map(String::toUpperCase).toList());
}
/**
* Demonstrates flatMap for nested collections and splitting strings.
*/
public static void flatMapExample() {
log.info("=== FlatMap Example ===");
List<List<String>> nested = List.of(List.of("A", "B"), List.of("C"));
log.info("Flatten: {}", nested.stream().flatMap(Collection::stream).toList());
List<String> sentences = List.of("Hello World", "Java Streams");
log.info("Words: {}", sentences.stream().flatMap(s -> Arrays.stream(s.split(" "))).toList());
}
/**
* Demonstrates distinct/sorted/limit/skip stream terminal operations.
*/
public static void distinctSortedLimitExample() {
log.info("=== Distinct/Sorted/Limit ===");
List<Integer> nums = List.of(5, 2, 8, 2, 9, 1, 5);
log.info("Distinct: {}", nums.stream().distinct().toList());
log.info("Sorted: {}", nums.stream().sorted().toList());
log.info("Top3 desc distinct: {}", nums.stream().distinct().sorted(Comparator.reverseOrder()).limit(3).toList());
log.info("Skip first 2 sorted: {}", nums.stream().sorted().skip(2).toList());
}
/**
* Demonstrates use of peek for debugging intermediate pipeline state.
*/
public static void peekExample() {
log.info("=== Peek Example ===");
List<Integer> nums = List.of(1, 2, 3, 4, 5);
log.debug("nums initial: {}", nums);
List<Integer> result = nums.stream()
.peek(n -> log.debug("Original {}", n))
.filter(n -> n % 2 == 0)
.peek(n -> log.debug("Filtered {}", n))
.map(n -> n * 2)
.peek(n -> log.debug("Mapped {}", n))
.toList();
log.info("Result {}", result);
// Student note: Stream.toList() (since Java 16) may return an unmodifiable list; Collectors.toList()
// historically returned a mutable list. If code expects mutability, use new ArrayList<>(stream.toList())
// or Collectors.toCollection(ArrayList::new).
}
/**
* Demonstrates different sorting idioms using streams and comparators.
*/
public static void sortingExample() {
log.info("=== Sorting Example ===");
List<Person> people = List.of(Person.of("Charlie", "Brown", 35), Person.of("Alice", "Smith", 30), Person.of("Bob", "Jones", 25));
log.info("Natural: {}", people.stream().sorted().map(Person::getFullName).toList());
log.info("By age: {}", people.stream().sorted(Comparator.comparing(Person::age)).map(p -> p.getFullName() + "(" + p.age() + ")").toList());
}
/**
* Demonstrates takeWhile and dropWhile on ordered streams.
*/
public static void takeWhileDropWhileExample() {
log.info("=== takeWhile/dropWhile ===");
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
log.info("takeWhile <4: {}", numbers.stream().takeWhile(n -> n < 4).toList());
log.info("dropWhile <4: {}", numbers.stream().dropWhile(n -> n < 4).toList());
}
/**
* Simple runner for the Stream examples.
*/
public static void main(String[] args) {
streamCreationExample();
filterExample();
mapExample();
flatMapExample();
distinctSortedLimitExample();
peekExample();
sortingExample();
takeWhileDropWhileExample();
}
}