Java 8 vs. Groovy

Streams vs. collection methods

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();

Java-versionen benytter sig af streams

List<Person> persons = ...
int oldest = persons
    .findAll { it.sex == 'male' }
    .collect { it.age }
    .max()

Groovy arbejder direkte med collections, f.eks. List

Forskellene er ikke så store set fra et kode-mæssigt synspunkt, umiddelbart er det enklere at gå til Groovy-versionen eftersom findAllcollect 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()

Groovy kan også bruge streams