Pregunta

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. Entonces, 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);
  }
} 

Al crítico no le gustó que cambiara el código y no lo hice, pero estoy de acuerdo con él. Una razón dada para no importar estáticamente fue que era confuso dónde se definió el método, no estaba en la clase actual y no en ninguna superclase, por lo que es demasiado tiempo para identificar su definición (el sistema de revisión basado en la web no tiene clics) enlaces como IDE :-) Realmente no creo que esto importe, las importaciones estáticas todavía son 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 calificado parece pertenecer al objeto actual y no debe saltar contextos. Pero si realmente perteneciera, tendría sentido extender esa superclase.

Entonces, ¿cuándo tiene sentido tener métodos de importación estáticos? Cuando lo has hecho ¿Te gustó / te gusta la apariencia de las llamadas no calificadas?

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

Gracias por su respuesta chicos, estoy cerrando la pregunta.

¿Fue útil?

Solución

Esto es de la guía de Sun cuando lanzaron la función (énfasis en el original):

  

Entonces, ¿cuándo debería usar la importación estática? ¡Muy escasamente! Úselo solo cuando se sienta tentado a declarar copias locales de constantes o abusar de la herencia (el antipatrón de interfaz constante). ... Si usa en exceso la función de importación estática, puede hacer que su programa sea ilegible e imposible de mantener, contaminando su espacio de nombres con todos los miembros estáticos que importe. Los lectores de su código (incluido usted, unos meses después de que lo escribió) no sabrán 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:

  • Utilice las importaciones estáticas solo cuando haya tenido la tentación de "abusar de la herencia". En este caso, ¿habría tenido la tentación de que BusinessObject extienda 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 , este es probablemente un mal uso de las importaciones estáticas. No lo use solo para guardar algunos 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 función de lenguaje muy raramente, y casi siempre solo con constantes o enumeraciones, nunca con métodos. La compensación, para mí, casi nunca vale la pena.

Otros consejos

Otro uso razonable para las importaciones estáticas es con JUnit 4. En versiones anteriores de JUnit, los métodos como ClaimEquals y fail se heredaron ya que la clase de prueba extendió 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 de aserción 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 documentos utilizándolo de esta manera.

Java efectivo, segunda edición , al final de El artículo 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 costa de perder información inmediata sobre dónde se define el método. Sin embargo, un buen IDE le permitirá ir a la definición, por lo que este 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 importe (constantes o métodos).

Estoy de acuerdo en que pueden ser problemáticos desde una perspectiva de legibilidad y deben usarse con moderación. Pero cuando se usa un método estático común, en realidad pueden aumentar la legibilidad. Por ejemplo, en una clase de prueba JUnit, los métodos como afirmanEquals son obvios de dónde provienen. De manera similar para los métodos de java.lang.Math .

Lo uso mucho para Color.

static import java.awt.Color.*;

Es muy poco probable que los colores se confundan con algo más.

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

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

  

Utilizado apropiadamente, la importación estática puede hacer que su programa sea más legible, al eliminar la repetitiva repetición de los nombres de clase.

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

Entonces, por ejemplo:

Afirmaciones 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);

Clases y enumeraciones de utilidades

El nombre de la clase se puede eliminar en muchos casos cuando se utilizan clases de utilidades que hacen 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);
El

paquete java.time tiene algunos casos en los que debería usarse

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

Las importaciones estáticas son las únicas & # 8220; nuevas & # 8221; característica de Java que nunca he usado y que no pretendo usar nunca, debido a los problemas que acaba de mencionar.

Utilizo 'import static java.lang.Math. *' al portar código pesado matemático de C / C ++ a java. Los métodos matemáticos se asignan del 1 al 1 y facilitan la diferenciación del código portado sin la calificación del nombre de clase.

Recomiendo el uso de importación estática al usar OpenGL con Java, que es un caso de uso que cae en el " uso intensivo de constantes de una clase de utilidad " categoría

Considera eso

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 generalizada común:

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);

Son útiles para reducir la palabrería, 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 involucra múltiples referencias a java.lang.Math

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

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

import static mypackage.TranslatorUtil._;

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

Esto marca la cadena como una cadena que debe extraerse y proporciona una manera fácil y limpia de reemplazar la cadena con su traducción.

La importación estática de IMO 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 o atributo estático. Sin embargo, en mi experiencia se convierte en una característica utilizable, especialmente al diseñar clases Util que proporcionan algunos métodos y atributos estáticos. La ambigüedad que surge cuando se proporciona importación estática se puede eludir mediante el establecimiento de estándares de código. En mi experiencia dentro de una 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 _ en los métodos estáticos frontales y los atributos estáticos (de alguna manera adoptado 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 me parece más elegante:

import static AngleUtils.*;

public class TestClass{

    public void testAngles(){

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

De inmediato, 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 la 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 este caso es importante saber qué clase proporciona cierta funcionalidad estática.

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

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

Y, por supuesto, cuando se utiliza la única y única afirmación, se debe utilizar `afirmar que () resulta útil para importar estáticamente los emparejadores de obstáculos necesarios, como en:

import static org.hamcrest.Matchers.*;

Encontré que esto es muy conveniente cuando uso las clases de utilidad

Por ejemplo, en lugar de usar: if (CollectionUtils.isNotEmpty (col))

Puedo en su lugar:

import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
if(isNotEmpty(col))

¿Qué IMO aumenta la legibilidad del código cuando uso esta utilidad varias veces en mi código?

Debe usarlos cuando:

  • desea utilizar una instrucción switch con valores de enumeración
  • desea que su código sea difícil de entender

Los uso cuando puedo. Tengo la configuración de IntelliJ para recordarme si lo olvido. Creo que se ve mucho más limpio que un nombre de paquete totalmente calificado.

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