Skip to content

Instantly share code, notes, and snippets.

@volgar1x
Created June 29, 2013 13:32
Show Gist options
  • Save volgar1x/5891113 to your computer and use it in GitHub Desktop.
Save volgar1x/5891113 to your computer and use it in GitHub Desktop.
Les nouveautés du JDK8 et de Java 8

I. Les lambdas

Introduction

Tout d'abord, qu'est-ce que les "lambdas" (ou closures). Ce sont des expressions qui permettent de créer des fonctions anonymes et ainsi de les stocker sous forme de variable. On les retrouve en C#, C++, Scala, Ruby, Python, JS, etc. Exemple :

// création d'une lambda
var lambda = function(param) {
    console.log("hello " + param);
};

// utilisation d'une lambda
lambda("world"); //=> hello world

Leur utilisation est très similaire d'un langage à un autre et leur application également. Les développeurs .NET, par exemple, en sont très friands grâce au namespace System.Linq qui leur permettent de manipuler des collections sans le moindre effort :

var myList = new List<string>();
myList.Add("hello");
myList.Add("world");
myList.Add("bonjour");
myList.Add("monde");

string result = myList.OrderBy(x => x.Length).First();
Console.WriteLine(result); //=> bonjour

En Java 8

Vous devez tout d'abord savoir ce que les Single Abstract Method, abrégées SAM, sont et leur utilisation avant Java 8. Derrière ce nom un peu barbare se cache en fait un concept tout simple : vous créez une interface avec une seule méthode, c'est tout. L'exemple qui devrait le plus vous parler est java.lang.Runnable, SAM très utilisée pour le threading. Sa définition est on ne peut plus simple :

package java.lang;

public interface Runnable {
    void run();
}

Vous pouvez ainsi l'instancier anonymement et ainsi créer une lambda en Java :

Runnable task = new Runnable() {
    public void run() {
        System.out.println("hello world");
    }
};

Thread thread = new Thread(task);
thread.join(); //=> hello world

Eh oui, les lambdas existaient déjà avant Java 8 mais leur syntaxe est quelque peu verbeuse. Le travail des développeurs de l'OpenJDK a justement été de supprimer cette verbosité et d'améliorer leurs performances. On obtient ainsi en Java 8 :

Thread thread = new Thread(() -> System.out.println("hello world"));
thread.join(); //=> hello world

On économise au moins 4 lignes de code à chaque fois (ici 6 lignes) et on va directement à l'essentiel : on veut seulement dire "hello world" ! L'autre travail aura été l'amélioration des performances. En effet, il est couteux d'instancier des classes anonymes donc au lieu de les instancier, les développeurs de l'OpenJDK ont décidé de les remplacer carrément par des méthodes. L'appel de la lambda sera ainsi remplacé par l'appel d'une méthode ce qui est beaucoup plus rapide ! (je vous laisse chercher des benchmarks)

Heureusement, les développeurs de l'OpenJDK ne se sont pas arrêtés là et on introduit une nouvelle feature : les pointeurs sur méthode. Les développeurs C# doivent sûrement les connaître au travers des delegates. Voici un exemple en Java de comment on aurait pu créer un pointeur sur méthode grâce aux lambdas :

public void myMethod() {
    System.out.println("hello world");
}

Thread thread = new Thread(() -> myMethod());
thread.join();

Nous sommes obligés de créer une lambda pour appeler la méthode. Maintenant, grâce aux pointeurs sur méthode :

public void myMethod() {
    System.out.println("hello world");
}

Thread thread = new Thread(this::myMethod);
thread.join();

Cet exemple est simple mais vous apprend au moins la syntaxe d'un pointeur sur méthode. Cette expression se décompose en deux parties : la gauche fait référence à l'objet sur laquelle la méthode sera appelée, la droite fait référence à la méthode qui sera appelée. Voici un exemple un peu plus compliqué :

public interface Printable {
    void print(String message);
}

public void printHelloWorld(Printable printable) {
    printable.print("hello world");
}

printHelloWorld(System.out::println); //=> hello world

Nous créons tout d'abord une SAM qui décrit l'utilisation de notre lambda, puis une méthode qui accepte une lambda (on qualifie ce genre de méthode de higher-order function) puis on appelle cette méthode avec pour paramètre un pointeur sur méthode de System.out#println. Ce genre d'utilisation est très pratique car on peut modifier le comportement d'une méthode sans pour autant toucher au code de celle-ci et ainsi créer du code réutilisable très facilement.

Une autre feature qui découle directement de celle présentée précédemment est la possibilité de créer un pointeur sur constructeur. Je ne vais pas m'attarder éternellement dessus et vous montrer directement la syntaxe :

public interface Factory<T> {
    T build();
}

public class MyClass {}

Factory<MyClass> factory = MyClass::new;
MyClass instance = factory.build();

Enfin, pour terminer ce chapitre, je vous redirige vers la documentation du JDK8 qui propose des nouvelles SAM standards utilisable dans vos propres projets : java.util.function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment