Java 8 introducerer java.util.stream-pakken under overskriften "Aggregate operations". Operationer der nok mest er kendt som Map/Reduce og lignende.
Den største gevinst er nok at de skjuler den interne struktur, hvilket typisk gøre kildeteksten mere koncis. Og typisk også med mindre kobling til den omgivende kontekst, begge dele gøre det lettere f.eks. at afvikle operationer i parallelt.
Nedenfor et eksempel på hvordan man finder den ældste mand i en liste af personer skrevet i hhv. Java og Groovy:
List<Person> persons = ...;
int oldest = persons
.stream()
.filter(Person p -> p.getSex().equals("male"))
.mapToInt(Person p -> p.getAge())
.max().getAsInt();
List<Person> persons = ...
int oldest = persons
.findAll { it.sex == 'male' }
.collect { it.age }
.max()
Forskellene er ikke så store set fra et kode-mæssigt synspunkt, umiddelbart er det enklere at gå til Groovy-versionen eftersom findAll, collect m.v. fungerer direkte på de forskellige typer af collections. Men det er samtidig også ulempen, operationerne på streams er dedikeret til det ene formål og vil i visse situationer være bedre optimeret - f.eks. vil de i det ovenstående ikke lave midlertidige collections undervejs, hvilket Groovy-versionen gør.
Det er selvfølgeligt afhængigt af situationen om det vil give anledning til forskel i performance. Skulle det være så kan man bruge Groovy's closure i stedet for java.util.function.Predicate og på den måde bruge Closure sammen med streams:
List<Person> persons = ...
int oldest = persons
.stream()
.filter { it.sex == 'male' }
.mapToInt { it.age }
.max().getAsInt()