lunes, 5 de septiembre de 2005

Java 5. ¿Que tiene de bueno y de malo?. Parte III


Continuando con la serie de notas sobre los features de Tiger, hoy voy a hablar de static imports.

Static imports permite importar miembros estáticos de clases o interfaces de forma tal de no hacer uso del antipattern "Constant Interface".
Static imports no me gusta. No me parece algo que brinde facilidades, sino todo lo contrario, creo que molesta y hace poco legible el código haciendo que este se vea mas como un conjunto de funciones en lugar declases con métodos. En el único caso en el que veo que static imports puede ser útil es al utilizar enums o constantes.

¿Trabajando con funciones?

Aquí daré unos ejemplos de como puede verse el código de una clase como si fueran funciones:
import static java.util.Arrays.sort;
import static java.lang.System.out;
 
public class StaticImportTest {
    public static void main(String... args) {
        sort(args);       // llamo a la función
        out.println( deepToString(args) );       // llamo a otra función
    }
}

Aquí vemos como una clase en Java se parece a un archivo de código en C. Los static imports actúan como la directiva include y la llamada al método sort parece como si estuviéramos llamando a una función. Por otro lado, además de parece código estructurado, el código pierde legibilidad. Imaginemos una clase con muchos métodos, también imaginemos que tenemos que modificar esa clase y nos encontramos con algo así en nuestro código.
public void execute() {
   Integer[] array = {5,8,2};
 
   sort(array);
   out.println( deepToString(array) );
}

Surgen las siguientes dudas: ¿El método sort es un método estático importado o es un método privado de la clase?. A primera vista no lo sabemos. ¿Que sucede si nosotros creamos un método para la clase llamado sort(Integer a[]) en un escenario como este?. Los métodos que realicen las llamadas al método estático sort de Arrays se verán modificados en su comportamiento dado que ahora llamarán al nuevo método private creado, con lo cual estamos introduciendo un error sin darnos cuenta. Esto es porque en runtime tratará primero de ejecutar métodos de la clase y luego los métodos estáticos importados.
public void execute() {
   Integer[] array = {5,8,2};
   sort(array);    // Llama al método de instancia sort y no Arrays.sort()
   out.println( deepToString(array) );
}
 
private void sort(Integer[] a) {
   // nothing
}

¿Què sucede si tenemos varios static imports que tienen los mismos métodos?. Bueno aquí el compilador se da cuenta que la llamada al método sort es ambigua y nos da un error.

import static java.lang.System.out;
import static java.util.Arrays.sort;
import static staticimport.array.MyArrays.sort;
 
public class StaticImportError {
 
   public static void main(String[] args) {
      int[] array = {5,8,2};
      sort(array);   // ERROR en tiempo de compilación
 
      for(int i: array) {
         out.println( i );
      }
   }
}
 
...
public class MyArrays {
   public static void sort(int[] a) {
      // nothing
   }
}

Como se puede ser en estos casos (al menos desde mi punto de vista) el código es confuso y poco claro. De hecho en puede leerse en http://java.sun.com/j2se/1.5.0/docs/guide/language/static-import.html algo así:

Usar static import con moderación. Este es usado en situaciones cuando se necesita acceder con frecuencia a unos pocos objetos estáticos desde una o dos clases. El abuso de static import puede resultar en un código difícil de leer y mantener (como hemos visto ;)). Usado correctamente hace que el código sea más fácil de leer dada la eliminación de varios classnames repetidos.

No hay comentarios:

Publicar un comentario