2. antislashn.org Java 8 - interfaces 2 / 34
Introduction
● Java 8 modifie le concept d'interface, en permettant à
une interface d'avoir
● des méthodes statiques
● des méthodes par défaut
● une seule méthode abstraite, pour définir une interface
fonctionnelle
3. antislashn.org Java 8 - interfaces 3 / 34
Méthode statique
● Une interface peut recevoir des méthodes statiques
● une méthode statique ne peut pas être redéfinie dans une
classe fille
● ne peut pas utiliser la référence this, puisque statique
● Les méthodes statiques d'interface ne peuvent être
utilisées que sur l'interface
● par sur les classes implémentant l'interface
● classiquement, par le nom de l'interface
4. antislashn.org Java 8 - interfaces 4 / 34
Méthode statique
● Permet de regrouper un ensemble de fonctionnalités
dans une interface
● Améliore la sécurité, car les classes filles ne peuvent
pas redéfinir la méthode statique
● Une méthode statique ne peut pas se substituer à
une méthode de la classe Object
● erreur
– "This static method cannot hide the instance method from
Object"
6. antislashn.org Java 8 - interfaces 6 / 34
Méthode par défaut
● Le qualificateur default marque une méthode par
défaut
● la classe fille n'est pas obligée de fournir une
implémentation
● this est utilisable dans la méthode par défaut
– ce n'est pas une méthode statique
7. antislashn.org Java 8 - interfaces 7 / 34
Méthode par défaut
● Exemple
public interface Roulable
{
default void rouler(){
System.out.println("Objet pouvant rouler par défaut");
}
}
public class Ballon implements Roulable
{
}
public class De implements Roulable
{
@Override
public void rouler()
{
System.out.println("valeur obtenue : "+((int)(Math.random()*6)+1));
}
}
8. antislashn.org Java 8 - interfaces 8 / 34
Méthode par défaut
● Une première utilité des méthodes par défaut est
l'intégration de nouvelles fonctionnalités sans avoir à
intervenir sur le code existant
● assure la compatibilité avec le code déjà écrit pour
l'ancienne version d'une interface
9. antislashn.org Java 8 - interfaces 9 / 34
Méthode par défaut
● Permet d'implémenter le concept de trait en Java
● le trait, ou extension, encapsule un ensemble cohérent de
méthodes
● ensemble de méthodes concrètes pouvant être ajoutée à
une classe pour étendre ses fonctionnalités
● il est composé :
– d'une méthode abstraite
– des méthodes additionnelles implémentées par le trait et utilisant
la méthode abstraite
10. antislashn.org Java 8 - interfaces 10 / 34
Méthode par défaut
● Exemple de trait
● l'interface Java Comparable possède une méthode
unique compareTo()
– cette méthode renvoie un int
● il est intéressant sémantiquement d'avoir des méthodes
telles que :
– greaterThan()
– lessThan()
– isBefore()
– isAfter()
– isSame()
11. antislashn.org Java 8 - interfaces 11 / 34
Méthode par défaut
● Exemple de trait
● les classes concrètes implémentant Orderable auront
juste à définir la méthode compareTo(), héritée de
Comparable
public interface Odrderable<T> extends Comparable<T> {
public default boolean isAfter(T other) {
return compareTo(other) > 0;
}
public default boolean isBefore(T other) {
return compareTo(other) < 0;
}
public default boolean isSameAs(T other) {
return compareTo(other) == 0;
}
}
12. antislashn.org Java 8 - interfaces 12 / 34
Méthode par défaut
● Que ce passe-t-il si deux interfaces possèdent une
méthode par défaut ayant la même signature ?
● la classe qui implémente les deux interfaces doit fournir
une implémentation de la méthode
public interface InterfaceA {
default void foo() {
System.out.println("InterfaceA - foo()");
}
}
public interface InterfaceB {
default void foo() {
System.out.println("InterfaceB - foo()");
}
}
public class ABImpl implements InterfaceA, InterfaceB {
}
13. antislashn.org Java 8 - interfaces 13 / 34
Méthode par défaut
● Il suffit alors de fournir le code pour la méthode
foo()
● exemples d'implémentation
public class ABImpl implements InterfaceA, InterfaceB {
@Override
public void foo() {
System.out.println("ABImpl - foo()");
}
}
public class ABImpl implements InterfaceA, InterfaceB {
@Override
public void foo() {
InterfaceB.super.foo();
}
}
14. antislashn.org Java 8 - interfaces 14 / 34
Interface fonctionnelle
● Interface qui possède une seule méthode abstraite
● SAM : Single Abstract Method
● l'annotation @FunctionnalInterface permet au
compilateur de vérifier que l'interface ne comporte qu'une
seule méthode abstraite
● peut posséder des méthodes par défaut
@FunctionalInterface
public interface Operation
{
int compute(int x, int y);
}
15. antislashn.org Java 8 - interfaces 15 / 34
Interface fonctionnelle
● Objectif : définir une signature de méthode qui pourra
être utilisée pour passer en paramètre :
● une référence vers une méthode statique
● une référence vers une méthode d'instance
● une référence vers un constructeur
● une expression lambda
● Un certains nombre d'interfaces fonctionnelles sont
fournies par Java 8 dans le package
java.util.function
16. antislashn.org Java 8 - interfaces 16 / 34
Interface fonctionnelle
● Exemple d'interface fonctionnelle
● Exemple d'utilisation de l'interface
@FunctionalInterface
public interface Operation
{
int compute(int x, int y);
}
public class Calcul
{
public static int compute(int x, int y, Operation op){
return op.compute(x,y);
}
}
17. antislashn.org Java 8 - interfaces 17 / 34
Interface fonctionnelle
● Classiquement, cette interface est implémentée par
une classe
● utilisation
public class Addition implements Operation
{
@Override
public int compute(int x, int y)
{
return x+y;
}
}
...
Operation op = new Addition();
int r = Calcul.compute(2, 2, op);
...
18. antislashn.org Java 8 - interfaces 18 / 34
Interface fonctionnelle
● Ou passée comme classe anonyme
...
r = Calcul.compute(5, 6, new Operation()
{
@Override
public int compute(int x, int y)
{
return x-y;
}
});
...
19. antislashn.org Java 8 - interfaces 19 / 34
Interface fonctionnelle
● Exemple d'une interface de création
● retourne un objet fabriqué avec trois String
● Exemple de classe utilisant l'interface
@FunctionalInterface
public interface Creator<T> {
T create(String str1, String str2, String str3);
}
public class ContactParser<T> {
public T parse(String nomComplet, Creator<T> creator) {
String[] items = nomComplet.split(" ");
String civilite = items[0];
String nom = items[1];
String prenom = items[2];
return creator.create(civilite, nom, prenom);
}
}
20. antislashn.org Java 8 - interfaces 20 / 34
Interface fonctionnelle
● Exemple de classe Contact (extrait)
● le constructeur prend 3 paramètres de type String
public class Contact {
private String civilite;
private String nom;
private String prenom;
public Contact() {}
public Contact(String civilite, String nom, String prenom) {
this.civilite = civilite;
this.nom = nom;
this.prenom = prenom;
}
...
}
21. antislashn.org Java 8 - interfaces 21 / 34
Interface fonctionnelle
● Réponse de Java 8
● sans modification de l'existant nous pouvons passer toute
méthode qui
– accepte les mêmes types de paramètre
● 3 paramètres de type String
– retourne le même type
● générique T
22. antislashn.org Java 8 - interfaces 22 / 34
Interface fonctionnelle
● Avec Java 8, nous pouvons éviter la création d'une
classe anonyme de type Creator<Contact>
● par une référence vers le constructeur de Contact
– la syntaxe ::<method> définit une référence vers une méthode
● ici il y a bien un constructeur Contact(String,String, String)
ContactParser<Contact> parser = new ContactParser<>();
Contact contact = parser.parse("M LAGAFFE Gaston", Contact::new);
public class ContactParser<T> {
public T parse(String nomComplet, Creator<T> creator) {
,,,
return creator.create(civilite, nom, prenom);
}
}
23. antislashn.org Java 8 - interfaces 23 / 34
Référence à une méthode
● Syntaxe permettant de référencer directement une
méthode ou un constructeur
● opérateur ::
● référence à un constructeur par défaut
– sans paramètre
● référence à une méthode
– statique ou non
System.out::println o -> System.out.println(o)est équivalent à
24. antislashn.org Java 8 - interfaces 24 / 34
Référence à une méthode
● Exemples
public class Voiture
{
public static Voiture create(final Supplier<Voiture> supplier){
return supplier.get();
}
public void rouler(){
System.out.println("Rouler");
}
}
public static void main(String[] args)
{
List<Voiture> voitures = new ArrayList<>();
voitures.add(Voiture.create(Voiture::new));
voitures.add(Voiture.create(Voiture::new));
voitures.add(Voiture.create(Voiture::new));
voitures.forEach(Voiture::rouler);
}
25. antislashn.org Java 8 - interfaces 25 / 34
java.util.function
● Nombreuses interfaces fonctionnelles
● définies avec des types génériques
● Interfaces de base :
● Consumer
– accepte un argument T et ne retourne pas de résultat
● Function
– accepte un argument T et retourne un résultat R
● Supplier
– ne prend pas d'argument et retourne un résultat T
● Predicate
– test un valeur T et retourne un booléen
26. antislashn.org Java 8 - interfaces 26 / 34
java.util.function.Consumer
● Abstraction d'une opération acceptant un seul
argument et ne renvoyant aucun résultat
● méthodes
– accept(T t) : exécute une opération sur le paramètre
● méthode abstraite
– andThen(Consumer<? super T> after) : exécute
l'opération accept puis l'opération accept sur after
27. antislashn.org Java 8 - interfaces 27 / 34
java.util.function.Consumer
● Exemple
List<String> types = new ArrayList<>(Arrays.asList("rock","trip hop","jazz","pop","rock"));
List<String> result = new ArrayList<>();
Consumer<String> c1 = result::add;
Consumer<String> c2 = System.out::println;
Consumer<String> c3 = c1.andThen(c2);
types.stream().forEach(c3); // BAD PATTERN (result::add)
System.out.println(result);
28. antislashn.org Java 8 - interfaces 28 / 34
java.util.function.Supplier
● Abstraction d'une fonction retournant une valeur
● le Supplier produit une valeur
– abstraction d'un factory
● le Consumer consomme une valeur
● méthode
– T get() : produit une valeur de type T
● méthode abstraite
29. antislashn.org Java 8 - interfaces 29 / 34
java.util.function.Supplier
● Exemples
Supplier<Point> pointSupplier = new Supplier<Point>(){
private int i = 0;
@Override
public Point get(){
i++;
return new Point(i,i);
}
};
Point p1 = pointSupplier.get();
Point p2 = pointSupplier.get();
Supplier<Point> pointSupplier = Point::new;
Point p1 = pointSupplier.get();
Point p2 = pointSupplier.get();
30. antislashn.org Java 8 - interfaces 30 / 34
java.util.function.Function
● Abstraction d'une fonction acceptant un paramètre et
retournant un résultat
● Function<T,R> : T argument, R résultat
● méthodes
– R apply(T t) : applique la fonction à l'argument t
– <T> Function<T,T> identity() : retourne toujours l'argument
– <V> Function<R,V> andThen(Function<R,V> after) :
retourne une fonction qui applique la fonction, puis applique after sur
le résultat
– <V> Function<V,R> compose(Function<V,T> before) :
retourne une fonction qui applique before, puis applique la fonction
sur le résultat de before
31. antislashn.org Java 8 - interfaces 31 / 34
java.util.function.Function
● Exemple
List<Point> points = new ArrayList<>();
initPoints(points);
Function<Point,Integer> f1 = p -> p.getX();
Stream<Point> stream = points.stream();
Stream<Integer> xs = stream.map(f1);
xs.forEach(System.out::println);
32. antislashn.org Java 8 - interfaces 32 / 34
java.util.function.Predicate
● Abstraction d'un prédicat (fonction retournant true
ou false)
● méthodes
– test(T t) : évalue le prédicat sur t
● méthode abstraite
– and(), or(), isEqual(), negate() : permet l'évaluation et le
chaînage des prédicats
33. antislashn.org Java 8 - interfaces 33 / 34
java.util.function.Predicate
● Exemple
List<String> types = new ArrayList<>(Arrays.asList("rock","trip hop","jazz","pop","rock"));
Predicate<String> p1 = s -> s.length() >3;
Predicate<String> p2 = s -> s.length() <5;
List<String> result = types.stream().filter(p1.and(p2)).collect(Collectors.toList());
System.out.println(result);
34. antislashn.org Java 8 - interfaces 34 / 34
java.util.function
● Les interfaces de base servent à définir de
nombreuses interfaces fonctionnelles sur les types
de base
● IntConsumer
● LongToIntFunction
● DoubleSupplier
● cf. javadoc