Perché l'utilizzo di un carattere jolly con un'istruzione di importazione Java non è corretto?
Domanda
È molto più conveniente e più pulito usare una singola istruzione come
import java.awt.*;
che importare un gruppo di singole classi
import java.awt.Panel;
import java.awt.Graphics;
import java.awt.Canvas;
...
Cosa c'è di sbagliato nell'usare un carattere jolly nell'istruzione import
?
Soluzione
L'unico problema è che ingombra lo spazio dei nomi locale. Ad esempio, supponiamo che tu stia scrivendo un'app Swing e che quindi sia necessario java.awt.Event
e che si interfacciano anche con il sistema di calendario dell'azienda, che ha com.mycompany.calendar .Event
. Se si importano entrambi utilizzando il metodo jolly, si verifica una di queste tre cose:
- Hai un vero conflitto di denominazione tra
java.awt.Event
ecom.mycompany.calendar.Event
e quindi non puoi nemmeno compilare. - In realtà riesci solo a importarne una (solo una delle tue due importazioni fa
. *
), ma è quella sbagliata e fai fatica a capire perché il tuo codice afferma che il tipo è sbagliato . - Quando compili il tuo codice non c'è
com.mycompany.calendar.Event
, ma quando successivamente ne aggiungono uno il tuo codice precedentemente valido interrompe improvvisamente la compilazione.
Il vantaggio di elencare esplicitamente tutte le importazioni è che posso dire a colpo d'occhio quale classe intendevi usare, il che rende semplicemente molto più semplice la lettura del codice. Se stai semplicemente facendo una cosa una tantum, non c'è nulla di esplicitamente sbagliato , ma i futuri manutentori ti ringrazieranno per la tua chiarezza altrimenti.
Altri suggerimenti
Ecco un voto per importazioni di stelle. Una dichiarazione di importazione intende importare un pacchetto , non una classe. È molto più pulito importare interi pacchetti; i problemi identificati qui (ad es. java.sql.Date
vs java.util.Date
) sono facilmente risolti con altri mezzi, non realmente risolti da importazioni specifiche e certamente non giustificano importazioni follemente pedanti su tutte le classi. Non c'è nulla di più sconcertante che aprire un file sorgente e dover sfogliare 100 dichiarazioni di importazione.
Effettuare importazioni specifiche rende più difficile il refactoring; se rimuovi / rinomina una classe, devi rimuovere tutto dalle sue importazioni specifiche. Se si passa un'implementazione a un'altra classe nello stesso pacchetto, è necessario correggere le importazioni. Sebbene questi passaggi aggiuntivi possano essere automatizzati, sono in realtà un aumento della produttività senza alcun reale guadagno.
Anche se Eclipse non eseguisse le importazioni di classe per impostazione predefinita, tutti continuerebbero a eseguire importazioni a stella. Mi dispiace, ma non esiste davvero alcuna giustificazione razionale per effettuare importazioni specifiche.
Ecco come affrontare i conflitti di classe:
import java.sql.*;
import java.util.*;
import java.sql.Date;
consulta il mio articolo L'importazione su richiesta è un male
In breve, il problema più grande è che il tuo codice può rompersi quando una classe viene aggiunta a un pacchetto che importi. Ad esempio:
import java.awt.*;
import java.util.*;
// ...
List list;
In Java 1.1, questo andava bene; L'elenco è stato trovato in java.awt e non si sono verificati conflitti.
Ora supponi di aver controllato il tuo codice perfettamente funzionante, e un anno dopo qualcun altro lo fa uscire per modificarlo e sta usando Java 1.2.
Java 1.2 ha aggiunto un'interfaccia chiamata List a java.util. BOOM! Conflitto. Il codice perfettamente funzionante non funziona più.
Questa è una funzione linguistica MALE . C'è NO motivo per cui il codice dovrebbe smettere di essere compilato solo perché un tipo viene aggiunto a un pacchetto ...
Inoltre, rende difficile per un lettore determinare quale "Foo" stai usando.
È non male usare un carattere jolly con una dichiarazione di importazione Java.
In Clean Code , Robert C. Martin consiglia di usarli per evitare elenchi di importazione lunghi.
Ecco la raccomandazione:
J1: evitare elenchi di importazione lunghi utilizzando I caratteri jolly
Se si utilizzano due o più classi da a pacchetto, quindi importare l'intero pacchetto con
pacchetto di importazione. *;
I lunghi elenchi di importazioni sono scoraggianti il lettore. Non vogliamo ingombrare in cima ai nostri moduli con 80 linee di importazione. Piuttosto vogliamo il le importazioni devono essere una dichiarazione concisa su quali pacchetti collaboriamo con.
Le importazioni specifiche sono difficili dipendenze, mentre le importazioni con caratteri jolly non sono. Se si importa specificamente a classe, quindi quella classe deve esistere. Ma se si importa un pacchetto con a carattere jolly, non sono necessarie classi particolari esistere. La dichiarazione di importazione semplicemente aggiunge il pacchetto al percorso di ricerca quando si cerca un nome. Quindi non è vero la dipendenza è creata da tali importazioni, e quindi servono a mantenere il nostro moduli meno accoppiati.
Ci sono momenti in cui la lunga lista di importazioni specifiche possono essere utili. Per esempio, se hai a che fare codice legacy e vuoi scoprirlo di quali classi hai bisogno per creare beffe e tronconi per, puoi camminare lungo il elenco di importazioni specifiche da scoprire i veri nomi qualificati di tutti quelli classi e poi mettere le appropriate mozziconi sul posto. Tuttavia, questo uso per le importazioni specifiche sono molto rare. Inoltre, la maggior parte degli IDE moderni lo farà consentire di convertire i caratteri jolly importazioni in un elenco di importazioni specifiche con un solo comando. Quindi anche nel caso legacy è meglio importare jolly.
Le importazioni di caratteri jolly possono talvolta causare nominare conflitti e ambiguità. Due classi con lo stesso nome, ma in pacchetti diversi, dovranno essere specificamente importato, o almeno specificamente qualificato quando utilizzato. Questo può essere una seccatura ma è abbastanza raro che l'utilizzo delle importazioni con caratteri jolly è ancora generalmente meglio di specifici importazioni.
Raggruppa il tuo spazio dei nomi, richiedendo di specificare completamente tutti i nomi di classe che sono ambigui. L'evento più comune di questo è con:
import java.util.*;
import java.awt.*;
...
List blah; // Ambiguous, needs to be qualified.
Aiuta anche a rendere concrete le tue dipendenze, poiché tutte le dipendenze sono elencate nella parte superiore del file.
Prestazioni : nessun impatto sulle prestazioni poiché il codice byte è lo stesso. sebbene porterà ad alcune spese generali di compilazione.
Compilazione : sul mio computer personale, la compilazione di una classe vuota senza importare nulla richiede 100 ms ma la stessa classe quando importa java. * richiede 170 ms.
- Aiuta a identificare i conflitti di nomi di classe: due classi in pacchetti diversi che hanno lo stesso nome. Questo può essere mascherato con * import.
- Rende esplicite le dipendenze, in modo che chiunque debba leggere il codice in seguito sappia cosa intendevi importare e cosa non intendevi importare.
- Può rendere più veloce la compilazione perché il compilatore non deve cercare l'intero pacchetto per identificare le depdenze, anche se di solito non è un grosso problema con i compilatori moderni.
- Gli aspetti scomodi delle importazioni esplicite sono ridotti al minimo con IDE moderni. La maggior parte degli IDE ti consente di comprimere la sezione di importazione in modo che non sia di ostacolo, popolare automaticamente le importazioni quando necessario e identifica automaticamente le importazioni non utilizzate per aiutarle a ripulirle.
La maggior parte dei posti in cui ho lavorato che utilizzano una quantità significativa di Java rendono le importazioni esplicite parte dello standard di codifica. A volte uso ancora * per la prototipazione rapida e quindi espando gli elenchi di importazione (alcuni IDE lo faranno anche per te) durante la produzione del codice.
Preferisco importazioni specifiche, perché mi permette di vedere tutti i riferimenti esterni utilizzati nel file senza guardare l'intero file. (Sì, lo so che non mostrerà necessariamente riferimenti pienamente qualificati. Ma li evito quando possibile.)
In un precedente progetto ho scoperto che il passaggio da * -import a importazioni specifiche ha ridotto della metà il tempo di compilazione (da circa 10 minuti a circa 5 minuti). * -Import consente al compilatore di cercare ciascuno dei pacchetti elencati per una classe corrispondente a quella utilizzata. Anche se questa volta può essere piccolo, si aggiunge a grandi progetti.
Un effetto collaterale di * -import era che gli sviluppatori avrebbero copiato e incollato le linee di importazione comuni invece di pensare a ciò di cui avevano bisogno.
In libro DDD
In qualunque tecnologia di sviluppo si baserà l'implementazione, cerca modi per ridurre al minimo il lavoro di refactoring MODULES. In Java, non c'è scampo dall'importazione in singole classi, ma tu può almeno importare interi pacchetti alla volta, riflettendo l'intenzione che i pacchetti siano unità altamente coesive riducendo contemporaneamente lo sforzo di modificare i nomi dei pacchetti.
E se ingombra lo spazio dei nomi locale non è colpa tua - incolpare la dimensione del pacchetto.
Il più importante è che l'importazione di java.awt. *
può rendere il programma incompatibile con una futura versione di Java:
Supponi di avere una classe chiamata " ABC " ;, stai usando JDK 8 e importi java.util. *
. Supponiamo ora che Java 9 esca e che abbia una nuova classe nel pacchetto java.util
che per coincidenza si chiami anche "ABC". Il tuo programma ora non verrà compilato su Java 9, perché il compilatore non sa se con il nome "ABC" intendi la tua classe o la nuova classe in java.awt
.
Non avrai questo problema quando importi solo quelle classi esplicitamente da java.awt
che effettivamente usi.
Risorse:
Tra tutti i punti validi fatti da entrambe le parti non ho trovato il motivo principale per evitare il carattere jolly: mi piace essere in grado di leggere il codice e sapere direttamente qual è ogni classe o se la sua definizione non è in la lingua o il file, dove trovarlo. Se viene importato più di un pacchetto con *, devo cercare ciascuno di essi per trovare una classe che non riconosco. La leggibilità è suprema e sono d'accordo che il codice non dovrebbe richiedere un IDE per leggerlo.
-
Non vi è alcun impatto sul runtime, poiché il compilatore sostituisce automaticamente * con nomi di classe concreti. Se decompili il file .class, non vedresti mai
import ... *
. -
C # usa sempre * (implicitamente) poiché puoi solo
usare
il nome del pacchetto. Non puoi mai specificare il nome della classe. Java introduce la funzione dopo c #. (Java è così complicato sotto molti aspetti ma va oltre questo argomento). -
In Intellij Idea quando "organizzi le importazioni", sostituisce automaticamente più importazioni dello stesso pacchetto con *. Questa è una funzione obbligatoria in quanto non è possibile disattivarla (sebbene sia possibile aumentare la soglia).
-
Il caso elencato dalla risposta accettata non è valido. Senza * hai ancora lo stesso problema. Devi specificare il nome della pakcage nel tuo codice, indipendentemente dal fatto che tu * usi o meno.
Per la cronaca: Quando aggiungi un'importazione, indichi anche le tue dipendenze.
Potresti vedere rapidamente quali sono le dipendenze dei file (escluse le classi dello stesso spazio dei nomi).