¿Por qué está mal usar un comodín con una sentencia de importación de Java?

Es mucho más conveniente y más limpio usar una statement única como

import java.awt.*; 

que importar un montón de clases individuales

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

¿Qué hay de malo con el uso de un comodín en la statement de import ?

El único problema con esto es que desordena su espacio de nombres local. Por ejemplo, supongamos que está escribiendo una aplicación Swing, por lo que necesita java.awt.Event , y también está interactuando con el sistema de calendario de la compañía, que tiene com.mycompany.calendar.Event . Si importa ambos usando el método comodín, ocurre una de estas tres cosas:

  1. Tienes un conflicto de nombres absoluto entre java.awt.Event y com.mycompany.calendar.Event , por lo que ni siquiera puedes comstackr.
  2. En realidad, solo logras importar uno (solo una de tus dos importaciones sí lo hace .* ), pero es la incorrecta, y te cuesta averiguar por qué tu código dice que el tipo es incorrecto.
  3. Cuando comstack su código, no hay com.mycompany.calendar.Event , pero cuando más tarde agregan uno, su código previamente válido deja de comstackr repentinamente.

La ventaja de enumerar explícitamente todas las importaciones es que puedo decir de un vistazo qué clase pretendía usar, lo que simplemente hace que leer el código sea mucho más fácil. Si solo está haciendo una única acción rápida, no hay nada explícitamente incorrecto , pero los mantenedores futuros le agradecerán por su claridad de lo contrario.

Aquí hay un voto para las importaciones estrella. Una statement de importación está destinada a importar un paquete , no una clase. Es mucho más limpio importar paquetes completos; los problemas identificados aquí (por ejemplo, java.sql.Date vs java.util.Date ) se pueden remediar fácilmente por otros medios, que en realidad no se abordan mediante importaciones específicas y ciertamente no justifican las importaciones peligrosamente pedantes en todas las clases. No hay nada más desconcertante que abrir un archivo fuente y tener que pasar por 100 declaraciones de importación.

Hacer importaciones específicas hace que la refacturación sea más difícil; si elimina / cambia el nombre de una clase, debe eliminar todas sus importaciones específicas. Si cambia una implementación a una clase diferente en el mismo paquete, debe corregir las importaciones. Si bien estos pasos adicionales se pueden automatizar, en realidad son éxitos de productividad sin ganancia real.

Si Eclipse no hiciera importaciones de clase por defecto, todos seguirían haciendo importaciones de estrellas. Lo siento, pero realmente no hay una justificación racional para hacer importaciones específicas.

A continuación, te explicamos cómo lidiar con los conflictos de clase:

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

por favor mira mi artículo Import on Demand is Evil

En resumen, el mayor problema es que su código se puede romper cuando se agrega una clase a un paquete que importa. Por ejemplo:

 import java.awt.*; import java.util.*; // ... List list; 

En Java 1.1, esto estuvo bien; La lista se encontró en java.awt y no hubo conflicto.

Ahora supongamos que comprueba el código que funciona perfectamente, y un año después alguien más lo saca para editarlo, y está usando Java 1.2.

Java 1.2 agregó una interfaz llamada List to java.util. ¡AUGE! Conflicto. El código que funciona perfectamente ya no funciona.

Esta es una característica de lenguaje MALVADA . No hay ninguna razón por la cual el código deba detener la comstackción solo porque se agrega un tipo a un paquete …

Además, hace que sea difícil para un lector determinar qué “Foo” está utilizando.

No está mal usar un comodín con una statement de importación de Java.

En Clean Code , Robert C. Martin realmente recomienda usarlos para evitar largas listas de importación.

Aquí está la recomendación:

J1: evitar largas listas de importación mediante el uso de comodines

Si usa dos o más clases de un paquete, entonces importe todo el paquete con

importar paquete. *;

Las largas listas de importaciones son desalentadoras para el lector. No queremos llenar las partes superiores de nuestros módulos con 80 líneas de importaciones. Más bien queremos que las importaciones sean una statement concisa sobre con qué paquetes colaboramos.

Las importaciones específicas son dependencias duras, mientras que las importaciones de comodines no lo son. Si importa una clase específicamente, entonces esa clase debe existir. Pero si importa un paquete con un comodín, no es necesario que existan clases particulares. La statement de importación simplemente agrega el paquete a la ruta de búsqueda cuando busca nombres. De modo que no se crea una verdadera dependencia mediante tales importaciones, y por lo tanto sirven para mantener nuestros módulos menos acoplados.

Hay momentos en que la larga lista de importaciones específicas puede ser útil. Por ejemplo, si está tratando con un código heredado y desea saber para qué clases necesita crear mocks y stubs, puede ir por la lista de importaciones específicas para descubrir los verdaderos nombres calificados de todas esas clases y luego ponerle los talones apropiados en su lugar. Sin embargo, este uso para importaciones específicas es muy raro. Además, la mayoría de los IDE modernos le permitirán convertir las importaciones de comodines a una lista de importaciones específicas con un solo comando. Entonces, incluso en el caso del legado, es mejor importar comodines.

Las importaciones de comodines a veces pueden causar conflictos de nombres y ambigüedades. Dos clases con el mismo nombre, pero en diferentes paquetes, deberán ser importadas específicamente, o al menos específicamente calificadas cuando se usen. Esto puede ser una molestia, pero es bastante raro que el uso de importaciones de comodines sea, en general, mejor que las importaciones específicas.

Atormenta su espacio de nombres, lo que requiere que especifique completamente cualquier nombre de clase que sea ambiguo. La ocurrencia más común de esto es con:

 import java.util.*; import java.awt.*; ... List blah; // Ambiguous, needs to be qualified. 

También ayuda a que sus dependencias sean concretas, ya que todas sus dependencias se enumeran en la parte superior del archivo.

Rendimiento : no afecta el rendimiento ya que el código de bytes es el mismo. aunque dará lugar a algunos gastos generales de comstackción.

Comstackción : en mi máquina personal, comstackr una clase en blanco sin importar nada lleva 100 ms pero la misma clase cuando import java. * Demora 170 ms.

  1. Ayuda a identificar conflictos de nombre de clase: dos clases en diferentes paquetes que tienen el mismo nombre. Esto se puede enmascarar con la * importación.
  2. Hace que las dependencias sean explícitas, de modo que cualquier persona que tenga que leer su código más tarde sepa qué significó importar y qué no quiso importar.
  3. Puede hacer una comstackción más rápida porque el comstackdor no tiene que buscar todo el paquete para identificar las dependencias, aunque esto no suele ser un gran problema con los comstackdores modernos.
  4. Los aspectos inconvenientes de las importaciones explícitas se minimizan con IDEs modernos. La mayoría de los IDE le permiten colapsar la sección de importación para que no estorbe, agregue automáticamente las importaciones cuando sea necesario e identifique automáticamente las importaciones no utilizadas para ayudar a limpiarlas.

La mayoría de los lugares en los que he trabajado que usan una cantidad significativa de Java hacen que las importaciones explícitas sean parte del estándar de encoding. A veces sigo usando * para la creación rápida de prototipos y luego amplío las listas de importación (algunos IDE también lo harán por usted) al generar el código.

Prefiero las importaciones específicas, porque me permite ver todas las referencias externas utilizadas en el archivo sin mirar el archivo completo. (Sí, sé que no necesariamente mostrará referencias totalmente calificadas. Pero las evito siempre que sea posible).

En un proyecto anterior descubrí que el cambio de * importaciones a importaciones específicas reducía el tiempo de comstackción a la mitad (de aproximadamente 10 minutos a aproximadamente 5 minutos). El * -import hace que el comstackdor busque cada uno de los paquetes enumerados para una clase que coincida con la que usaste. Si bien este tiempo puede ser pequeño, se sum para proyectos grandes.

Un efecto secundario del * -import fue que los desarrolladores copiarían y pegarían líneas de importación comunes en lugar de pensar en lo que necesitaban.

En el libro DDD

En cualquier tecnología de desarrollo en la que se base la implementación, busque formas de minimizar el trabajo de los MÓDULOS de refactorización. En Java, no hay escapatoria de la importación en clases individuales, pero al menos se pueden importar paquetes completos a la vez, lo que refleja la intención de que los paquetes sean unidades altamente cohesivas y al mismo tiempo se reduzca el esfuerzo de cambiar los nombres de los paquetes.

Y si desordena el espacio de nombres local, no es su culpa, culpe al tamaño del paquete.

El más importante es que la importación de java.awt.* Puede hacer que su progtwig sea incompatible con una futura versión de Java:

Supongamos que tiene una clase llamada “ABC”, está utilizando JDK 8 e importa java.util.* . Ahora, supongamos que sale Java 9, y tiene una nueva clase en el paquete java.util que por casualidad también se llama “ABC”. Su progtwig ahora no se comstackrá en Java 9, porque el comstackdor no sabe si con el nombre “ABC” quiere decir su propia clase o la nueva clase en java.awt .

No tendrá ese problema cuando importe solo aquellas clases explícitamente de java.awt que realmente usa.

Recursos:

Importaciones de Java

Entre todos los puntos válidos hechos en ambos lados, no he encontrado la razón principal para evitar el comodín: me gusta poder leer el código y saber directamente qué es cada clase, o si su definición no está en el idioma o el archivo, dónde encontrarlo. Si se importa más de un paquete con * tengo que buscar en cada uno de ellos para encontrar una clase que no reconozco. La legibilidad es suprema, y ​​acepto que el código no debería requerir un IDE para leerlo.

  • No hay impacto en el tiempo de ejecución, ya que el comstackdor reemplaza automáticamente * con nombres de clase concretos. Si descomstacks el archivo .class, nunca verías import ...* .

  • C # siempre usa * (implícitamente) ya que solo puede using nombre del paquete. Nunca puedes especificar el nombre de clase en absoluto. Java introduce la función después de c #. (Java es tan complicado en muchos aspectos, pero va más allá de este tema).

  • En Intellij Idea, cuando “organiza importaciones”, reemplaza automáticamente múltiples importaciones del mismo paquete con *. Esta es una característica obligatoria porque no puede desactivarla (aunque puede boost el umbral).

  • El caso enumerado por la respuesta aceptada no es válido. Sin * todavía tienes el mismo problema. Debe especificar el nombre de pakcage en su código sin importar si usa * o no.

    Intereting Posts