¿Por qué es malo usar un comodín con una declaración de importación de Java?

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

  •  02-07-2019
  •  | 
  •  

Pregunta

Es mucho más conveniente y limpio usar una sola declaración 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 declaración import ?

¿Fue útil?

Solución

El único problema es que satura el espacio de nombres local. Por ejemplo, digamos que está escribiendo una aplicación Swing y, por lo tanto, necesita java.awt.Event y también está interactuando con el sistema de calendario de la empresa, que tiene com.mycompany.calendar .Evento . Si importa ambos utilizando el método comodín, ocurre una de estas tres cosas:

  1. Tiene un conflicto de nombres absoluto entre java.awt.Event y com.mycompany.calendar.Event , por lo que ni siquiera puede compilar.
  2. En realidad solo logras importar uno (solo una de tus dos importaciones hace . * ), pero es incorrecto, y te cuesta descubrir por qué tu código afirma que el tipo es incorrecto .
  3. Cuando compila su código no hay com.mycompany.calendar.Event , pero cuando luego agregan uno, su código previamente válido deja de compilarse.

La ventaja de enumerar explícitamente todas las importaciones es que puedo decir de un vistazo qué clase querías usar, lo que hace que la lectura del código sea mucho más fácil. Si solo estás haciendo una cosa rápida, no hay nada explícitamente mal , pero los futuros mantenedores te agradecerán tu claridad de lo contrario.

Otros consejos

Aquí hay un voto para importaciones estrella. Una declaración 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 solucionan fácilmente por otros medios, no realmente abordados por importaciones específicas y ciertamente no justifican importaciones increíblemente pedantes en todas las clases. No hay nada más desconcertante que abrir un archivo de origen y tener que pasar por 100 declaraciones de importación.

Hacer importaciones específicas dificulta la refactorización; Si elimina / cambia el nombre de una clase, debe eliminar todas de 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, son realmente éxitos de productividad sin ganancias reales.

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

Aquí se explica cómo lidiar con los conflictos de clase:

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

consulte mi artículo Import on Demand is Evil

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

import java.awt.*;
import java.util.*;

// ...

List list;

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

Ahora suponga que registra su código que funciona perfectamente, y un año después alguien más lo saca para editarlo y está utilizando Java 1.2.

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

Esta es una función de idioma EVIL . Hay NO razón por la cual el código debe dejar de compilarse solo porque un tipo se agrega a un paquete ...

Además, hace que sea difícil para un lector determinar qué "Foo" estás usando.

No es no malo usar un comodín con una declaración 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 listas de importación largas utilizando   Comodines

     

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

     

paquete de importación. *;

     

Las largas listas de importaciones son desalentadoras para   el lector. No queremos abarrotar   arriba de nuestros módulos con 80   líneas de importación. Más bien queremos el   las importaciones para ser una declaración concisa   sobre qué paquetes colaboramos   con.

     

Importaciones específicas son difíciles   dependencias, mientras que las importaciones de comodines   no son. Si importa específicamente un   clase, entonces esa clase debe existir. Pero   si importa un paquete con un   comodín, no se necesitan clases particulares   existir. La declaración de importación simplemente   agrega el paquete a la ruta de búsqueda   cuando buscas nombres. Entonces no es verdad   la dependencia es creada por tales importaciones,   y por lo tanto sirven para mantener nuestra   módulos menos acoplados.

     

Hay momentos en que la larga lista de   Las importaciones específicas pueden ser útiles. por   ejemplo, si está tratando con   código heredado y quieres averiguarlo   qué clases necesitas para construir simulacros   y talones para, puedes caminar por el   Lista de importaciones específicas para descubrir.   Los verdaderos nombres calificados de todos aquellos.   clases y luego poner el apropiado   trozos en su lugar. Sin embargo, este uso para   Las importaciones específicas son muy raras.   Además, la mayoría de las IDEs modernas   te permite convertir el comodín   importaciones a una lista de importaciones específicas   con un solo comando Así que incluso en el   caso antiguo es mejor importar   comodines.

     

Las importaciones de comodines a veces pueden causar   Nombrar conflictos y ambigüedades. Dos   clases con el mismo nombre, pero en   diferentes paquetes, deberán ser   específicamente importado, o al menos   específicamente calificado cuando se usa. Esta   Puede ser una molestia pero es bastante raro   que el uso de las importaciones comodín sigue siendo   generalmente mejor que específico   importaciones.

Abarrota 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 concretar sus dependencias, ya que todas sus dependencias se enumeran en la parte superior del archivo.

Rendimiento : no hay impacto en el rendimiento, ya que el código de bytes es el mismo. aunque conducirá a algunos gastos generales de compilación.

Compilación : en mi máquina personal, compilar una clase en blanco sin importar nada toma 100 ms, pero la misma clase cuando import java. * toma 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 * import.
  2. Hace explícitas las dependencias, de modo que cualquiera que tenga que leer su código más tarde sepa lo que quiso importar y lo que no quiso importar.
  3. Puede hacer que la compilación sea más rápida porque el compilador no tiene que buscar en todo el paquete para identificar las dependencias, aunque esto generalmente no es un gran problema con los compiladores modernos.
  4. Los aspectos inconvenientes de las importaciones explícitas se minimizan con los IDE modernos. La mayoría de los IDE le permiten colapsar la sección de importación para que no se interponga, llenar automáticamente las importaciones cuando sea necesario e identificar 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 formen parte del estándar de codificación. 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) cuando produzca el código.

Prefiero 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 las importaciones de * a importaciones específicas reducía el tiempo de compilación a la mitad (de unos 10 minutos a unos 5 minutos). El * -import hace que el compilador busque en cada uno de los paquetes listados para una clase que coincida con la que usaste. Si bien este tiempo puede ser pequeño, se suma a proyectos grandes.

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

En libro de DDD

  

En cualquier tecnología de desarrollo en la que se basará la implementación, busque formas de minimizar el   Trabajos de refactorización MODULOS. En Java, no hay escapatoria para importar a clases individuales, pero usted   al menos puede importar paquetes completos a la vez, lo que refleja la intención de que los paquetes sean unidades altamente cohesivas   al tiempo que reduce el esfuerzo de cambiar los nombres de los paquetes.

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

El más importante es que importar java.awt. * puede hacer que tu programa 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 Java 9 sale y tiene una nueva clase en el paquete java.util que, por coincidencia, también se llama "ABC". Su programa ahora no se compilará en Java 9, porque el compilador no sabe si con el nombre " ABC " te refieres a tu propia clase o la nueva clase en java.awt .

No tendrás ese problema cuando solo importes esas clases explícitamente desde java.awt que realmente usas.

Recursos:

Importaciones Java

Entre todos los puntos válidos hechos en ambos lados no he encontrado mi 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 *, debo buscar en cada uno de ellos para encontrar una clase que no reconozco. La legibilidad es suprema, y ??estoy de acuerdo en que el código no debe requerir un IDE para leerlo.

  • No hay impacto de tiempo de ejecución, ya que el compilador reemplaza automáticamente el * con nombres de clase concretos. Si descompila el archivo .class, nunca verá importar ... * .

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

  • En Intellij Idea, cuando "organiza las importaciones", reemplaza automáticamente las importaciones múltiples del mismo paquete con *. Esta es una función obligatoria, ya que no puede desactivarla (aunque puede aumentar el umbral).

  • El caso listado 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 que use * o no.

Para el registro: Cuando agrega una importación, también está indicando sus dependencias.

Podría ver rápidamente cuáles son las dependencias de los archivos (excluyendo las clases del mismo espacio de nombres).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top