Warum ist die Verwendung einer Wildkarte mit einer Java -Import -Erklärung schlecht?

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

  •  02-07-2019
  •  | 
  •  

Frage

Es ist viel bequemer und sauberer, eine einzige Aussage wie wie

import java.awt.*;

als ein paar einzelne Klassen zu importieren

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

Was ist falsch daran, eine Wildcard in der zu verwenden? import Aussage?

War es hilfreich?

Lösung

Das einzige Problem dabei ist, dass es Ihren lokalen Namespace zusammenfasst. Nehmen wir zum Beispiel an, Sie schreiben eine Swing -App und brauchen so java.awt.Event, und verbinden sich auch mit dem Kalendersystem des Unternehmens, das hat com.mycompany.calendar.Event. Wenn Sie beide mit der Wildcard -Methode importieren, geschieht eines dieser drei Dinge:

  1. Sie haben einen direkten Namenskonflikt zwischen java.awt.Event und com.mycompany.calendar.Event, Und so können Sie nicht einmal kompilieren.
  2. Sie schaffen es tatsächlich nur, einen zu importieren (nur einer Ihrer beiden Importe tut dies .*), aber es ist falsch, und Sie haben Schwierigkeiten, herauszufinden, warum Ihr Code behauptet, der Typ sei falsch.
  3. Wenn Sie Ihren Code kompilieren, gibt es keine com.mycompany.calendar.Event, Aber wenn sie später einen hinzufügen, wird Ihr zuvor gültiger Code plötzlich nicht mehr kompiliert.

Der Vorteil der expliziten Auflistung aller Importe besteht darin, dass ich auf einen Blick erkennen kann, welche Klasse Sie verwenden möchten, was einfach das Lesen des Codes erheblich erleichtert. Wenn Sie nur ein kurzes einmaliges Ding machen, gibt es nichts explizites falsch, Aber zukünftige Betreuer werden Ihnen sonst für Ihre Klarheit danken.

Andere Tipps

Hier ist eine Abstimmung zum Sternimporte. Eine Einfuhranweisung soll a importieren Paket, keine Klasse. Es ist viel sauberer, ganze Pakete zu importieren. die hier identifizierten Probleme (z. B. zB java.sql.Date vs java.util.Date) Mit anderen Mitteln leicht zu beheben, nicht Ja wirklich angesprochen von bestimmten Importen und rechtfertigen wahnsinnig pedantische Importe in allen Klassen nicht. Es gibt nichts Beunruhigenderes, als eine Quelldatei zu öffnen und über 100 importierte Anweisungen durchzuführen.

Das Durchführen spezifischer Importe erschwert das Wiederverfassen; Wenn Sie eine Klasse entfernen/umbenennen, müssen Sie entfernen alle seiner spezifischen Importe. Wenn Sie eine Implementierung in eine andere Klasse im selben Paket wechseln, müssen Sie die Importe beheben. Obwohl diese zusätzlichen Schritte automatisiert werden können, handelt es sich um keinen wirklichen Gewinn.

Selbst wenn Eclipse nicht standardmäßig Klassenimporte erledigt hätte, würde jeder immer noch Starimporte machen. Es tut mir leid, aber es gibt wirklich keine rationale Rechtfertigung für bestimmte Importe.

Hier erfahren Sie, wie man mit Klassenkonflikten umgeht:

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

Bitte beachten Sie meinen Artikel Import auf Nachfrage ist böse

Kurz gesagt, das größte Problem ist, dass Ihr Code brechen kann, wenn eine Klasse ist hinzugefügt zu einem Paket, das Sie importieren. Zum Beispiel:

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

// ...

List list;

In Java 1.1 war das in Ordnung; Die Liste wurde in Java.awt gefunden und es gab keinen Konflikt.

Nehmen wir nun an, Sie überprüfen Ihren perfekt funktionierenden Code, und ein Jahr später bringt jemand anderes ihn heraus, um ihn zu bearbeiten, und verwendet Java 1.2.

Java 1.2 fügte java.util eine Schnittstelle mit dem Namen namens Liste hinzu. BOOM! Konflikt. Der perfekt funktionierende Code funktioniert nicht mehr.

Das ist ein TEUFLISCH Sprachfunktion. Es gibt NEIN Grund, dass der Code aufhören sollte zu kompilieren, nur weil ein Typ ist hinzugefügt zu einem Paket ...

Außerdem erschwert es einem Leser es schwierig zu bestimmen, welches "Foo" Sie verwenden.

Es ist nicht Schlecht, eine Wildkarte mit einer Java -Import -Erklärung zu verwenden.

Im Clean Code, Robert C. Martin empfiehlt tatsächlich, sie zu verwenden, um lange Importlisten zu vermeiden.

Hier ist die Empfehlung:

J1: Vermeiden Sie lange Importlisten durch die Verwendung von Wildcards

Wenn Sie zwei oder mehr Klassen aus einem Paket verwenden, importieren Sie das gesamte Paket mit

Paket importieren.*;

Lange Listen von Importen sind für den Leser entmutigend. Wir wollen die Spitzen unserer Module nicht mit 80 Zeilen von Importen überladen. Vielmehr möchten wir, dass die Importe eine kurze Aussage darüber sind, mit welchen Paketen wir zusammenarbeiten.

Spezifische Importe sind harte Abhängigkeiten, während keine Platzhalterimporte sind. Wenn Sie eine Klasse speziell importieren, muss diese Klasse existieren. Wenn Sie jedoch ein Paket mit einer Wildcard importieren, müssen keine bestimmten Klassen existieren. Die Import -Anweisung fügt das Paket einfach zum Suchpfad hinzu, wenn Sie nach Namensuche suchen. Es wird also keine echte Abhängigkeit durch solche Importe erzeugt, und sie dienen daher dazu, unsere Module weniger gekoppelt zu halten.

Es gibt Zeiten, in denen die lange Liste spezifischer Importe nützlich sein kann. Wenn Sie beispielsweise mit Legacy -Code zu tun haben und herausfinden möchten, welche Klassen Sie für Mocks und Stubs erstellen müssen, können Sie die Liste der spezifischen Importe entlang gehen, um die wahren qualifizierten Namen all dieser Klassen herauszufinden und dann zu setzen die entsprechenden Stubs an Ort und Stelle. Diese Verwendung für bestimmte Importe ist jedoch sehr selten. Darüber hinaus können Sie die meisten modernen IDEs mit einem einzigen Befehl in eine Liste spezifischer Importe in eine Liste konvertieren. Selbst im Legacy -Fall ist es besser, Wildcards zu importieren.

Wildcard -Importe können manchmal zu Namenskonflikten und -deutigkeiten führen. Zwei Klassen mit demselben Namen, aber in verschiedenen Paketen müssen spezifisch importiert oder zumindest spezifisch qualifiziert werden, wenn sie verwendet werden. Dies kann ein Ärgernis sein, ist aber selten genug, dass die Verwendung von Wildcard -Importen im Allgemeinen immer noch besser ist als bestimmte Importe.

Es kämpft Ihren Namespace und erfordert, dass Sie alle mehrdeutigen Klassennamen angeben. Das häufigste Auftreten davon ist mit:

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

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

Es hilft auch dabei, Ihre Abhängigkeiten konkret zu machen, da alle Ihre Abhängigkeiten oben in der Datei aufgeführt sind.

Leistung: Keine Auswirkungen auf die Leistung als Byte -Code ist gleich. Es wird zwar zu einigen Kompilierung von Gemeinkosten führen.

Zusammenstellung: Auf meiner persönlichen Maschine dauert das Kompilieren einer leeren Klasse ohne Import von 100 ms, aber die gleiche Klasse, wenn Java importiert wird.* Den 170 ms dauert.

  1. Es hilft, Klassenname -Konflikte zu identifizieren: zwei Klassen in verschiedenen Paketen mit demselben Namen. Dies kann mit dem * Import maskiert werden.
  2. Es macht Abhängigkeiten explizit, so dass jeder, der Ihren Code später lesen muss, weiß, was Sie importieren und was Sie nicht importieren wollten.
  3. Es kann eine Kompilierung schneller machen, da der Compiler das gesamte Paket nicht durchsuchen muss, um Depdenzen zu identifizieren. Dies ist jedoch normalerweise kein großer Deal für moderne Compiler.
  4. Die unbequemen Aspekte explizite Importe werden mit modernen IDES minimiert. Mit den meisten IDEs können Sie den Importabschnitt zusammenbrechen, damit er nicht im Weg ist, die Importe bei Bedarf automatisch füllen und ungenutzte Importe automatisch identifizieren, um sie zu bereinigen.

Die meisten Orte, an denen ich bearbeitet habe, die eine erhebliche Menge an Java verwenden, machen explizite Importe Teil des Codierungsstandards. Ich benutze manchmal noch * für schnelles Prototyping und erweitere dann die Importlisten (einige IDEs werden dies auch für Sie tun), wenn ich den Code produziere.

Ich bevorzuge bestimmte Importe, da ich alle externen Referenzen in der Datei sehen kann, ohne die gesamte Datei zu betrachten. (Ja, ich weiß, dass es nicht unbedingt vollständig qualifizierte Referenzen zeigt. Aber ich vermeide sie, wann immer möglich.)

In einem früheren Projekt stellte ich fest, dass das Wechsel von *-imports zu bestimmten Importen die Kompilierungszeit um die Hälfte verkürzte (von ca. 10 Minuten auf etwa 5 Minuten). Mit dem *-import sucht die Compiler-Suche nach jedem der für eine Klasse aufgeführten Pakete, die dem von Ihnen verwendeten übereinstimmt. Diese Zeit kann jedoch klein sein, aber es summiert sich für große Projekte.

Ein Seiteneinfluss des *-import war, dass Entwickler gemeinsame Importlinien kopieren und einfügen würden, anstatt darüber nachzudenken, was sie brauchten.

Im DDD -Buch

In welcher Entwicklungstechnologie, auf der die Implementierung basiert, suchen Sie nach Möglichkeiten zur Minimierung der Arbeit des Refactoring -Module. In Java gibt es keine Flucht vor dem Importieren in einzelne Klassen, aber Sie können zumindest zumindest ganze Pakete importieren, was die Absicht widerspiegelt, dass Pakete sehr kohärente Einheiten sind und gleichzeitig die Anstrengung, Paketnamen zu ändern, verringern.

Und wenn es sich um den lokalen Namespace handelt, ist es nicht Ihre Schuld - Schuld an der Größe des Pakets.

Das Wichtigste ist das Importieren java.awt.* Kann Ihr Programm mit einer zukünftigen Java -Version unvereinbar machen:

Angenommen, Sie haben eine Klasse namens "ABC", verwenden Sie JDK 8 und importieren java.util.*. Nehmen wir nun an, dass Java 9 herauskommt und eine neue Klasse im Paket hat java.util Das durch Zufall wird auch "ABC" genannt. Ihr Programm wird jetzt nicht auf Java 9 kompiliert, da der Compiler nicht weiß, ob Sie mit dem Namen "ABC" Ihre eigene Klasse oder die neue Klasse in meinen java.awt.

Sie werden dieses Problem nicht haben, wenn Sie nur diese Klassen ausdrücklich aus importieren java.awt das benutzt du tatsächlich.

Ressourcen:

Java -Importe

Unter allen gültigen Punkten, die auf beiden Seiten gemacht wurden, habe ich meinen Hauptgrund nicht gefunden, die Wildcard zu vermeiden: Ich mag es, den Code lesen zu können und direkt zu wissen, was jede Klasse ist oder ob es sich um eine Definition handelt, nicht in der Sprache oder nicht die Datei, wo sie sie finden. Wenn mehr als ein Paket mit * importiert wird, muss ich jeden von ihnen suchen, um eine Klasse zu finden, die ich nicht erkenne. Die Lesbarkeit ist überragend, und ich stimme zu, dass Code nicht sollte benötigen Eine ide zum Lesen.

  • Es gibt keine Laufzeit -Auswirkungen, da Compiler die * Namen von Konkreten automatisch ersetzt. Wenn Sie die .class -Datei dekompilieren, würden Sie nie sehen import ...*.

  • C# stets verwendet * (implizit) wie Sie nur können using Paketnamen. Sie können den Klassennamen überhaupt nie angeben. Java stellt die Funktion nach C#vor. (Java ist in vielen Aspekten so schwierig, aber es ist jenseits dieses Themas).

  • In der Intellij -Idee, wenn Sie "Importe organisieren", ersetzt es automatisch mehrere Importe desselben Pakets durch *. Dies ist eine Mandantenfunktion, da Sie sie nicht ausschalten können (obwohl Sie den Schwellenwert erhöhen können).

  • Der von der akzeptierte Antwort aufgeführte Fall ist nicht gültig. Ohne * hast du immer noch das gleiche Problem. Sie müssen den Pakcage -Namen in Ihrem Code angeben, unabhängig davon, ob Sie * oder nicht.

Für den Datensatz: Wenn Sie einen Import hinzufügen, geben Sie auch Ihre Abhängigkeiten an.

Sie konnten schnell sehen, welche Abhängigkeiten von Dateien sind (ohne Klassen gleicher Namespace).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top