miércoles, 15 de febrero de 2012

Lo nuevo de Java 7

En julio de 2011 Mark Reinhold presentó la primera versión de de Java 7. Entre la versiones 5 y 6  no hubo grandes modificaciones ni del lenguaje ni de la VM pero la versión 7 sí que nos trajo cambios significativos. A la espera que Java 8 vea la luz en Octubre de este año, os presento una lista de 7 cambios de señor Java 7. La lista completa la podéis consultar aquí.




Cadenas en switchs

Si amigos por fin, no entiendo el motivo para no incorporar antes esta característica que tanto he echado en falta en multitud de ocasiones. Antes sólo lo podíamos utilizar con tipos básicos como char, byte, short, int,Character, Byte, Short, Integer o tipo enumerado (desde la versión 5). Ahora nos podemos olvidar de colocar sentencias if-else interminables y las comparación con el método equals de String, teniendo un código mucho más limpio y entendible.

public void testStringSwitch(String direction) {

        switch (direction) {

             case "up":

                 y--;

             break;



             case "down":

                 y++;

             break;



             case "left":

                 x--;

             break;



             case "right":

                 x++;

             break;



            default:

                System.out.println("Invalid direction!");

            break;

        }
    }

Antes cuando definíamos por ejemplo una lista genérica y queríamos instanciarla mediante su constructor debíamos indicar el tipo tanto en el momento de la definición como en el momento de instanciarla dinámicamente. Ahora ya no tendremos que indicarla en el momento de la asignación dinámica (en el constructor) porque se infiere de la definición del tipo.

Antes de Java 7:

List strings = new ArrayList();

En Java 7:

List strings = new ArrayList();

En casos de tipos más complejos puede ser muy útil no repetir de nuevo todos los tipos:

Gestión múltiple de excepciones

Antes teníamos que definir en varias sentencias try-catch el código para crear una instancia por Reflection, crear nuevos recursos como ficheros, etc... Ahora todo esto se puede compactar en una única línea separando las excepciones con el carácter "|".

Antes de Java 7:

try {
    Class a = Class.forName("wrongClassName");
    Object instance = a.newInstance();
} catch (ClassNotFoundException ex) {
    System.out.println("Failed to create instance");
} catch (IllegalAccessException ex) {
    System.out.println("Failed to create instance");
} catch (InstantiationException ex) {
   System.out.println("Failed to create instance");
}

Después de Java 7:


try {
    Class a = Class.forName("wrongClassName");
    Object instance = a.newInstance();
} catch (ClassNotFoundException | IllegalAccessException |
   InstantiationException ex) {
   System.out.println("Failed to create instance");
}

Try-Catch con gestión de recursos

En Java 7 tenemos la posibilidad de gestionar los diferentes recursos (File, Statement, ResultSet, Socket...) mediante sentencias try-catch sin tener que poner la sentencia finally. Dicha sentencia se utiliza para asegurar que se ejecuta un código determinado después de un bloque try-catch, bien se produzcan excepciones o  no. Normalmente aquí se cerraban los recursos que abríamos mediante el bloque try-catch, asegurando la correcta gestión de los diferentes recursos.

Antes de Java 7:


try {
            in = new BufferedReader(new FileReader("test.txt"));

            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (in != null) in.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

En Java 7:



       try (BufferedReader in=new BufferedReader(new FileReader("test.txt")))
       {
            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }


Mejorada la API de IO

Hay varios cambios en el paquete java.nio, sobre todo relacionados con el rendimiento. También se han realizado mejoras del paquete java.io (sobre todo de la clase java.io.File), lo que ha desencadenado que se crease un nuevo paquete (java.nio.file).

Entre las las clases más relevantes de este paquete están:
  • java.nio.file.Path. Interfaz que sustituye a la clase java.io.File.
  • java.nio.FileSystem. Para obtener las rutas de los diferentes ficheros.
  • java.nio.FileSystems. Factoría con la que se puede obtener una instancia de FileSystem mediante el método getDefault().
  • java.nio.Files. Contiene los métodos estáticos necesarios para las operaciones con ficheros. Por ejemplo, abajo podemos ver como podemos leer todas las líneas de un fichero y guardarlas en una lista mediante el método readAllLines. Con esta clase también podemos crear enlaces simbólicos a ficheros (imposible antes de Java 7). Otra característica que se añade en Java 7 es la posibilidad de establecer permisos de ficheros en una sistema de ficheros compatible con POSIX mediante el método Files.setPosixFilePermissions. Antes de esto sólo se podía haver mediante la interfaz JNI o mediante 'hackeos' con System.exec()
Mediante la API del WatchService también podemos recibir notificaciones sobre diferentes elementos. Por ejemplo, podemos indicar que se nos notifique cuando se creeen ficheros, modifiquen o se borren ficheros en un directorio del sistema de ficheros determinado. 

Ejemplo de lectura de fichero con Java 7:


List lines =  Files.readAllLines(
       FileSystems.getDefault().getPath("test.txt"), StandardCharsets.UTF_8);

       for (String line : lines) System.out.println(line);

Soporte para lenguajes no Java (invokedynamic)

En la versión 7 hay una nueva instrucción a nivel de bytecodes llamada invokedynamic. Esta instrucción no podrá ejecutarse desde Java pero será muy útil para los lenguajes dinámicos que corran bajo la JVM.

En un lenguaje con tipado estático como Java todos los tipos de las variables se conocen en tiempo de compilación mientras que en un lenguaje tipado dinámicamente como JRuby, Groovy,... esto no es así. 

Cuando en un lenguaje dinámico que corre bajo la JVM invocamos un método de un objeto que desconoce, se invoca ese método a nivel de bytecode mediante la reflection de Java. 

A modo de ejemplo, en un lenguaje dinámico llamaríamos al método de un objeto desconocido de esta forma: 

def veamos( objeto )
    objeto.salvar()
end

Que en un lenguaje Java sería algo similar a hacer esto:

Method m = objeto.getClass().getMetodo("salvar");
m.invoke( objeto )

Actualmente hay varios tipos de reflexión en Java:

  • invokevirtual. Para llamar a un método de un objeto.
  • invokeinterface. Para llamar a métodos de interfaces (objeto debe implementar interfaz).
  • invokestatic. Para llamar a un método de una clase.
  • invokespecial. Para llamar a constructores.
Con Java 7 se añade invokedynamic, para llamar a un método de un objeto desconocido. Esto hará que a nivel de bytecode, las llamadas a este tipo de métodos desde otros lenguajes tipados dinámicamente ya no se apoyarán en la reflection de Java, sino en esta nueva instrucción.

Las ventajas de esto es que se mejora el rendimiento a la misma vez que hace que la JVM sea independiente del lenguaje, por lo que aumenta la interoperabilidad entre componentes creados en otros lenguajes y los programas escritos en Java.

JLayerPane

Componente similar a uno proporcionado en el proyecto JXLayer, que sirve para añadir efectos a componentes Swing. JLayerPane permite decorar los componentes gráficos de Swing y añadir eventos a los mismos sin modificar el código de esos componentes.

JLayerPane (Foto: sellmic)

Via: sellmic

No hay comentarios:

Publicar un comentario en la entrada