Perché l'utilizzo di un carattere jolly con un'istruzione di importazione Java non è corretto?

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

  •  02-07-2019
  •  | 
  •  

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 ?

È stato utile?

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:

  1. Hai un vero conflitto di denominazione tra java.awt.Event e com.mycompany.calendar.Event e quindi non puoi nemmeno compilare.
  2. 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 .
  3. 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.

  1. 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.
  2. Rende esplicite le dipendenze, in modo che chiunque debba leggere il codice in seguito sappia cosa intendevi importare e cosa non intendevi importare.
  3. 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.
  4. 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:

Importazioni Java

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top