Opzioni -Xlint di javac

Il compilatore del linguaggio di programmazione Java (javac) fornito da Oracle (e in precedenza da Sun) ha diverse opzioni non standard che sono spesso utili. Uno dei più utili è l'insieme di opzioni non standard che stampano gli avvisi incontrati durante la compilazione. Quella serie di opzioni è l'argomento di questo post.

La sezione della pagina javac sugli elenchi di opzioni non standard e fornisce brevi dettagli su ciascuna di queste opzioni. Quello che segue è lo snippet pertinente da quella pagina.

Un elenco di queste opzioni è disponibile anche dalla riga di comando (supponendo che Java SDK sia installato) con il comando: javac -help -X. Questo è più breve dell'esempio di pagina man / pagina web mostrato sopra e viene mostrato di seguito.

Come l'istantanea precedente esecuzione javac -help -Xindica le condizioni specifiche dieci per i quali esistono avvertimenti Xlint sono (in ordine alfabetico): cast, deprecation, divzero, empty, fallthrough, finally, overrides, path, serial, e unchecked. Esamino brevemente ciascuno di questi e fornisco uno snippet di codice che porta a questi avvisi che si verificano quando Xlint è attivato. Si noti che la pagina man per javac e la pagina javac Java SE 6 elencano entrambe solo metà di queste opzioni Xlint (la documentazione non è apparentemente aggiornata come l'utilizzo / aiuto di javac). C'è un'utile voce Wiki di NetBeans che riassume tutte e dieci le opzioni.

Il compilatore javac consente di abilitare tutti o nessuno degli avvisi Xlint. Se Xlint non è affatto specificato l'opzione -Xlint: nessuno è esplicitamente specificato, il comportamento è di non mostrare la maggior parte degli avvisi. È interessante notare che l'output fornisce un avviso sulla deprecazione e sugli avvisi non selezionati e consiglia di eseguire javac con -Xlint abilitato per vedere i dettagli su questi due tipi di avvisi.

Prima della fine di questo post, mostrerò il codice Java che porta a 13 avvisi Xlint segnalati in totale che coprono tutte e dieci le opzioni discusse sopra. Tuttavia, senza Xlint specificato, l'output è come mostrato nell'istantanea della schermata successiva.

Come indica l'immagine sopra, se Xlint non è specificato affatto o è specificato esplicitamente con "nessuno", il risultato è lo stesso: la maggior parte degli avvisi non viene mostrata, ma ci sono semplici riferimenti alla deprecazione e avvisi deselezionati con consigli per eseguire javac con -Xlint: deprecation e -Xlint: deselezionati rispettivamente per ulteriori dettagli. L'esecuzione di javac con -Xlint: all o -Xlint senza altre opzioni mostrerà tutti gli avvisi e funzionerà per vedere i dettagli riguardanti gli avvisi deprecati, non selezionati e tutti gli altri avvisi abilitati per Xlint applicabili. Questo verrà mostrato dopo aver esaminato il codice sorgente e ogni avviso Xlint individualmente.

-Xlint: cast

Questa opzione può essere utilizzata per fare in modo che il compilatore avverta lo sviluppatore che è in corso un cast ridondante. Ecco uno snippet di codice che verrebbe segnalato se -Xlint, -Xlint: all o -Xlint: cast fosse fornito a javac durante la compilazione del sorgente.

/** * Demonstrates -Xlint:cast warning of a redundant cast. */ private static void demonstrateCastWarning() { final Set people = new HashSet(); people.add(fred); people.add(wilma); people.add(barney); for (final Person person : people) { // Redundant cast because generic type explicitly is Person out.println("Person: " + ((Person) person).getFullName()); } } 

Nel codice precedente, non è necessario eseguire il cast dell'oggetto person all'interno del ciclo for su Person e -Xlint: cast avviserà di questo cast non necessario e ridondante con un messaggio che indica qualcosa come:

src\dustin\examples\Main.java:37: warning: [cast] redundant cast to dustin.examples.Person out.println("Person: " + ((Person) person).getFullName()); ^ 

-Xlint: deprecazione

Come discusso in precedenza, l'avviso di deprecazione di Xlint è stato evidentemente ritenuto abbastanza importante da giustificare la sua pubblicità anche quando Xlint non è esplicitamente eseguito. Questo avviso si verifica quando viene richiamato un metodo deprecato. Nell'esempio di codice seguente viene illustrato un caso del genere.

/** * Cause -Xlint:deprecation to print warning about use of deprecated method. */ private static void demonstrateDeprecationWarning() { out.println("Fred's full name is " + fred.getName()); } 

Non puoi dirlo senza il codice sorgente per la classe Person (di cui "fred" è un'istanza), ma quel metodo getName () è deprecato in Person. Il seguente output dall'esecuzione di javac con -Xlint, -Xlint: all o -Xlint: deprecation lo conferma (o lo indica se lo sviluppatore lo ha mancato).

src\dustin\examples\Main.java:47: warning: [deprecation] getName() in dustin.examples.Person has been deprecated out.println("Fred's full name is " + fred.getName()); ^ 

-Xlint: divzero

L'opzione divzero Xlint indica quando la divisione integrale divide per uno zero letterale. Di seguito viene mostrato un esempio di codice che lo dimostrerà:

/** * Demonstrate -Xlint:divzero in action by dividing an int by a literal zero. */ private static void demonstrateDivideByZeroWarning() { out.println("Two divided by zero is " + divideIntegerByZeroForLongQuotient(2)); } /** * Divide the provided divisor into the provided dividend and return the * resulting quotient. No checks are made to ensure that divisor is not zero. * * @param dividend Integer to be divided. * @return Quotient of division of dividend by literal zero. */ private static long divideIntegerByZeroForLongQuotient(final int dividend) { // Hard-coded divisor of zero will lead to warning. Had the divisor been // passed in as a parameter with a zero value, this would not lead to // that warning. return dividend / 0; } 

Viene ora mostrato l'output di javac quando quanto sopra è stato compilato.

src\dustin\examples\Main.java:231: warning: [divzero] division by zero return dividend / 0; ^ 

Quando ho tentato intenzionalmente di forzare questo avviso, sembrava funzionare solo per un divisore zero (letterale) hardcoded. Inoltre, non contrassegna la doppia divisione perché Infinity può essere restituito come risposta valida in quel caso senza generare un'eccezione.

-Xlint: vuoto

Lo scopo di -Xlint:emptyè notificare allo sviluppatore che un ifcondizionale "vuoto" è nel codice. Dai miei test, questo sembra valere solo per il caso del blocco "if" vuoto. NetBeans fornisce "suggerimenti" (quegli avvertimenti sottolineati in giallo che sono anche contrassegnati nel margine destro dell'editor del codice sorgente) per diversi tipi di istruzioni vuote, ma -Xlint:emptysembra che contrassegni solo le istruzioni "if" vuote. Ho incluso gli altri segnalati da NetBeans insieme a uno -Xlint:emptynel prossimo esempio di codice sorgente.

/** * This method demonstrates how javac's -Xlint:empty works. Note that javac's * -Xlint:empty will only flag the empty statement involved in the "if" block, * but does not flag the empty statements associated with the do-while loop, * the while loop, the for loop, or the if-else. NetBeans does flag these if * the appropriate "Hints" are turned on. */ private static void demonstrateEmptyWarning() { int[] integers = {1, 2, 3, 4, 5}; if (integers.length != 5); out.println("Not five?"); if (integers.length == 5) out.println("Five!"); else; out.println("Not Five!"); do; while (integers.length > 0); for (int integer : integers); out.println("Another integer found!"); int counter = 0; while (counter < 5); out.println("Extra semicolons.");;;; } 

Il codice sopra è pieno di un posizionamento problematico di punti e virgola che quasi certamente non sono ciò che lo sviluppatore voleva. Questo codice verrà compilato, ma lo sviluppatore è avvertito di queste situazioni sospette se -Xlint, -Xlint:allo -Xlint:emptyviene utilizzato con javac. Di seguito vengono visualizzati i messaggi di avviso stampati nella compilazione altrimenti riuscita.

src\dustin\examples\Main.java:197: warning: [empty] empty statement after if if (integers.length != 5); ^ 

Viene contrassegnata solo la clausola dell'istruzione "if" vuota; gli altri non sono segnalati da -Xlint:empty.

-Xlint: fallthrough

Una comodità allettante ma controversa che Java fornisce è la capacità di "fallire" espressioni comuni in switchun'istruzione per applicare la stessa logica a più valori integrali con un pezzo di codice. Se tutti i valori integrali con la funzionalità condivisa sono vuoti tranne quello finale che esegue effettivamente la funzionalità e fornisce un break, il -Xlint:fallthroughnon verrà attivato. Tuttavia, se alcune caseespressioni eseguono la propria logica oltre alla logica fallthrough comune, viene prodotto questo avviso. Di seguito viene mostrato un esempio che lo dimostra.

/** * Cause -Xlint:fallthrough to print warning about use of switch/case * fallthrough. */ private static void demonstrateFallthroughWarning() { out.print("Wilma's favorite color is "); out.print(wilma.getFavoriteColor() + ", which is "); // check to see if 'artistic' primary color // NOTE: This one will not lead to -Xlint:fallthrough flagging a warning // because no functionality is included in any of the case statements // that don't have their own break. switch (wilma.getFavoriteColor()) { case BLUE: case YELLOW: case RED: out.print("a primary color for artistic endeavors"); break; case BLACK: case BROWN: case CORAL: case EGGSHELL: case GREEN: case MAUVE: case ORANGE: case PINK: case PURPLE: case TAN: case WHITE: default: out.print("NOT a primary artistic color"); } out.print(" and is "); // check to see if 'additive' primary color // NOTE: This switch WILL lead to -Xlint:fallthrough emitting a warning // because there is some functionality being performed in a case // expression that does not have its own break statement. switch (wilma.getFavoriteColor()) { case BLUE: case GREEN: out.println("(it's not easy being green!) "); case RED: out.println("a primary color for additive endeavors."); break; case BLACK: case BROWN: case CORAL: case EGGSHELL: case MAUVE: case ORANGE: case PINK: case PURPLE: case TAN: case YELLOW: case WHITE: default: out.println("NOT a primary additive color."); } } 

L'esempio di codice sopra mostra intenzionalmente entrambi i casi (gioco di parole) dell'interruttore / caso che porterà e non porterà a un messaggio di avviso grazie a -Xlint:fallthrough. L'output, con un solo avviso, viene visualizzato di seguito.

src\dustin\examples\Main.java:95: warning: [fallthrough] possible fall-through into case case RED: ^ 

Quello caseche è stato contrassegnato è stato il ROSSO che casesegue il VERDE caseche ha fatto una logica propria prima di cadere nella logica ROSSA.

-Xlint: finalmente

Più di una persona ha avvertito: "Non tornare in una clausola finalmente". In effetti, "il ritorno di Java non sempre" si trova in The Java Hall of Shame. Uno sviluppatore Java può essere avvisato riguardo a questa situazione nefasta utilizzando -Xlint, -Xlint:allo -Xlint:finally. Di seguito viene mostrato un pezzo di codice sorgente che dimostra come potrebbe essere generato questo avviso.

/** * Demonstrate -Xlint:finally generating warning message when a {@code finally} * block cannot end normally. */ private static void demonstrateFinallyWarning() { try { final double quotient = divideIntegersForDoubleQuotient(10, 0); out.println("The quotient is " + quotient); } catch (RuntimeException uncheckedException) { out.println("Caught the exception: " + uncheckedException.toString()); } } /** * Divide the provided divisor into the provided dividend and return the * resulting quotient. No checks are made to ensure that divisor is not zero. * * @param dividend Integer to be divided. * @param divisor Integer by which dividend will be divided. * @return Quotient of division of dividend by divisor. */ private static double divideIntegersForDoubleQuotient(final int dividend, final int divisor) { double quotient = 0.0; try { if (divisor == 0) { throw new ArithmeticException( "Division by zero not allowed: cannot perform " + dividend + "/" + divisor); } // This would not have led to Xlint:divzero warning if we got here // with a literal zero divisor because Infinity would have simply been // returned rather than implicit throwing of ArithmeticException. quotient = (double) dividend / divisor; } finally { return quotient; } } 

Quanto sopra è difettoso e probabilmente non è ciò che lo sviluppatore intendeva. Successivamente viene mostrato l'avviso relativo che javac fornisce quando Xlint è abilitato.

src\dustin\examples\Main.java:159: warning: [finally] finally clause cannot complete normally } ^ 

-Xlint: sostituisce