Retrolambda: lambda expression anche su Java 7

Non vedete l’ora di poter lavorare in modo funzionale con le espressioni lambda anche in Java? Purtroppo però siete bloccati su Java 7 e potete solo sognarle la notte… Almeno fino ad oggi! Esiste un progetto molto interessante su GitHub che porta le espressioni lambda su Java 7 (e in teoria anche prima), vediamo insieme cosa offre.

Vade retro

Basta con le anonymous class che complicano la lettura del codice: da oggi anche in Java 7 possiamo ordinare una lista di numeri in modo decrescente così:

List<Integer> numbers = Arrays.asList(5,3,4,6);
Collections.sort(numbers, (n1, n2) -> n2.compareTo(n1));

Come è possibile? Il trucco c’è ma non si vede! Intanto è necessario compilare il codice in Java 8,

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.2</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

e con l’aggiunta di questo plugin Maven:

<plugin>
    <groupId>net.orfjackal.retrolambda</groupId>
    <artifactId>retrolambda-maven-plugin</artifactId>
    <version>2.0.0</version>
    <executions>
        <execution>
            <goals>
                <goal>process-main</goal>
                <goal>process-test</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <target>1.7</target>
        <fork>false</fork>
    </configuration>
</plugin>

il gioco è fatto ed il codice gira anche su Java 7! In fase di compilazione, in poche parole le espressioni lambda vengono sostituite in classi anonime, con l’accortezza che per quelle stateless vengono creati dei singleton in modo da risparmiare memoria.

Non è tutto oro quel che luccica

Balza subito all’occhio che il compile level deve per forza essere portato a Java 8, il che ci permetterebbe di usare anche gli streamATTENZIONE quindi!! Retrolambda non è un backport dell’API Java 8! C’è da fare quindi molta attenzione a cosa si può e cosa non si può usare di Java 8.

Quello che sicuramente funziona sono le espressioni lambda e i method reference. Come fare a verificare che non stiamo scrivendo codice retrocompatibile? I test su una JRE 7 sono d’obbligo a questo punto!

Compila Java 8, Testa Java 7

I test su Java 7 sono l’unico modo per essere sicuri di aver scritto codice funzionante. Fortunatamente Maven ci viene incontro, e ci permette di specificare una JRE diversa per i test tramite una variabile d’ambiente da passare al plugin surefire (stessa cosa vale anche per i test di integrazione con failsafe):

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.18.1</version>
    <configuration>
        <jvm>${JAVA7_HOME}/bin/java</jvm>
    </configuration>
</plugin>

Siete della filosofia “a cosa servono i test?”. Il tempo impiegato per fare i test ha sicuramente un alto valore in questo contesto (non ci sono più scuse per non farli 😉 ). Per maggiori dettagli su surefire e failsafe date un’occhiata al post sui test di integrazione.

Tutto qui? No stream, no party?

Volevate anche gli stream? Purtroppo questo è un altro film, possiamo però trarre grandi vantaggi dalle lambda expressions se già usare Guava o RxJava. Qualche esempio? Sicuramente per quanto riguarda Guava, è piuttosto snello filtrare, per esempio, una lista di articoli per numero di visite così:

Predicate<Article> filter = article -> article.getViewCount() > 20;
Collection<Article> collect = Collections2.filter(articles, filter);

invece che

Predicate<Article> filter = new Predicate<Article>() {

      @Override
      public boolean apply(Article article) {
         return article.getViewCount() > 20;
      }
};
Collection<Article> collect = Collections2.filter(articles, filter);

Retrolambda esegue questa trasformazione per noi in compilazione.

La classe Observable di RxJava espone una API molto simile agli Stream di Java 8, ma è pensata soprattutto per l’elaborazione in modo asincrono, quindi può non essere comodo per manipolare collezioni nella sua interezza, anche se fattibile. Su GitHub è presente un progetto di test per Retrolambda con alcune prove anche con RxJava.

Conclusioni

Con qualche attenzione all’API da non utilizzare (leggi streams), possiamo portarci a casa le lambda expressions anche in Java 7 con poco sforzo, e tutti vissero felici e contenti (con i test 😉 )

Andrea Como

Sono un software engineer focalizzato nella progettazione e sviluppo di applicazioni web in Java. Presso OmniaGroup ricopro il ruolo di Tech Leader sulle tecnologie legate alla piattaforma Java EE 5 (come WebSphere 7.0, EJB3, JPA 1 (EclipseLink), JSF 1.2 (Mojarra) e RichFaces 3) e Java EE 6 con JBoss AS 7, in particolare di CDI, JAX-RS, nonché di EJB 3.1, JPA2, JSF2 e RichFaces 4. Al momento mi occupo di ECM, in particolar modo sulla customizzazione di Alfresco 4 e sulla sua installazione con tecnologie da devops come Vagrant e Chef. In passato ho lavorato con la piattaforma alternativa alla enterprise per lo sviluppo web: Java SE 6, Tomcat 6, Hibernate 3 e Spring 2.5. Nei ritagli di tempo sviluppo siti web in PHP e ASP. Per maggiori informazioni consulta il mio curriculum pubblico. Follow me on Twitter - LinkedIn profile - Google+