Les changements d’interface de Java 8 comprennent des méthodes statiques et des méthodes par défaut dans les interfaces. Avant Java 8, nous ne pouvions avoir que des déclarations de méthode dans les interfaces. Mais depuis Java 8, nous pouvons avoir des méthodes par défaut et des méthodes statiques dans les interfaces.
Interface Java 8
La conception des interfaces a toujours été difficile car si nous voulons ajouter des méthodes supplémentaires dans les interfaces, cela nécessitera des modifications dans toutes les classes implémentant ces interfaces. À mesure que l’interface vieillit, le nombre de classes qui l’implémentent peut augmenter à un point tel qu’il n’est plus possible d’étendre les interfaces. C’est pourquoi, lors de la conception d’une application, la plupart des frameworks fournissent une classe d’implémentation de base que nous étendons et dans laquelle nous remplaçons les méthodes qui sont applicables à notre application. Examinons les méthodes par défaut des interfaces et les méthodes statiques des interfaces, ainsi que la raison de leur introduction dans les changements d’interface de Java 8.
Méthode par défaut de l’interface Java
Pour créer une méthode par défaut dans une interface Java, nous devons utiliser le mot-clé « default » avec la signature de la méthode. Par exemple,
package com.journaldev.java8.defaultmethod;
public interface Interface1 {
void method1(String str);
default void log(String str){
System.out.println("I1 logging::"+str);
}
}
Remarquez que log(String str) est la méthode par défaut dans l’interface Interface1
. Maintenant, lorsqu’une classe implémentera Interface1, il ne sera pas obligatoire de fournir une implémentation pour les méthodes par défaut de l’interface. Cette fonctionnalité nous aidera à étendre les interfaces avec des méthodes supplémentaires, tout ce dont nous avons besoin est de fournir une implémentation par défaut. Supposons que nous ayons une autre interface avec les méthodes suivantes :
package com.journaldev.java8.defaultmethod;
public interface Interface2 {
void method2();
default void log(String str){
System.out.println("I2 logging::"+str);
}
}
Nous savons que Java ne nous permet pas d’étendre plusieurs classes car cela entraînerait le « problème du diamant » où le compilateur ne peut pas décider quelle méthode de superclasse utiliser. Avec les méthodes par défaut, le problème du diamant se poserait également pour les interfaces. Car si une classe implémente à la fois Interface1
et Interface2
et ne met pas en œuvre la méthode par défaut commune, le compilateur ne peut pas décider laquelle choisir. Étendre plusieurs interfaces est une partie intégrante de Java, vous le trouverez dans les classes Java de base ainsi que dans la plupart des applications d’entreprise et des frameworks. Ainsi, pour s’assurer que ce problème ne se produira pas dans les interfaces, il est obligatoire de fournir une implémentation pour les méthodes par défaut communes des interfaces. Donc, si une classe implémente les deux interfaces ci-dessus, elle devra fournir une implémentation pour la méthode log()
sinon le compilateur générera une erreur de compilation. Une classe simple qui implémente à la fois Interface1
et Interface2
sera :
package com.journaldev.java8.defaultmethod;
public class MyClass implements Interface1, Interface2 {
@Override
public void method2() {
}
@Override
public void method1(String str) {
}
@Override
public void log(String str){
System.out.println("MyClass logging::"+str);
Interface1.print("abc");
}
}
Points importants sur les méthodes par défaut des interfaces Java :
- Les méthodes par défaut des interfaces Java nous aideront à étendre les interfaces sans craindre de casser les classes d’implémentation.
- Les méthodes par défaut des interfaces Java ont réduit les différences entre les interfaces et les classes abstraites.
- Les méthodes par défaut des interfaces Java 8 nous aideront à éviter les classes utilitaires, telles que toutes les méthodes de la classe Collections peuvent être fournies directement dans les interfaces elles-mêmes.
- Les méthodes par défaut des interfaces Java nous aideront à supprimer les classes d’implémentation de base, nous pouvons fournir une implémentation par défaut et les classes d’implémentation peuvent choisir celle à substituer.
- L’une des principales raisons d’introduire des méthodes par défaut dans les interfaces est d’améliorer l’API Collections en Java 8 pour prendre en charge les expressions lambda.
- Si une classe dans la hiérarchie a une méthode avec la même signature, alors les méthodes par défaut deviennent sans importance. Une méthode par défaut ne peut pas substituer une méthode de la classe
java.lang.Object
. La raison est très simple, c’est parce que Object est la classe de base pour toutes les classes Java. Donc même si nous avons des méthodes de classe Object définies comme des méthodes par défaut dans les interfaces, elles seront inutiles car les méthodes de classe Object seront toujours utilisées. C’est pourquoi, pour éviter toute confusion, nous ne pouvons pas avoir de méthodes par défaut qui substituent les méthodes de classe Object. - Les méthodes par défaut des interfaces Java sont également appelées méthodes défenseur ou méthodes d’extension virtuelles.
Méthode statique d’interface Java
La méthode statique de l’interface Java est similaire à la méthode par défaut, sauf que nous ne pouvons pas les remplacer dans les classes d’implémentation. Cette fonctionnalité nous aide à éviter les résultats indésirables en cas de mauvaise implémentation dans les classes d’implémentation. Regardons cela avec un exemple simple.
package com.journaldev.java8.staticmethod;
public interface MyData {
default void print(String str) {
if (!isNull(str))
System.out.println("MyData Print::" + str);
}
static boolean isNull(String str) {
System.out.println("Interface Null Check");
return str == null ? true : "".equals(str) ? true : false;
}
}
Maintenant, voyons une classe d’implémentation qui a une méthode isNull() avec une mauvaise implémentation.
package com.journaldev.java8.staticmethod;
public class MyDataImpl implements MyData {
public boolean isNull(String str) {
System.out.println("Impl Null Check");
return str == null ? true : false;
}
public static void main(String args[]){
MyDataImpl obj = new MyDataImpl();
obj.print("");
obj.isNull("abc");
}
}
Remarquez que isNull(String str)
est une méthode de classe simple, elle ne remplace pas la méthode d’interface. Par exemple, si nous ajoutons l’annotation @Override à la méthode isNull(), cela entraînera une erreur de compilation. Maintenant, lorsque nous exécutons l’application, nous obtenons la sortie suivante.
Interface Null Check
Impl Null Check
Si nous passons la méthode d’interface de statique à par défaut, nous obtiendrons la sortie suivante.
Impl Null Check
MyData Print::
Impl Null Check
La méthode statique de l’interface Java est visible uniquement pour les méthodes d’interface, si nous supprimons la méthode isNull() de la classe MyDataImpl
, nous ne pourrons pas l’utiliser pour l’objet MyDataImpl
. Cependant, comme pour les autres méthodes statiques, nous pouvons utiliser les méthodes statiques de l’interface en utilisant le nom de la classe. Par exemple, une déclaration valide sera:
boolean result = MyData.isNull("abc");
Points importants sur la méthode statique de l’interface Java:
- La méthode statique de l’interface Java fait partie de l’interface, nous ne pouvons pas l’utiliser pour les objets de classe d’implémentation.
- Les méthodes statiques de l’interface Java sont utiles pour fournir des méthodes utilitaires, par exemple la vérification de nullité, le tri de collections, etc.
- L’interface statique de Java nous aide à assurer la sécurité en empêchant les classes d’implémentation de les remplacer.
- On ne peut pas définir de méthode statique d’interface pour les méthodes de la classe Object; sinon, une erreur de compilation survient avec le message « Cette méthode statique ne peut pas masquer la méthode d’instance de Object ». Cela n’est pas autorisé en Java, car Object est la classe de base pour toutes les classes et il n’est pas possible d’avoir une méthode statique au niveau de la classe et une autre méthode d’instance avec la même signature.
- Nous pouvons utiliser les méthodes statiques d’interface Java pour supprimer les classes utilitaires telles que Collections et déplacer toutes ses méthodes statiques vers l’interface correspondante, ce qui faciliterait leur recherche et leur utilisation.
Interfaces fonctionnelles en Java
Avant de conclure le post, j’aimerais fournir une brève introduction aux interfaces fonctionnelles. Une interface avec exactement une méthode abstraite est connue sous le nom d’interface fonctionnelle. Une nouvelle annotation @FunctionalInterface a été introduite pour marquer une interface en tant qu’interface fonctionnelle. L’annotation @FunctionalInterface est une facilité pour éviter l’ajout accidentel de méthodes abstraites dans les interfaces fonctionnelles. C’est facultatif mais une bonne pratique de l’utiliser. Les interfaces fonctionnelles sont une fonctionnalité attendue depuis longtemps et très recherchée de Java 8 car elle nous permet d’utiliser des expressions lambda pour les instancier. Un nouveau package java.util.function
avec un tas d’interfaces fonctionnelles a été ajouté pour fournir des types cibles pour les expressions lambda et les références de méthode. Nous examinerons les interfaces fonctionnelles et les expressions lambda dans les futurs articles.