125 votes

Méthodes optionnelles dans l'interface Java

D'après ce que j'ai compris, si vous implémentez une interface en Java, les méthodes spécifiées dans cette interface doivent être utilisées par les sous-classes qui implémentent cette interface.

J'ai remarqué que dans certaines interfaces telles que l'interface Collection, certaines méthodes sont commentées comme étant optionnelles, mais qu'est-ce que cela signifie exactement ? Je suis un peu déconcerté car je pensais que toutes les méthodes spécifiées dans l'interface étaient obligatoires ?

0 votes

À quelles méthodes faites-vous référence ? Je ne les trouve ni dans la JavaDoc ni dans le code source.

0 votes

0 votes

240voto

Laurence Gonsalves Points 50783

Il semble qu'il y ait beaucoup de confusion dans les réponses.

Le langage Java exige que chaque méthode d'une interface soit implémentée par toutes les implémentations de cette interface. Période. Il n'y a pas d'exception à cette règle. Dire que "les collections sont une exception" suggère une compréhension très floue de ce qui se passe réellement ici.

Il est important de comprendre qu'il y a en quelque sorte deux niveaux de conformité à une interface :

  1. Ce que le langage Java peut vérifier. Cela se résume à peu près à la question suivante : existe-t-il une algunos pour chacune des méthodes ?

  2. Respecter le contrat. En d'autres termes, l'implémentation fait-elle ce que la documentation de l'interface indique qu'elle doit faire ?

    Les interfaces bien écrites comprennent une documentation expliquant exactement ce que l'on attend des implémentations. Votre compilateur ne peut pas vérifier cela pour vous. Vous devez lire la documentation et faire ce qu'elle dit. Si vous ne faites pas ce que dit le contrat, vous aurez une implémentation de l'interface dans la mesure où l'interface compilateur est concerné, mais il s'agira d'une mise en œuvre défectueuse/invalide.

Lors de la conception de l'API Collections, Joshua Bloch a décidé qu'au lieu d'avoir des interfaces très fines pour distinguer les différentes variantes des collections (par exemple : lisible, inscriptible, à accès aléatoire, etc.), il n'aurait qu'un ensemble d'interfaces très grossières, principalement Collection , List , Set y Map et de documenter certaines opérations comme étant "optionnelles". Il s'agit d'éviter l'explosion combinatoire qui résulterait d'interfaces à grain fin. De la FAQ sur la conception de l'API des collections Java :

Pour illustrer le problème dans les moindres détails, su notion de modifiabilité à la hiérarchie. Vous avez besoin de quatre nouveaux interfaces : ModifiableCollection, ModifiableSet, ModifiableList et ModifiableMap. Ce qui était auparavant une simple hiérarchie est maintenant une hétéroarchie désordonnée. Vous avez également besoin d'une nouvelle interface Iterator à utiliser avec les collections non modifiables, qui ne contient pas l'opération de suppression. Pouvez-vous maintenant supprimer l'exception UnsupportedOperationException ? Malheureusement malheureusement pas.

Prenons l'exemple des tableaux. Ils implémentent la plupart des opérations de la liste, mais pas les opérations suivantes supprimer et ajouter. Il s'agit de listes de taille fixe. Si vous voulez capturer cette notion dans la hiérarchie, vous devez ajouter deux nouvelles interfaces : VariableSizeList et VariableSizeMap. Il n'est pas nécessaire d'ajouter VariableSizeCollection et VariableSizeSet, car elles seraient identiques à ModifiableCollection et ModifiableSet. mais vous pouvez choisir de les ajouter quand même par souci de cohérence. Vous avez également besoin d'une nouvelle de ListIterator qui ne supporte pas les opérations add et remove pour aller de pair avec la liste non modifiable. Nous en sommes maintenant à dix ou douze interfaces, plus deux nouvelles interfaces Iterator, au lieu de nos quatre quatre interfaces initiales. Avons-nous terminé ? Non.

Tenez compte des journaux (tels que les journaux d'erreurs, les journaux d'audit et les journaux de pour les objets de données récupérables). Il s'agit de séquences naturelles de type "append-only", qui prennent en charge toutes les opérations de liste (remplacement). Ils nécessitent une nouvelle interface de base et un nouvel itérateur.

Qu'en est-il des collections immuables, par opposition aux (c'est-à-dire les collections qui ne peuvent pas être modifiées par le client ET qui ne changeront jamais pour une période donnée). pour aucune autre raison). [ ] distinction la plus importante, car elle permet à plusieurs threads d'accéder à une collection. d'accéder à une collection simultanément sans avoir besoin de synchronisation. L'ajout de ce support à la hiérarchie des types nécessite quatre autres interfaces.

Nous en sommes maintenant à une vingtaine d'interfaces et à cinq i presque certain qu'il y a encore des collections qui apparaissent dans la pratique qui ne s'intègrent pas proprement dans l'une ou l'autre des interfaces. Par exemple, la collection renvoyées par Map sont des collections naturelles de type "delete-only". Il existe également des collections qui rejettent certains éléments sur la base de leur valeur. sur la base de leur valeur, de sorte que nous n'avons toujours pas supprimé les exceptions d'exécution. d'exécution.

En fin de compte, nous avons estimé qu'il s'agissait d'une bonne ingénierie. de contourner l'ensemble de la question en fournissant un très petit ensemble de d'interfaces de base pouvant lever une exception au moment de l'exécution.

Lorsque les méthodes de l'API Collections sont documentées comme étant des "opérations optionnelles", cela ne signifie pas que vous pouvez simplement laisser l'implémentation de la méthode dans l'implémentation, ni que vous pouvez utiliser un corps de méthode vide (d'une part, beaucoup d'entre elles doivent renvoyer un résultat). Cela signifie plutôt qu'un choix d'implémentation valide (qui reste conforme au contrat) est de lancer une erreur de type UnsupportedOperationException .

Il convient de noter que, dans la mesure où UnsupportedOperationException est un RuntimeException vous pouvez la lancer à partir de n'importe quelle implémentation de méthode, pour autant que le compilateur soit concerné. Par exemple, vous pouvez le lancer à partir d'une implémentation de Collection.size() . Toutefois, une telle mise en œuvre constituerait une violation du contrat, car la documentation relative aux Collection.size() ne dit pas que cela est autorisé.

A part : L'approche utilisée par l'API Collections de Java est quelque peu controversée (probablement moins aujourd'hui que lorsqu'elle a été introduite pour la première fois, cependant). Dans un monde parfait, les interfaces pas ont des opérations optionnelles, et des interfaces à grain fin seraient utilisées à la place. Le problème est que Java ne prend en charge ni les types structurels déduits ni les types d'intersection, et c'est la raison pour laquelle tenter de faire les choses de la "bonne manière" finit par devenir extrêmement lourd dans le cas des collections.

31 votes

+1 pour There are no exceptions to this rule . Je me demande pourquoi cette réponse n'est pas marquée comme acceptée. Les autres réponses sont bonnes, mais vous en avez donné plus qu'il n'en faut.

10 votes

"Le langage Java exige que chaque méthode d'une interface soit implémentée par toutes les implémentations de cette interface. C'est tout. Il n'y a pas d'exception à cette règle." Sauf... quand il y en a :-) Les interfaces Java 8 peuvent spécifier une implémentation de méthode par défaut. Ainsi, en Java 8... il n'est PAS vrai que chaque méthode d'une interface doit être implémentée par chaque implémentation de l'interface, du moins pas dans le sens où vous devez coder l'implémentation dans la classe concernée.

1 votes

@DaBlick Lorsque j'ai dit "est implémentée par chaque implémentation", je ne voulais pas dire que l'implémentation de cette méthode doit résider dans le source de la classe qui l'implémente. Même avant Java 8, on peut hériter d'une implémentation d'une méthode d'interface, même à partir d'une classe qui n'implémente pas cette interface. ex : create Foo qui ne met pas en œuvre Runnable avec la méthode publique void run() . Créez maintenant une classe Bar que extends Foo y implements Runnable sans préjudice de l'application de l'article run . Il implémente toujours la méthode, bien qu'indirectement. De même, l'implémentation d'une méthode par défaut reste une implémentation.

29voto

amit Points 74385

Pour compiler une classe d'implémentation (non abstraite) d'une interface, toutes les méthodes doivent être implémentées.

Cependant Si nous considérons une méthode dont l'implémentation est une simple exception à lancer comme "non implémentée" (comme certaines méthodes dans l'outil Collection ), puis l'interface Collection L'interface est l'exception dans ce cas, et non le cas habituel. En général La classe d'implémentation doit (et va) implémenter toutes les méthodes.

Le terme "optionnel" dans collection signifie que la classe d'implémentation n'a pas à "implémenter" (selon la terminologie ci-dessus) la collection, et qu'elle lancera simplement NotSupportedException ).

Un bon exemple add() pour les collections immuables - le béton implémentera simplement une méthode qui ne fait rien d'autre que de lancer des NotSupportedException

Dans le cas de Collection Il s'agit d'éviter les arbres d'héritage désordonnés, qui rendront les programmeurs malheureux. le plus ce paradigme n'est pas conseillé et doit être évité dans la mesure du possible.


Mise à jour :

A partir de java 8, un méthode par défaut a été introduite.

Cela signifie qu'une interface peut définir une méthode, y compris sa mise en œuvre.
Cela a été ajouté afin de permettre l'ajout de fonctionnalités aux interfaces, tout en assurant la compatibilité ascendante pour les morceaux de code qui n'ont pas besoin de la nouvelle fonctionnalité.

Notez que la méthode est toujours implémentée par toutes les classes qui la déclarent, mais en utilisant la définition de l'interface.

0 votes

Au lieu de "ne pas faire de bêtises", je pense que c'est plutôt "c'est comme ça".

0 votes

@pst : I croire c'est ce à quoi les concepteurs pensaient lorsqu'ils l'ont mis en œuvre, mais je n'ai aucun moyen de le savoir avec certitude. I penser toute autre approche ne ferait que créer un désordre, mais encore une fois - je peux me tromper. Ce que j'essayais de montrer ici, c'est que cet exemple est l'exception, et non la règle : Cet exemple est l'exception, pas la règle - et bien qu'il puisse parfois être utile - pour le cas général, il devrait être évité, si possible.

12 votes

"n'a pas besoin de l'implémenter (il se contentera probablement de créer une méthode qui lance ...)". Ce qui veut dire que es la mise en œuvre de la méthode.

19voto

S.R.I Points 1323

En Java, une interface ne fait que déclarer le contrat de mise en œuvre des classes. Toutes les méthodes de cette interface doit doivent être implémentées, mais les classes qui les implémentent sont libres de les laisser non implémentées, c'est-à-dire vierges. En guise d'exemple artificiel,

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

class MyClass implements Foo {
  public void doSomething() {
     /* All of my code goes here */
  }

  public void doSomethingElse() {
    // I leave this unimplemented
  }
}

Maintenant, j'ai quitté doSomethingElse() non implémentée, laissant à mes sous-classes le soin de l'implémenter. C'est facultatif.

class SubClass extends MyClass {
    @Override
    public void doSomethingElse() {
      // Here's my implementation. 
    }
}

Toutefois, s'il s'agit d'interfaces de collecte, comme d'autres l'ont dit, elles constituent une exception. Si certaines méthodes ne sont pas implémentées et que vous les appelez, elles peuvent lancer des UnsupportedOperationException exceptions.

0 votes

Je pourrais t'embrasser, mon ami.

16voto

MByD Points 78505

Les méthodes optionnelles de l'interface Collection signifient que l'implémentation de la méthode est autorisée à lever une exception, mais qu'elle doit quand même être implémentée. Comme spécifié, les méthodes optionnelles de l'interface dans la documentation :

Certaines implémentations de collections ont des restrictions sur les éléments qu'elles peuvent contenir. ils peuvent contenir. Par exemple, certaines implémentations interdisent les éléments null et d'autres ont des restrictions sur les types de leurs éléments. Toute tentative d'ajout d'un élément inéligible lève une exception non vérifiée, généralement NullPointerException ou ClassCastException. La tentative de d'interroger la présence d'un élément inéligible peut lever une exception, ou bien renvoyer simplement false ; certaines implémentations présenteront le premier comportement. certaines implémentations auront le premier comportement et d'autres le second. Plus généralement, tenter une opération sur un élément inéligible dont l'exécution n'entraînerait pas l'insertion d'un élément inéligible dans la collection peut lever une exception ou réussir, au choix de l'outil d'implémentation. l'implémentation. De telles exceptions sont marquées comme "optionnelles" dans la de cette interface.

0 votes

Je n'ai jamais vraiment compris ce que les javadocs entendaient par optional. Je pense qu'ils voulaient dire ce que vous avez dit. Mais la plupart des méthodes sont optionnelles selon cette norme : new Runnable ( ) { @ Override public void run ( ) { throw new UnsupportedOperationException ( ) ; } } ;

0 votes

Cela ne semble pas s'appliquer aux méthodes facultatives mais plutôt cela, par exemple, add((T)null) peut être valable dans un cas, mais pas autre. En d'autres termes, celle-ci parle d'exceptions/comportements optionnels et de pour les arguments ("restrictions sur les éléments" ... "élément inéligible" ... "exceptions marquées comme facultatives") et ne traite pas de la question des méthodes facultatives .

10voto

berry120 Points 21945

Toutes les méthodes doivent être mises en œuvre pour que le code soit compilé (à l'exception de celles qui comportent un élément default dans Java 8+), mais l'implémentation n'a pas à faire quoi que ce soit d'utile d'un point de vue fonctionnel. Plus précisément, elle :

  • Peut être vide (une méthode vide).
  • Il se peut que l'on lance un UnsupportedOperationException (ou similaire)

Cette dernière approche est souvent adoptée dans les classes de collection - toutes les méthodes sont toujours implémentées, mais certaines peuvent lever une exception si elles sont appelées au moment de l'exécution.

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