175 votes

À quoi servent les interfaces fonctionnelles dans Java 8 ?

J'ai découvert un nouveau terme dans Java 8 : "interface fonctionnelle". Je n'ai pu trouver qu'une seule utilisation de ce terme en travaillant avec expressions lambda .

Java 8 fournit quelques interfaces fonctionnelles intégrées et si nous voulons définir une interface fonctionnelle, nous pouvons utiliser la fonction @FunctionalInterface annotation. Elle nous permettra de ne déclarer qu'une seule méthode dans l'interface.

Par exemple :

@FunctionalInterface
interface MathOperation {
    int operation(int a, int b);
}

Quelle est son utilité dans Java 8, à part le fait de travailler avec expressions lambda ?

(La question aquí est différente de celle que j'ai posée. Elle demande pourquoi nous avons besoin d'interfaces fonctionnelles lorsque nous travaillons avec des expressions lambda. Ma question est la suivante : quelles sont les autres utilisations des interfaces fonctionnelles en dehors de l'utilisation avec les expressions lambda).

1 votes

Il ressemble à ce lien. Ils expliquent également pourquoi il ne devrait y avoir qu'une seule méthode dans une interface fonctionnelle. stackoverflow.com/questions/33010594/

1 votes

@KulbhushanSingh J'ai vu cette question avant de la poster... Les deux questions sentent la différence...

139voto

Sergii Bishyr Points 4342

@FunctionalInterface est utile pour vérifier votre code à la compilation. Vous ne pouvez pas avoir plus d'une méthode en plus de static , default et les méthodes abstraites qui surchargent les méthodes dans Object dans votre @FunctionalInterface ou toute autre interface utilisée comme interface fonctionnelle.

Mais vous pouvez utiliser des lambdas sans cette annotation, de même que vous pouvez surcharger des méthodes sans l'annotation @Override annotation.

De la documentation

une interface fonctionnelle possède exactement une méthode abstraite. Puisque les méthodes par défaut ont une implémentation, elles ne sont pas abstraites. Si une interface déclare une méthode abstraite qui surmonte l'une des méthodes publiques de java.lang.Object, cette méthode n'est pas non plus comptabilisée dans le nombre de l'interface puisque toute implémentation de l'interface aura une implémentation de aura une implémentation de java.lang.Object ou d'un autre élément.

Ce site peut être utilisé dans l'expression lambda :

public interface Foo {
  public void doSomething();
}

Ce site ne peut être utilisé dans l'expression lambda :

public interface Foo {
  public void doSomething();
  public void doSomethingElse();
}

Mais cela donnera erreur de compilation :

@FunctionalInterface
public interface Foo {
  public void doSomething();
  public void doSomethingElse();
}

Annotation '@FunctionalInterface' invalide ; Foo n'est pas une interface fonctionnelle. fonctionnelle

46 votes

Pour être plus précis, vous devez avoir exactement un une méthode abstraite qui ne surcharge pas une méthode de la section java.lang.Object dans une interface fonctionnelle.

9 votes

Et c'est légèrement différent de "ne pas avoir plus d'un". public méthode en plus static y default "

0 votes

@lwpro2 une erreur de frappe. Bien sûr, il s'agissait de obj -> obj.doSomething(anyObj) . Merci de l'avoir remarqué !

51voto

Interfaces fonctionnelles ont une seule fonctionnalité à présenter. Par exemple, une interface Comparable dotée d'une seule méthode "compareTo" est utilisée à des fins de comparaison. Java 8 a défini un grand nombre d'interfaces fonctionnelles à utiliser largement dans les expressions lambda .

Il y a une annotation introduite- @FunctionalInterface qui peut être utilisé pour les erreurs au niveau du compilateur lorsque l'interface que vous avez annotée n'est pas une interface fonctionnelle valide.

@FunctionalInterface
 interface MathOperation {
      int operation(int a, int b);
 }

Essayons d'ajouter une autre méthode abstraite :

@FunctionalInterface
 interface MathOperation {
      int operation(int a, int b);
      int operationMultiply(int a, int b);
 }

Le résultat ci-dessus sera une erreur de compilation comme indiqué ci-dessous :

Unexpected @FunctionalInterface annotation
@FunctionalInterface ^ MathOperation is not a functional interface
multiple non-overriding abstract methods found in interface MathOperation

Une interface fonctionnelle est valide même si le @FunctionalInterface l'annotation serait omise. Elle sert uniquement à informer le compilateur de l'application d'une méthode abstraite unique à l'intérieur de l'interface.

 interface MathOperation {
      int operation(int a, int b);
 }

Conceptuellement, une interface fonctionnelle possède exactement une méthode abstraite. Comme les méthodes par défaut ont une implémentation, elles ne sont pas abstraites. Puisque les méthodes par défaut ne sont pas abstraites, vous Vous êtes libre d'ajouter autant de méthodes par défaut que vous le souhaitez à votre interface fonctionnelle.

Vous trouverez ci-dessous une interface fonctionnelle valide :

@FunctionalInterface
 interface MathOperation {
      int operation(int a, int b);
      default void doSomeMathOperation(){
       //Method body
      }
 }

Si une interface déclare un méthode abstraite surchargeant une des méthodes publiques de java.lang.Object, qui ne compte pas non plus. vers le nombre de méthodes abstraites de l'interface puisque toute implémentation de l'interface aura une implémentation de java.lang.Object ou autre.

Par exemple, l'interface ci-dessous est une interface fonctionnelle valide même si elle déclare deux méthodes abstraites. Pourquoi ? Parce que l'une de ces méthodes abstraites "equals()" a une signature égale à la méthode publique de la classe Object.

@FunctionalInterface
 interface MathOperation {
      int operation(int a, int b);
      @Override
      public String toString();  //Overridden from Object class
      @Override
      public boolean equals(Object obj); //Overridden from Object class
 }

Bien que l'utilisation prévue de Interfaces fonctionnelles est pour expressions lambda , références aux méthodes y références du constructeur mais elles peuvent toujours être utilisées, comme toute interface, avec des classes anonymes, implémentées par des classes, ou créées par des méthodes de fabrique.

23voto

Holger Points 13789

El documentation fait en effet une différence entre l'objectif

Un type d'annotation informatif utilisé pour indiquer qu'une déclaration de type d'interface est destinée à être une interface fonctionnelle tel que défini par la spécification du langage Java.

et le cas d'utilisation

Notez que les instances d'interfaces fonctionnelles peuvent être créées avec des expressions lambda, des références de méthodes ou des références de constructeurs.

dont le libellé n'exclut pas d'autres cas d'utilisation en général. Puisque le but premier est d'indiquer une interface fonctionnelle votre question se résume à "Y a-t-il d'autres cas d'utilisation pour interfaces fonctionnelles autres que les expressions lambda et les références aux méthodes/constructeurs ?"

Depuis interface fonctionnelle est une construction du langage Java définie par la spécification du langage Java, seule cette spécification peut répondre à cette question :

JLS §9.8. Interfaces fonctionnelles :

En plus du processus habituel de création d'une instance d'interface par la déclaration et l'instanciation d'une classe (§15.9), les instances d'interfaces fonctionnelles peuvent être créées avec des expressions de référence de méthode et des expressions lambda (§15.13, §15.27).

La spécification du langage Java ne dit pas le contraire, le seul cas d'utilisation mentionné dans cette section est celui de la création d'instances d'interface avec des expressions de référence de méthode et des expressions lambda. (Cela inclut les références de constructeur, car elles sont considérées comme une forme d'expression de référence de méthode dans la spécification).

Donc, en une phrase, non, il n'y a pas d'autre cas d'utilisation dans Java 8.

0 votes

C'est peut-être un peu trop demander ou hors sujet (vous pouvez choisir de ne pas répondre), mais que suggéreriez-vous à quelqu'un qui a créé un utilitaire ? public static String generateTaskId() versus pour le rendre plus "fonctionnel", quelqu'un d'autre a choisi de l'écrire en tant que public class TaskIdSupplier implements Supplier<String> avec le get en utilisant l'implémentation de la génération existante. S'agit-il d'une mauvaise utilisation des interfaces fonctionnelles, en particulier la réutilisation de l'implémentation de génération de Supplier à partir du JDK intégré ? PS : Je n'ai pas trouvé de meilleur endroit/Q&A pour poser cette question. Je suis heureux de migrer si vous pouvez me le suggérer.

1 votes

@Naman vous ne rendez pas la méthode utilitaire plus fonctionnelle lorsque vous créez une classe nommée TaskIdSupplier . Maintenant, la question est de savoir pourquoi vous avez créé la classe nommée. Il existe des scénarios où un tel type nommé est nécessaire, par exemple lorsque vous voulez aider à trouver l'implémentation par le biais de ServiceLoader . Il n'y a rien de mal à laisser faire Supplier alors. Mais si vous n'en avez pas besoin, ne le créez pas. Lorsque vous avez seulement besoin d'un Supplier<String> il est déjà suffisant d'utiliser DeclaringClass::generateTaskId et l'élimination de la nécessité d'une classe explicite est l'intérêt de cette fonctionnalité du langage.

0 votes

Pour être honnête, je cherchais une justification pour une recommandation que j'étais en train de passer. Pour une raison quelconque, au travail, je n'ai pas vraiment senti que la TaskIdSupplier valait la peine d'être mise en œuvre, mais ensuite le concept de ServiceLoader a totalement disparu de mon esprit. J'ai rencontré quelques questions au cours de ces discussions que nous avions, telles que Quelle est l'utilité de Supplier 's public existence quand on peut aller de l'avant et développer ses propres interfaces ? y _Pourquoi ne pas avoir public static Supplier<String> TASK_ID_SUPPLIER = () ->... comme une constante globale ?_ . (1/2)

13voto

Louis Wasserman Points 67557

Pas du tout. Les expressions lambda sont le seul et unique intérêt de cette annotation.

7 votes

Eh bien, les lamdbas fonctionnent aussi sans l'annotation. C'est une assertion tout comme @Override pour faire savoir au compilateur que vous aviez l'intention d'écrire quelque chose de "fonctionnel" (et obtenir une erreur si vous avez dérapé).

2 votes

Droit au but et à la bonne réponse, bien qu'un peu court. J'ai pris le temps d'ajouter un réponse plus élaborée dire la même chose avec plus de mots

7voto

Hank D Points 1777

Une expression lambda peut être affectée à un type d'interface fonctionnelle, mais il en va de même pour les références de méthodes et les classes anonymes.

Un aspect intéressant des interfaces fonctionnelles spécifiques dans java.util.function est qu'elles peuvent être composées pour créer de nouvelles fonctions (telles que Function.andThen y Function.compose , Predicate.and ) grâce aux méthodes par défaut pratiques qu'ils contiennent.

0 votes

Vous devriez développer davantage ce commentaire. Qu'en est-il des références de méthodes et des nouvelles fonctions ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X