Opciones -Xlint de javac

El compilador del lenguaje de programación Java (javac) proporcionado por Oracle (y anteriormente por Sun) tiene varias opciones no estándar que a menudo son útiles. Uno de los más útiles es el conjunto de opciones no estándar que imprimen las advertencias encontradas durante la compilación. Ese conjunto de opciones es el tema de esta publicación.

La sección de la página javac sobre opciones no estándar enumera y proporciona breves detalles sobre cada una de estas opciones. El siguiente es el fragmento relevante de esa página.

También está disponible una lista de estas opciones desde la línea de comandos (suponiendo que el SDK de Java esté instalado) con el comando: javac -help -X. Esto es más breve que el ejemplo de página de manual / página web que se muestra arriba y se muestra a continuación.

A medida que la instantánea anterior se ejecute javac -help -Xindica, las condiciones específicas diez para los que existen advertencias Xlint son (en orden alfabético): cast, deprecation, divzero, empty, fallthrough, finally, overrides, path, serial, y unchecked. Miro brevemente cada uno de estos y proporciono un fragmento de código que lleva a que se produzcan estas advertencias cuando Xlint está encendido. Tenga en cuenta que la página de manual de javac y la página de Java SE 6 javac solo enumeran la mitad de estas opciones de Xlint (la documentación aparentemente no está tan actualizada como el uso / ayuda de javac). Hay una entrada útil de NetBeans Wiki que resume las diez opciones.

El compilador javac permite que se habiliten todas o ninguna de las advertencias de Xlint. Si Xlint no se especifica en absoluto en la opción -Xlint: none se especifica explícitamente, el comportamiento es no mostrar la mayoría de las advertencias. Curiosamente, la salida proporciona una advertencia sobre la desaprobación y las advertencias sin marcar y recomienda ejecutar javac con -Xlint habilitado para ver los detalles de estos dos tipos de advertencias.

Antes del final de esta publicación, demostraré el código Java que genera 13 advertencias de Xlint reportadas en total que cubren las diez opciones discutidas anteriormente. Sin embargo, sin Xlint especificado, la salida es como se muestra en la siguiente captura de pantalla.

Como indica la imagen de arriba, ya sea que Xlint no se especifique en absoluto o que se especifique explícitamente con "none", el resultado es el mismo: la mayoría de las advertencias no se muestran, pero hay referencias simples a la desaprobación y advertencias sin marcar con recomendaciones. para ejecutar javac con -Xlint: deprecation y -Xlint: sin marcar respectivamente para obtener detalles adicionales. La ejecución de javac con -Xlint: all o -Xlint sin otras opciones mostrará todas las advertencias y funcionaría para ver los detalles sobre las advertencias obsoletas, no marcadas y todas las demás advertencias habilitadas para Xlint aplicables. Esto se mostrará después de revisar el código fuente y cada advertencia de Xlint individualmente.

-Xlint: fundido

Esta opción se puede utilizar para que el compilador advierta al desarrollador que se está realizando una conversión redundante. Aquí hay un fragmento de código que se marcaría si se proporcionaran -Xlint, -Xlint: all o -Xlint: cast a javac al compilar la fuente.

/** * 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()); } } 

En el código anterior, no hay necesidad de convertir el objeto person dentro del bucle for a Person y -Xlint: cast advertirá de esta transmisión innecesaria y redundante con un mensaje que indique algo como:

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

-Xlint: desaprobación

Como se mencionó anteriormente, la advertencia de desaprobación de Xlint evidentemente se consideró lo suficientemente importante como para justificar su publicidad incluso cuando Xlint no se ejecuta explícitamente. Esta advertencia se produce cuando se invoca un método obsoleto. El siguiente ejemplo de código demuestra un caso así.

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

No se puede saber sin el código fuente de la clase Person (de la cual "fred" es una instancia), pero ese método getName () está obsoleto en Person. El siguiente resultado de la ejecución de javac con -Xlint, -Xlint: all o -Xlint: deprecation confirma eso (o lo señala si el desarrollador se lo pasó por alto).

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

La opción divzero Xlint indica cuando la división integral se divide por un cero literal. A continuación, se muestra un ejemplo de código que demostrará esto:

/** * 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; } 

Ahora se muestra la salida de javac cuando se compila lo anterior.

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

Cuando intenté forzar esta advertencia intencionalmente, parecía que solo funcionaba para un divisor cero codificado (literal). Además, no marca la división doble porque Infinity se puede devolver como una respuesta válida en ese caso sin lanzar una excepción.

-Xlint: vacío

El propósito de -Xlint:emptyes notificar al desarrollador que hay un ifcondicional "vacío" en el código. Según mis pruebas, esto parece aplicarse solo al caso del bloque "if" vacío. NetBeans proporciona "sugerencias" (esas advertencias subrayadas en amarillo que también están marcadas en el margen derecho del editor de código fuente) para varios tipos de declaraciones vacías, pero -Xlint:emptyparece que solo marca las declaraciones vacías "if". Incluí los otros marcados por NetBeans junto con uno -Xlint:emptyen la siguiente muestra de código fuente.

/** * 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.");;;; } 

El código anterior está lleno de ubicaciones problemáticas de puntos y comas que casi con certeza no son lo que quería el desarrollador. Este código se compilará, pero el desarrollador está advertido de estas situaciones sospechosas si -Xlint, -Xlint:allo -Xlint:emptyse utiliza con javac. A continuación, se muestran los mensajes de advertencia que se imprimen en la compilación que de otro modo sería exitosa.

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

Sólo se marca la cláusula de declaración "if" vacía; los demás no son reportados por -Xlint:empty.

-Xlint: fallthrough

Una conveniencia tentadora pero controvertida que ofrece Java es la capacidad de "pasar por alto" expresiones comunes en una switchdeclaración para aplicar la misma lógica a múltiples valores integrales con una sola pieza de código. Si todos los valores integrales con la funcionalidad compartida están vacíos, excepto el último que realmente realiza la funcionalidad y proporciona una break, -Xlint:fallthroughno se activará. Sin embargo, si algunas de las caseexpresiones realizan su propia lógica además de la lógica de caída común, se produce esta advertencia. A continuación se muestra un ejemplo que demuestra esto.

/** * 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."); } } 

El ejemplo de código anterior muestra intencionalmente ambos casos (juego de palabras) del interruptor / caso que conducirá y no a un mensaje de advertencia gracias a -Xlint:fallthrough. A continuación se muestra la salida, con una sola advertencia.

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

El caseque quedó marcado fue el ROJO casesiguiendo al VERDE caseque hizo algo de lógica propia antes de pasar a la lógica ROJA.

-Xlint: finalmente

Más de una persona ha advertido: "No regrese en una cláusula final". De hecho, "El retorno de Java no siempre" está en The Java Hall of Shame. Un desarrollador de Java puede ser advertido acerca de esta situación nefasta mediante el uso de -Xlint, -Xlint:allo -Xlint:finally. A continuación, se muestra un fragmento de código fuente que demuestra cómo se podría generar esta advertencia.

/** * 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; } } 

Lo anterior es defectuoso y probablemente no sea lo que pretendía el desarrollador. A continuación, se muestra la advertencia relevante que proporciona javac cuando Xlint está habilitado.

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

-Xlint: anula