Pourquoi l'utilisation d'un caractère générique avec une instruction d'importation Java est-elle mauvaise?

StackOverflow https://stackoverflow.com/questions/147454

  •  02-07-2019
  •  | 
  •  

Question

Il est beaucoup plus pratique et plus propre d’utiliser une seule déclaration telle que

import java.awt.*;

que d'importer un groupe de classes individuelles

import java.awt.Panel;
import java.awt.Graphics;
import java.awt.Canvas;
...

Quel est le problème avec l'utilisation d'un caractère générique dans l'instruction import ?

Était-ce utile?

La solution

Le seul problème, c’est qu’il encombre votre espace de noms local. Par exemple, supposons que vous écriviez une application Swing et que vous ayez besoin de java.awt.Event , et que vous interfaciez également avec le système de calendrier de l'entreprise, qui contient com.mycompany.calendar. .Événement . Si vous importez les deux à l'aide de la méthode générique, l'une des trois choses suivantes se produit:

  1. Vous avez un conflit de nom entre java.awt.Event et com.mycompany.calendar.Event et vous ne pouvez même pas compiler.
  2. En réalité, vous ne pouvez importer qu'un seul (un seul de vos deux importations importe . * ), mais c'est le mauvais choix et vous avez du mal à comprendre pourquoi votre code prétend que le type est incorrect .
  3. Lorsque vous compilez votre code, il n'y a pas de com.mycompany.calendar.Event , mais lorsqu'il en ajoute un, votre code précédemment valide cesse soudainement de se compiler.

L'avantage de répertorier explicitement toutes les importations est que je peux dire en un coup d'œil quelle classe vous vouliez utiliser, ce qui facilite simplement la lecture du code. Si vous faites simplement une chose ponctuelle, il n'y a rien de explicitement faux , mais les futurs responsables vous remercieront pour votre clarté sinon.

Autres conseils

Voici un vote pour l'importation d'étoiles. Une instruction d'importation est destinée à importer un package , pas une classe. Il est beaucoup plus propre d'importer des paquets entiers; les problèmes identifiés ici (par exemple, java.sql.Date vs java.util.Date ) sont facilement résolus par d'autres moyens, et non vraiment par importations spécifiques et ne justifient certainement pas des importations incroyablement pédantes sur toutes les classes. Rien de plus déconcertant que d’ouvrir un fichier source et de parcourir 100 instructions d’importation.

Faire des importations spécifiques rend la refactorisation plus difficile; si vous supprimez / renommez une classe, vous devez supprimer toutes ses importations spécifiques. Si vous passez d'une implémentation à une classe différente dans le même package, vous devez réparer les importations. Bien que ces étapes supplémentaires puissent être automatisées, elles constituent un véritable gage de productivité sans réel gain.

Même si Eclipse n'effectuait pas d'importation de classe par défaut, tout le monde continuerait à importer en étoile. Je suis désolé, mais il n'y a vraiment aucune justification rationnelle pour faire des importations spécifiques.

Voici comment traiter les conflits de classes:

import java.sql.*;
import java.util.*;
import java.sql.Date;

veuillez consulter mon article Importer à la demande, c'est mal

En bref, le plus gros problème est que votre code peut casser lorsqu'une classe est ajoutée à un package que vous importez. Par exemple:

import java.awt.*;
import java.util.*;

// ...

List list;

En Java 1.1, c’était parfait; La liste a été trouvée dans java.awt et il n’ya pas eu de conflit.

Supposons maintenant que vous archiviez votre code qui fonctionne parfaitement et qu'un an plus tard, quelqu'un d'autre le charge de le modifier et utilise Java 1.2.

Java 1.2 a ajouté une interface nommée List à java.util. BOOM! Conflit. Le code qui fonctionne parfaitement ne fonctionne plus.

Ceci est une fonctionnalité du langage EVIL . Il y a une NON raison pour laquelle le code doit cesser de compiler simplement parce qu'un type est ajouté à un package ...

De plus, il est difficile pour un lecteur de déterminer lequel "Foo" vous utilisez.

Il n'est pas bon d'utiliser un caractère générique avec une instruction d'importation Java.

Dans le code propre , Robert C. Martin recommande en fait de les utiliser pour éviter longues listes d'importation.

Voici la recommandation:

  

J1: Évitez les longues listes d'importation en utilisant   Caractères génériques

     

Si vous utilisez deux classes ou plus d'un   package, puis importez le package complet   avec

     

package d'importation. *;

     

Les longues listes d’importations sont décourageantes   le lecteur. Nous ne voulons pas encombrer   les sommets de nos modules avec 80   lignes d'importations. Nous voulons plutôt le   les importations d'être une déclaration concise   à propos de quels paquets nous collaborons   avec.

     

Les importations spécifiques sont difficiles   dépendances, alors que les importations génériques   ne sont pas. Si vous importez spécifiquement un   classe, alors cette classe doit exister. Mais   si vous importez un paquet avec un   joker, pas besoin de classes particulières   exister. La déclaration d'importation simplement   ajoute le paquet au chemin de recherche   lors de la recherche de noms. Donc pas vrai   la dépendance est créée par de telles importations,   et ils servent donc à garder notre   modules moins couplés.

     

Il arrive parfois que la longue liste de   des importations spécifiques peuvent être utiles. Pour   par exemple, si vous avez affaire à   code hérité et que vous voulez savoir   quelles classes vous avez besoin pour construire des simulacres   et des talons pour, vous pouvez descendre le   liste des importations spécifiques à découvrir   les vrais noms qualifiés de tous ceux   classes et ensuite mettre le approprié   talons en place. Cependant, cette utilisation pour   les importations spécifiques sont très rares.   En outre, la plupart des IDE modernes   vous permet de convertir les caractères génériques   importations à une liste d'importations spécifiques   avec une seule commande. Donc même dans le   cas, il est préférable d’importer   caractères génériques.

     

Les importations génériques peuvent parfois causer   conflits de noms et ambiguïtés. Deux   classes avec le même nom, mais dans   différents forfaits, devront être   spécifiquement importé, ou du moins   spécifiquement qualifié lorsqu'il est utilisé. Ce   peut être une nuisance mais est assez rare   que l'utilisation des importations génériques est encore   généralement mieux que spécifique   importations.

Cela encombre votre espace de noms et vous oblige à spécifier tous les noms de classe ambigus. Cela se produit le plus souvent avec:

import java.util.*;
import java.awt.*;

...
List blah; // Ambiguous, needs to be qualified.

Cela permet également de rendre vos dépendances concrètes, car toutes vos dépendances sont listées en haut du fichier.

Performances : aucun impact sur les performances, car le code octet est identique. bien que cela conduise à des frais généraux de compilation.

Compilation : sur ma machine personnelle, la compilation d'une classe vide sans rien importer prend 100 ms, mais la même classe lorsque l'importation java. * prend 170 ms.

  1. Il est utile d’identifier les conflits de nom de classe: deux classes de même packages portant le même nom. Ceci peut être masqué avec * import.
  2. Cela rend les dépendances explicites, de sorte que toute personne devant lire votre code ultérieurement sache ce que vous voulez importer et ce que vous ne vouliez pas importer.
  3. Cela peut accélérer certaines compilations car le compilateur n'a pas à chercher dans tout le paquet pour identifier les dépendances, bien que ce ne soit généralement pas une grosse affaire avec les compilateurs modernes.
  4. Les aspects peu pratiques des importations explicites sont minimisés avec les IDE modernes. La plupart des IDE vous permettent de réduire la section d'importation afin qu'elle ne gêne pas, d'alimenter automatiquement les importations en cas de besoin et d'identifier automatiquement les importations inutilisées pour faciliter leur nettoyage.

La plupart des endroits où j'ai utilisé beaucoup de Java, font des importations explicites une partie de la norme de codage. J'utilise parfois encore * pour le prototypage rapide, puis je développe les listes d'importation (certains IDE le feront aussi pour vous) lors de la production du code.

Je préfère les importations spécifiques, car cela me permet de voir toutes les références externes utilisées dans le fichier sans regarder l'ensemble du fichier. (Oui, je sais que les références complètes ne seront pas nécessairement répertoriées. Mais je les évite autant que possible.)

Dans un projet précédent, j'avais constaté que le passage des importations-* à des importations spécifiques réduisait de moitié le temps de compilation (passant d'environ 10 minutes à environ 5 minutes). Le * -import amène le compilateur à rechercher dans chacun des packages répertoriés une classe correspondant à celle que vous avez utilisée. Ce temps peut être réduit, mais il s’agit de projets volumineux.

L'un des effets secondaires de * -import était que les développeurs copiaient et collaient les lignes d'importation courantes plutôt que de réfléchir à ce dont ils avaient besoin.

Dans le livre DDD

  

Quelle que soit la technologie de développement sur laquelle reposera la mise en œuvre, recherchez des moyens de minimiser les   travail de refactoring MODULES. En Java, il n’est pas inutile d’importer dans des classes individuelles, mais vous   peut au moins importer des packages entiers à la fois, reflétant ainsi l’intention que les packages soient des unités hautement cohérentes   tout en réduisant simultanément l’effort de modification des noms de package.

Et s'il encombre l'espace de noms local, ce n'est pas votre faute - blâmez la taille du paquet.

Le plus important est que l'importation de java.awt. * peut rendre votre programme incompatible avec une future version de Java:

Supposons que vous ayez une classe nommée "ABC", que vous utilisiez JDK 8 et que vous importiez java.util. * . Supposons maintenant que Java 9 soit sorti et qu’il ait une nouvelle classe dans le paquet java.util qui, par coïncidence, s’appelle également "ABC". Votre programme ne compilera pas maintenant sur Java 9, car le compilateur ne sait pas s'il porte le nom "ABC". vous voulez dire votre propre classe ou la nouvelle classe dans java.awt .

Vous ne rencontrerez pas ce problème si vous importez uniquement les classes de manière explicite à partir de java.awt que vous utilisez réellement.

Ressources:

Importations Java

Parmi tous les arguments valables formulés des deux côtés, je n’ai pas trouvé la principale raison pour éviter le caractère générique: j’aime pouvoir lire le code et savoir directement ce que chaque classe est, ou si sa définition n’est pas définie la langue ou le fichier, où le trouver. Si plus d'un paquet est importé avec * je dois aller chercher dans chacun d'eux pour trouver une classe que je ne reconnais pas. La lisibilité est primordiale, et j’accepte le code ne devrait pas demander à un IDE pour le lire.

  • Il n'y a pas d'impact à l'exécution, car le compilateur remplace automatiquement * par des noms de classe concrets. Si vous décompilez le fichier .class, vous ne verrez jamais importer ... * .

  • C # toujours utilise * (implicitement) car vous pouvez uniquement utiliser le nom du package. Vous ne pouvez jamais spécifier le nom de la classe. Java introduit la fonctionnalité après c #. (Java est tellement compliqué à de nombreux égards, mais cela dépasse ce sujet).

  • Dans Intellij Idea, lorsque vous "organisez les importations", il remplace automatiquement plusieurs importations du même package par *. Ceci est une fonctionnalité obligatoire car vous ne pouvez pas la désactiver (bien que vous puissiez augmenter le seuil).

  • Le cas répertorié dans la réponse acceptée n'est pas valide. Sans * vous avez toujours le même problème. Vous devez spécifier le nom de la pakcage dans votre code, que vous utilisiez * ou non.

Pour mémoire: Lorsque vous ajoutez une importation, vous indiquez également vos dépendances.

Vous pouvez voir rapidement quelles sont les dépendances des fichiers (à l’exclusion des classes du même espace de nom).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top