Stream API (Java 8+) mahdollistaa kokoelmien käsittelyn funktionaalisessa tyylissä — tietojen suodattamisen, muunnoksen ja aggregoinnin operaatioputken kautta, ilmaistuna deklaratiivisesti (mitä tehdä) eikä eksplisiittisilla silmukoilla (miten).
Imperatiivinen vs Stream-tyyli
// ❌ imperative — explicit loop, mutable accumulator
List<String> result = new ArrayList<>();
for (Person p : people) {
if (p.getAge() >= 18) {
result.add(p.getName().toUpperCase());
}
}
// ✅ stream — declarative pipeline, reads like a description of the transformation
List<String> result = people.stream()
.filter(p -> p.getAge() >= 18) // keep adults
.map(p -> p.getName().toUpperCase()) // extract + transform names
.collect(Collectors.toList()); // gather into a list
Stream-versio ilmaisee tarkoituksen selvästi operaatioiden ketjuna ilman manuaalista silmukkaa tai akkumulaattoria.
Putkiston rakenne
Source → Intermediate operations (lazy) → Terminal operation (triggers execution)
stream() // source
.filter(...) .map(...) // intermediate — lazy, return a new stream, chainable
.collect(...) // terminal — produces a result, RUNS the pipeline
Välioperaatiot (filter, map, sorted, distinct) ovat laiskoja — ne rakentavat putkiston, mutta eivät suorita sitä ennen kuin terminaalinen operaatio (collect, forEach, reduce, count) käynnistää sen.
Yleiset operaatiot
list.stream()
.filter(x -> x > 0) // keep matching
.map(x -> x * 2) // transform each
.sorted() // sort
.distinct() // remove duplicates
.limit(10) // take first 10
.collect(Collectors.toList());
// aggregations
int sum = nums.stream().mapToInt(Integer::intValue).sum();
long count = list.stream().filter(...).count();
Optional<Person> first = people.stream().filter(...).findFirst();
boolean any = list.stream().anyMatch(x -> x > 100);
// grouping (very powerful)
Map<String, List<Person>> byCity =
people.stream().collect(Collectors.groupingBy(Person::getCity));
reduce — taita yhteen arvoon
int total = nums.stream().reduce(0, (a, b) -> a + b); // sum via reduction
Rinnakkaiset streamit
list.parallelStream().filter(...).collect(...); // process across multiple cores
// ⚠️ use only for large data + independent/stateless operations; measure first
Miksi se on tärkeää
Stream API muutti tapaa, jolla Java käsittelee tietoja — korvasi monisanaisen, virhealttiit silmukat ytimekkäillä, luettavilla, deklaratiivisilla putkistoilla suodatukseen, kartoitukseen, lajitteluun, ryhmittelyyn ja aggregointiin.
Sitä käytetään laajasti modernissa Javassa tietojen käsittelyyn, se selkeyttää koodin tarkoitusta ja integroituu lambdoihin ja menetelmäviitteisiin funktionaalista tyyliä varten.
Laiskaan välioperaatioihin / innostuneisiin pääteoperaatioihin -mallin ymmärtäminen, yleiset operaatiot (filter/map/collect/reduce/groupingBy) ja rinnakkaisten streamien vaihtoehto (niiden varoituksilla) ovat välttämättömiä idiomaattisen modernin Javan kirjoittamiselle.
Streamit ovat sekä tuottavuuden lisäys että usein esiintyvä haastattelun aihe, joka heijastaa nykyisten Java-käytäntöjen hallintaa.
