web-dev-qa-db-fra.com

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

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

import Java.awt.*;

que d'importer un tas 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?

340
jnancheta

Le seul problème 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 a com.mycompany.calendar.Event. 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 noms entre Java.awt.Event et com.mycompany.calendar.Event et vous ne pouvez même pas compiler.
  2. En réalité, vous ne pouvez en importer qu'une (une seule de vos deux importations correspond à .*), mais c'est la mauvaise 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 quand ils en ajoutent un, votre code précédemment valide cesse soudainement de compiler.

L'avantage de lister 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 explicitement faux , mais les futurs responsables vous remercieront pour votre clarté sinon.

414
Benjamin Pollack

Voici un vote pour étoiles importations. 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 pas {vraiment} par des importations spécifiques et ne justifient certainement pas des importations incroyablement pédantes sur toutes les classes. Il n’y a rien de plus déconcertant que d’ouvrir un fichier source et de devoir parcourir 100 déclarations d’importation.

Faire des importations spécifiques rend le refactoring plus difficile; si vous supprimez/renommez une classe, vous devez supprimer tout de 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 gérer les conflits de classes:

import Java.sql.*;
import Java.util.*;
import Java.sql.Date;
162
davetron5000

veuillez consulter mon article L'importation à la demande, c'est le mal

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

import Java.awt.*;
import Java.util.*;

// ...

List list;

En Java 1.1, c'était très bien. La liste a été trouvée dans Java.awt et il n'y a pas eu de conflit.

Supposons maintenant que vous archiviez votre code qui fonctionne parfaitement et qu'un an plus tard, quelqu'un d'autre l'apporte pour 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 NO raison pour laquelle le code doit cesser de compiler simplement parce qu'un type est ajouté à un paquet ...

En outre, il est difficile pour un lecteur de déterminer quel "Foo" vous utilisez.

147
Scott Stanchfield

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

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

Voici la recommandation:

J1: Évitez les longues listes d'importation en utilisant Wildcards

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 pour le lecteur. Nous ne voulons pas encombrer les sommets de nos modules avec 80 lignes d'importations. Nous voulons plutôt le les importations doivent être une déclaration concise sur 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 fichier classe, alors cette classe doit exister. Mais si vous importez un package avec un wildcard, pas besoin de classes particulières exister. La déclaration d'importation simplement ajoute le package 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 y a des moments où la longue liste de des importations spécifiques peuvent être utiles. Pour exemple, si vous avez affaire à code hérité et que vous voulez savoir Quelles sont les classes dont vous avez besoin pour construire des simulacres et bouts pour, vous pouvez marcher 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 le seront vous permet de convertir le caractère générique importations à une liste d'importations spécifiques avec une seule commande. Donc même dans le cas, il est préférable d’importer joker.

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

64
hwiechers

Il encombre votre espace de noms et vous oblige à spécifier tous les noms de classe ambigus. L'occurrence la plus commune de ceci est avec:

import Java.util.*;
import Java.awt.*;

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

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

22
hazzen

Performance : Aucun impact sur les performances car le code octet est identique . Cependant, cela entraînera des frais généraux de compilation.

Compilation : sur ma machine personnelle, Compiler une classe vide sans rien importer prend 100 ms, mais la même classe lors de l'importation Java. * Prend 170 ms.

19
Vinish Nain
  1. Il est utile d’identifier les conflits de nom de classe: deux classes de même nom dans des packages différents. Ceci peut être masqué avec l'import *.
  2. Cela rend les dépendances explicites, de sorte que toute personne qui doit lire votre code plus tard 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 un gros problème 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, de renseigner automatiquement les importations en cas de besoin et d'identifier automatiquement les importations inutilisées pour les nettoyer.

La plupart des endroits où j'ai travaillé et qui utilisent une quantité importante 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.

14
Josh Segall

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 cela ne montrera pas nécessairement les références complètes. Mais je les évite autant que possible.)

10
Jeff C

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 (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. Bien que cette période puisse être réduite, elle s’additionne pour les grands projets.

Un effet secondaire 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.

9
Michael Hall

Dans Livre DDD

Quelle que soit la technologie de développement sur laquelle la mise en œuvre sera basée, cherchez des moyens de réduire au minimum la vulnérabilité travail de refactoring MODULES. En Java, il n’est pas impossible 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 très cohérentes tout en réduisant simultanément l'effort de changer les noms de paquets.

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

6
Ivan

Parmi tous les arguments valables 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 dans le langage le fichier, où le trouver. Si plus d'un paquet est importé avec *, je dois aller les chercher tous pour trouver une classe que je ne reconnais pas. La lisibilité est primordiale, et je conviens que le code ne devrait pas nécessiter un IDE pour le lire.

2
user109439

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 paquetage Java.util qui, par coïncidence, s’appelle également "ABC". Votre programme maintenant ne compilera pas sur Java 9, car le compilateur ne sait pas si, avec le nom "ABC", vous voulez dire votre propre classe ou la nouvelle classe dans Java.awt

Vous n'aurez pas ce problème si vous importez uniquement les classes explicitement à partir de Java.awt que vous utilisez réellement. 

Ressources:

Java Imports

2
Virtual
  • 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 import ...*

  • C # always utilise * (implicitement) car vous ne pouvez que using nom de 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 *. Il s'agit d'une fonctionnalité obligatoire car vous ne pouvez pas la désactiver (même si vous pouvez 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 pakcage dans votre code, que vous utilisiez * ou non.

2
Leon

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 noms). 

0
magallanes