Java Streams

Streams process collections declaratively — you describe what you want, not the loop that gets it.

Java
import java.util.List;
import java.util.stream.Collectors;

List<String> books = List.of("Muna Madan", "Palpasa Cafe", "Seto Dharti");

List<String> result = books.stream()
    .filter(b -> b.length() > 10)
    .map(String::toUpperCase)
    .sorted()
    .collect(Collectors.toList());

System.out.println(result);

The shape of a pipeline

  1. Source — list.stream(), Arrays.stream(arr), Stream.of(...)
  2. Intermediate operations — lazy, return a new stream
  3. Terminal operation — triggers execution, produces a result

Nothing runs until the terminal operation. A pipeline without one does nothing at all.

Intermediate operations

Java
.filter(x -> x > 10)        // keep matching
.map(x -> x * 2)             // transform each
.flatMap(List::stream)       // flatten nested collections
.distinct()                  // remove duplicates
.sorted()                    // natural order
.sorted(Comparator.comparing(Book::getPrice))
.limit(10)                   // first 10
.skip(5)                     // drop first 5
.peek(System.out::println)   // debugging only

Terminal operations

Java
.collect(Collectors.toList())
.toList()                          // Java 16+, immutable
.forEach(System.out::println)
.count()
.anyMatch(x -> x > 100)
.allMatch(x -> x > 0)
.noneMatch(x -> x < 0)
.findFirst()                       // Optional
.reduce(0, Integer::sum)

Numeric streams

Java
List<Integer> nums = List.of(5, 2, 9, 1);

int sum = nums.stream().mapToInt(Integer::intValue).sum();
OptionalDouble avg = nums.stream().mapToInt(Integer::intValue).average();
IntSummaryStatistics st = nums.stream().mapToInt(Integer::intValue).summaryStatistics();
System.out.println(st.getMax() + " " + st.getMin() + " " + st.getAverage());

Grouping and joining

Java
Map<String, List<Book>> byAuthor = books.stream()
    .collect(Collectors.groupingBy(Book::getAuthor));

Map<String, Long> countByAuthor = books.stream()
    .collect(Collectors.groupingBy(Book::getAuthor, Collectors.counting()));

String titles = books.stream()
    .map(Book::getTitle)
    .collect(Collectors.joining(", "));

When not to use streams

A stream is not automatically faster than a loop, and a long pipeline can be harder to debug. For a simple iteration with side effects, a plain for loop is clearer. Use streams where they genuinely shorten filter/map/reduce logic.

Also: a stream can be consumed once. Reusing one throws IllegalStateException.