Java 8 vs. Groovy

Lambda vs. Closure

Closures er i top 5 over de ting der har gjort Groovy til et mere produktiv miljø sammenlignet med Java.

Med Java 8 har vi også den feature til rådighed i form af lambda expressions, så det er virkelig et stort plus.

Men der er forskel på hvordan de to ting er implementeret, og det giver anledning til forskelle, og der er ulemper og fordele ved begge fremgangsmåder.

I Groovy er en closure et objekt af typen groovy.lang.Closure mens Lambdas er instancer of java.util.function.* interfaces (med default metoder). Implementationen af førstnævnte gør at Groovy compileren genererer ekstra klasse filer, f.eks. ClosureEx$_run_closure1.class, hvilket man kan argumentere er mindre strømlinet sammenlignet med den måde Java compileren håndterer lambdas.

Forskellene i implementationen er dog mest i den subtile ende af skalaen, og typisk ikke noget man bekymrer sig om i den daglige brug. I den sammenhæng er det nok mere af betydning at man skal være ret familiær med java.util.function.* interfaces for at kunne anvende lambdas i sin egne metoder, hvor det i Groovy forkommer mere ligetil.

Nedenfor er et enkelt eksempel på en metode der tager som en parameter tager en lambda hhv. closure og gør noget med den (lidt fortænkt, men viser mekanikken):

import java.util.function.*;

public class LambdaEx {

    public String example( String text, Function doSomething ) {
        return doSomething.apply( text + " " ) ;
    }

    public static void main( String[] args ) {
        String result = new LambdaEx().example( "hallo", (it) -> it + "world" ) ;
        System.out.println( result ) ;
        assert result.equals("hallo world");
    }
}

Eksempel på lambda i Java

def example( String text, Closure doSomething ) {
    doSomething( text + ' ' )
}

String result = example( 'hallo' ) { it + 'world' }
println result
assert result == 'hallo world'

Eksempel på closure i Groovy

I Java-eksemplet defineres metoden example som tager et Function-interface som parameter og invokerer apply() på den (med en parameter) og returnerer resultatet fra lambda udtrykket.

Man skal vælge det rette interface ud fra de muligheder der er i java.util.function pakken eller også skal man definere sit eget interface. I Groovy er det nok at indikere at parameteren er af type Closure. Det gøre det lidt lettere (*) og derfor også mere sandsynligt man vil anvende det i sin egen kode.

(*) Groovy eksemplet er et script så derfor er main(), den omgivende klasse og instantiering af denne implicit - det sparer en for tastearbejde når man laver scripts, men det har for så vidt ikke noget med forskellen mellem lambdas og closures at gøre.