sábado, 28 de marzo de 2009

Enumeraciones en Java 5.0

En general manejamos ciertos datos que pertenecen a un tipo, por ejemplo cadenas de caracteres (String), datos numéricos enteros (int), en estos casos limitamos ciertos tipo de datos que puede almacenar una variable; ahora, lo que no teníamos hasta java 5.0 era la posibilidad de que una variable pudiese almacenar específicamente datos definidos por el usuario como los días de la semana, los meses de año, datos por ejemplode nombres de sistemas operativos, etc. Bueno, lo que veo que podíamos hacer es crear arreglos final de String y llamarlos con su índice, veamos un código:

public class ArregloFinal {

private final static String[] diasSemanas={"Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"};

public static void main(String[] args) {

System.out.println("Hoy es "+diasSemanas[0]);//Salida: “hoy es Lunes”

}

}

Esto crea dificultades al programar ya que aunque importemos en forma estática desde otra clase el arreglo y trabajar en base a él, debemos aprender el índice de cada elemento para poder llamarlo, otra manera sería trabajar con colecciones Hashmap (clave, valor) pero sería más fácil trabajar con un concepto viejo en programación pero relativamente nuevo en java 5.0: Las Enumeraciones.

Las enumeraciones se introdujeron en java 5.0 a nivel de clase, todas las enumeraciones hereden de la clase java.lang.Enum, que contiene métodos que discutiremos posteriormente en este mismo artículo. Javac al encontrar la palabra clave enum interpreta esa enumeración como una clase y por ello no puede haber un enum public en un archivo que ya contiene una clase pública, además también podemos tenerla dentro de una clase como una clase interna.

Con las enumeraciones, podemos crear una variable que almacenen datos específicos, veamos un código para entender mejor:

class Dias{

enum DiaSemana{lunes, martes, miercoles, jueves, viernes, sabado, domingo}

public static void main(String[] args) {

DiaSemana hoy = DiaSemana.jueves;

DiaSemana comienza = DiaSemana.lunes;

System.out.println("Semana comienza en "+comienza);

System.out.println("Hoy es "+hoy);

switch(hoy){

case lunes: System.out.println("Empezar a trabajar");

break;

case martes: System.out.println("Visitar Enfermos");

break;

//etc...

}

}

}

Puede verse que es mucho más fácil de manejar el código, la variable hoy puede almacenar cualquiera de los datos de lunes a domingo, por ejemplo podemos hacer que de acuerdo a un día el programa realice una actividad con un switch, en nuestro ejemplo anterior martes: visitar a los enfermos.

Bueno, los métodos que estudiaremos contenidos dentro de la clase java.lang.Enum, son ordinal() y compareTo() y name():

Ordinal devuelve el índice de la posición del elemento del enum (el primer índice es cero), por ejemplo hoy.ordinal(), devuelve tres.

En cuanto al método compareTo(), permite comparar dos valores de la enumeración, devuelve un entero negativo si el ordinal del invocador es menor al argumento, cero si sus ordinales son iguales o un número positivo si el ordinal del invocador es mayor.

hoy.compareTo(comienza) // devuelve un entero positivo ya que hoy es mayor

El último método que estudiaremos es name(), que devuelve por supuesto el nombre del ordinal.

hoy.name();//devuelve jueves

Por ser enum una clase puede contener propiedades y métodos:

Los dejo con el código para que analicen, una enum con propiedades y métodos:

enum EnumConMetodos{

Primero(1),

Segundo(2),

Decimo(10),

Otra(30);

private int bit;

private EnumConMetodos(int bitNumber) {

bit=bitNumber;

}

public int getBit(){

return(bit);

}

}

public class EnumExample{

public static void main(String[] args) {

EnumConMetodos elemento = EnumConMetodos.Decimo;//bit almacena 10

System.out.println("Elegido:"+elemento.ordinal()+"; con nombre:"+elemento.name()+";");

System.out.println(elemento.getBit());

}

}

martes, 3 de marzo de 2009

Importaciones estáticas en Java 5.0

Otra innovación de java 5.0 son las llamadas importaciones estáticas que permiten llamar a un método o propiedad estática sin necesidad de hacer referencia al nombre de su clase.

La sintaxis general, es:

import static paquete.Clase.metodo_o_propiedad_static; //Para un sólo método o propiedad.

import static paquete.Clase.*; //para todos los elementos estáticos de la clase


Tomemos en ejemplo de la clase Math, que se encuentra en el paquete java.lang, la mayoría de sus métodos son estáticos como lo son random (para generar números aleatorios), abs (para calcular el valor absoluto de un número) y muchos más. En la versión anterior de java debía hacer la llamada al método random de la siguiente manera: Math.random() o Math.abs(-67.15), sin necesidad de importar la clase Math para poder hacer efectivo el llamado al método, con la importación estática quedaría:

import static java.lang.Math.*;
public class ImportStatic {
public static void main(String[] args) {
System.out.println((int)(random()*5));//aleatorio entero entre 0 y 4
}


Con la primera línea estamos importando todas las propiedades y los métodos estáticos de la clase Math, podría darse el caso que sólo quiera importar random se cambiaría la primera línea de la siguiente manera:

import static java.lang.Math.random;

Luego, a la hora de llamar al método sólo debo escribir su nombre sin la clase (random();), esto permite reducir el tiempo de programación, en este caso de aplicaciones matemáticas, además de ello, veamos otro campo de aplicación de las importaciones estáticas:

Supongamos que tenemos una interfaz con varias propiedades:


interface ColorEnIngles{
public static String AMARILLO = "YELLOW";
public static String AZUL= "BLUE";
public static String ROJO = "RED";
}

Supongamos que vamos a implementar la interfaz ColorEnIngles, en una clase. Si lo hacemos creamos una dependencia innecesaria a la interfaz y además no podremos cambiar los valores de AMARILLO

class Colores implements ColorEnIngles{
public Colores(){
ColorEnIngles.AMARILLO += " ADDED";//Error de compilación
}
}

Se genera un error de compilación debido a que AMARILLO es un miembro de interfaz, tiene los modificados implícitos static y final. No puede cambiar.

Para poder lograr este cometido, entonces debemos entonces crear una clase en vez de una interfaz de la siguiente manera:


package importaciones;

class ColorEnIngles{
public static String AMARILLO = "YELLOW";
public static String AZUL= "BLUE";
public static String ROJO = "RED";
}


Es importante mencionar que la clase debe pertenecer a un paquete con nombre y no al paquete por defecto, debido a que al importarlo debemos hacer referencia al mismo. En el codigo anterior el nombre del paquete es importaciones.

Ahora, si tenemos:


import static importaciones.ColorEnIngles.*;

public class ColorTraducido{

public ColorTraducido(){
AMARILLO+=" ADDED";
System.out.println(AMARILLO);
}

public static void main(String[] args) {
ColorTraducido miColor = new ColorTraducido();
EnglishColor myColor = new EnglishColor();
}
}

class EnglishColor{
public EnglishColor(){
AMARILLO+=" ADDED";
System.out.println(AMARILLO);
}
}


Si compilamos y ejecutamos la clase ColorTraducido, por consola tendrá la siguiente salida:

YELLOW ADDED
YELLOW ADDED ADDED

Se demuestra que NO hizo falta llamar a las propiedades estáticas por medio del nombre de la clase (ColorEnIngles.AMARILLO), además pudimos utilizar la variable estática en las dos clases manteniendo su valor por tener modificador static en la clase ColorEnIngles. Primero la propiedad AMARILLO contiene el valor string "YELLOW", luego en ColorTraducido se modifica a "YELLOW ADDED" y en EnglishColor a "YELLOW ADDED ADDED".

Hey! se me olvidaba, si tienes más de una importación estática y una propiedad o método en ambas clases tienen el mismo nombre, para hacer el llamado a ésta o éste si debe colocarse el nombre de la clase seguido de la propiedad o método, ejemplo:

package paquete;

class Computadora{

public static String color;
public static String marca;
public static String modelo;
}

class Televisor{
public static String color;
public static String tamaño;
public static String marca;
}


en un nuevo archivo:


package paquete;

import static paquete.Computadora.*;
import static paquete.Televisor.*;

public class Ejecutora {
public static void main(String[] args) {
color="Negro";//Error de compilacion: Campo ambiguo
Televisor.color="Negro";//Ahora si
Computadora.color="Plateado";//Este también
}
}


Bueno, esto es todo lo que les quería comentar acerca de las importaciones estáticas, nos veremos en una próxima edición. Chao.