¿Cuál es un buen caso de uso para la importación estática de métodos?


Acabo de recibir un comentario de revisión de que mi importación estática del método no era una buena idea. La importación estática era de un método de una clase DA, que tiene principalmente métodos estáticos. Así que en medio de la lógica de negocios tuve una actividad da que aparentemente parecía pertenecer a la clase actual:

import static some.package.DA.*;
class BusinessObject {
  void someMethod() {
    ....
    save(this);
  }
} 

El revisor no estaba interesado en que cambiara el código y no lo hice, pero estoy de acuerdo con él. Una razón dada para no static-importing fue que era confuso donde se definió el método, se no estaba en la clase actual y no en ninguna superclase por lo que también algún tiempo para identificar su definición (el sistema de revisión basado en la web no tiene enlaces clicables como IDE :-) Realmente no creo que esto importe, las importaciones estáticas siguen siendo bastante nuevas y pronto todos nos acostumbraremos a localizarlas.

Pero la otra razón, con la que estoy de acuerdo, es que una llamada a un método no cualificado parece pertenecer al objeto actual y no debería saltar contextos. Pero si realmente perteneciera, tendría sentido extiende esa súper clase.

Entonces, ¿cuándo tiene sentido importar métodos estáticos? ¿Cuándo lo has hecho? ¿Te gustó/te gustó la forma en que se ven las llamadas no calificadas?

EDITAR: La opinión popular parece ser que los métodos de importación estática si nadie va a confundirlos como métodos de la clase actual. Por ejemplo métodos de java.lang.Matemáticas y java.awt.Color. Pero si abs y getAlpha no son ambiguos no veo por qué readEmployee lo es. Como en muchas opciones de programación, creo esto también es una cosa de preferencia personal.

Gracias por su respuesta chicos, estoy cerrando la pregunta.

Author: Miserable Variable, 2009-01-07

15 answers

Esto es de la guía de Sun cuando lanzaron la característica (énfasis en el original):

Entonces, ¿cuándo debe usar la importación estática? Muy escasamente! Solo úselo cuando de otra manera estaría tentado a declarar copias locales de constantes, o a abusar de la herencia (el Antipatrón de la Interfaz de Constantes). ... Si utilizas en exceso la función de importación estática, puede hacer que tu programa sea ilegible e inalcanzable, contaminando su espacio de nombres con todos los miembros estáticos que importas. Lectores de su el código (incluido usted, unos meses después de escribirlo) no sabrá de qué clase proviene un miembro estático. Importar todos los miembros estáticos de una clase puede ser particularmente dañino para la legibilidad; si solo necesita uno o dos miembros, impórtelos individualmente.

(https://docs.oracle.com/javase/8/docs/technotes/guides/language/static-import.html)

Hay dos partes que quiero llamar específicamente:

  • Use importaciones estáticas solamente cuando fuiste tentado a "abusar de la herencia". En este caso, ¿habrías estado tentado de tener BusinessObject extend some.package.DA? Si es así, las importaciones estáticas pueden ser una forma más limpia de manejar esto. Si nunca hubiera soñado con extender some.package.DA, entonces este es probablemente un mal uso de las importaciones estáticas. No lo use solo para guardar unos pocos caracteres al escribir.
  • Importar miembros individuales. Diga import static some.package.DA.save en lugar de DA.*. Eso hará que sea mucho más fácil encontrar de dónde proviene este método importado.

Personalmente, he usado esta característica del lenguaje muy raramente, y casi siempre solo con constantes o enums, nunca con métodos. La compensación, para mí, casi nunca vale la pena.

 117
Author: Ross,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-22 15:33:17

Otro uso razonable para las importaciones estáticas es con JUnit 4. En versiones anteriores de JUnit métodos como assertEquals y fail fueron heredados desde la clase test extended junit.framework.TestCase.

// old way
import junit.framework.TestCase;

public class MyTestClass extends TestCase {
    public void myMethodTest() {
        assertEquals("foo", "bar");
    }
}

En JUnit 4, las clases de prueba ya no necesitan extender TestCase y en su lugar pueden usar anotaciones. Luego puede importar estáticamente los métodos assert desde org.junit.Assert:

// new way
import static org.junit.Assert.assertEquals;

public class MyTestClass {
    @Test public void myMethodTest() {
        assertEquals("foo", "bar");
        // instead of
        Assert.assertEquals("foo", "bar");
    }
}

JUnit documenta usándolo de esta manera.

 55
Author: Rob Hruska,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-07 18:32:14

Effective Java, Second Edition , al final de Item 19 señala que puede usar importaciones estáticas si se encuentra fuertemente usando constantes de una clase de utilidad. Creo que este principio se aplicaría a las importaciones estáticas de constantes y métodos.

import static com.example.UtilityClassWithFrequentlyUsedMethods.myMethod;

public class MyClass {
    public void doSomething() {
        int foo= UtilityClassWithFrequentlyUsedMethods.myMethod();
        // can be written less verbosely as
        int bar = myMethod();
    }
}

Esto tiene ventajas y desventajas. Hace que el código sea un poco más legible a expensas de perder información inmediata sobre dónde se define el método. Sin embargo, un buen IDE te dejará ir a la definición, así que esto no es un gran problema.

Todavía debe usar esto con moderación, y solo si se encuentra usando cosas del archivo importado muchas, muchas veces.

Editar: Actualizado para ser más específico a los métodos, ya que a eso se refiere esta pregunta. El principio se aplica independientemente de lo que se está importando (constantes o métodos).

 20
Author: Rob Hruska,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-13 08:46:58

Lo uso mucho para el color.

static import java.awt.Color.*;

Es muy poco probable que los colores se confundan con otra cosa.

 10
Author: jjnguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-07 17:19:06

Estoy de acuerdo en que pueden ser problemáticas desde una perspectiva de legibilidad y deben usarse con moderación. Pero cuando se utiliza un método estático común que en realidad puede aumentar la legibilidad. Por ejemplo, en una clase de prueba JUnit, métodos como assertEquals son obvios de dónde vienen. Del mismo modo para los métodos de java.lang.Math.

 10
Author: Joel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-26 14:37:22

Creo que la importación estática es realmente útil para eliminar nombres de clases redundantes cuando se usan clases utils como Arrays y Assertions.

No estoy seguro de por qué, pero Ross omitió la última frase que menciona esto en la documentación que está haciendo referencia a.

Usado apropiadamente, la importación estática puede hacer que su programa sea más legible, eliminando la repetición de nombres de clases.

Básicamente copiado de este blog: https://medium.com/alphadev-thoughts/static-imports-are-great-but-underused-e805ba9b279f

Por ejemplo:

Aserciones en pruebas

Este es el caso más obvio en el que creo que todos estamos de acuerdo

Assertions.assertThat(1).isEqualTo(2);

// Use static import instead
assertThat(1).isEqualTo(2);

Utils classes and enums

El nombre de la clase se puede eliminar en muchos casos cuando se utilizan clases utils haciendo que el código sea más fácil de leer

List<Integer> numbers = Arrays.asList(1, 2, 3);

// asList method name is enough information
List<Integer> numbers = asList(1, 2, 3);

Java.paquete de tiempo tiene algunos casos en los que debe ser usado

// Get next Friday from now, quite annoying to read
LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.FRIDAY));

// More concise and easier to read
LocalDate.now().with(next(FRIDAY));

Ejemplo de cuándo no usar

// Ok this is an Optional
Optional.of("hello world");

// I have no idea what this is 
of("hello world");
 4
Author: softarn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-25 13:08:31

Las importaciones estáticas son la única característica "nueva" de Java que nunca he usado y no tengo la intención de usar, debido a los problemas que acaba de mencionar.

 2
Author: Bombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-07 15:48:56

Recomiendo el uso de static import cuando se usa OpenGL con Java, que es un caso de uso que cae en la categoría "uso intensivo de constantes de una clase de utilidad"

Considera que

import static android.opengl.GLES20.*;

Le permite portar el código C original y escribir algo legible como:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(samplerUniform, 0);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuffer);
glVertexAttribPointer(vtxAttrib, 3, GL_FLOAT, false, 0, 0);

En lugar de esa fealdad común y extendida :

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(samplerUniform, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vtxBuffer);
GLES20.glVertexAttribPointer(vtxAttrib, 3, GLES20.GL_FLOAT, false, 0, 0);
 2
Author: Flint,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-19 23:38:11

Son útiles para reducir la verborrea, particularmente en los casos en que se llaman muchos métodos importados, y la distinción entre métodos locales e importados es clara.

Un ejemplo: código que implica múltiples referencias a java.lang.Matemáticas

Otro: Una clase XML builder donde anteponer el nombre de la clase a cada referencia ocultaría la estructura que se está construyendo

 1
Author: kdgregory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-07 15:57:48

Creo que las importaciones estáticas están limpias para NLS en el estilo gettext.

import static mypackage.TranslatorUtil._;

//...
System.out.println(_("Hello world."));

Esto marca la cadena como una cadena que tiene que ser extraída y proporciona una manera fácil y limpia de reemplazar la cadena con su traducción.

 1
Author: Matthias Wuttke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-26 10:30:13

IMO static import es una característica bastante agradable. Es absolutamente cierto que la gran dependencia de la importación estática hace que el código sea ilegible y difícil de entender a qué clase pertenece un método estático o atributo. Sin embargo, en mi experiencia se convierte en una característica utilizable especialmente cuando se diseñan clases Util que proporcionan algunos métodos y atributos estáticos. La ambigüedad que surge cada vez que se proporciona una importación estática puede eludirse mediante el establecimiento de normas de código. En mi experiencia dentro de un empresa este enfoque es aceptable y hace que el código sea más limpio y fácil de entender. Preferiblemente inserto el carácter _ delante métodos estáticos y atributos estáticos (adoptado de alguna manera de C). Aparentemente, este enfoque viola los estándares de nomenclatura de Java, pero proporciona claridad al código. Por ejemplo, si tenemos una clase AngleUtils:

public class AngleUtils {

    public static final float _ZERO = 0.0f;
    public static final float _PI   = 3.14f;

    public static float _angleDiff(float angle1, float angle2){

    }

    public static float _addAngle(float target, float dest){

    }
}

En este caso la importación estática proporciona claridad y la estructura del código se ve más elegante para mí:

import static AngleUtils.*;

public class TestClass{

    public void testAngles(){

        float initialAngle = _ZERO;
        float angle1, angle2;
        _addAngle(angle1, angle2);
    }
}

Inmediatamente alguien puede decir qué método o atributo proviene de una importación estática y oculta la información de la clase a la que pertenece. No sugiero usar importación estática para clases que son parte integral de un módulo y proporcionan métodos estáticos y no estáticos, ya que en estos casos es importante saber qué clase proporciona cierta funcionalidad estática.

 1
Author: eldjon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-25 16:16:21

Uso 'importar java estático.lang.Matemáticas.* 'when porting math heavy code from C / C++ to java. Los métodos matemáticos mapean 1 a 1 y hacen que diffing el código portado sea más fácil sin la calificación de nombre de clase.

 1
Author: Fracdroid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-30 16:37:04

Necesitas usarlos cuando:

  • desea utilizar una instrucción switch con valores de enumeración
  • desea hacer que su código sea difícil de entender
 1
Author: davetron5000,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-05 13:34:39

Hablando de pruebas unitarias: la mayoría de las personas usan importaciones estáticas para los diversos métodos estáticos que se burlan de los marcos proporcionan, como when() o verify().

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Y por supuesto, cuando se utiliza el único y único assert deberías usar ' assertThat () es útil importar estáticamente los matchers hamcrest requeridos, como en:

import static org.hamcrest.Matchers.*;
 0
Author: GhostCat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-25 13:16:22

Los uso siempre que puedo. Tengo preparado IntelliJ para recordármelo si se me olvida. Creo que se ve mucho más limpio que un nombre de paquete totalmente calificado.

 -5
Author: Javamann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-07 16:22:54