sábado, 31 de enero de 2009

Tipos Genéricos o Parametrizados en Java 5.0

Saludos y bienvenidos a mi segunda publicación de Acerca de Java. Como lo prometido es deuda, aquí discutiremos acerca de los Tipos Genéricos o Parametrizados.

Estos tipos genéricos o parametrizados (Generics) es una de las innovaciones más conocidas que promueve Java 5.0, estos nos permiten crear una clase que pueda operar con cualquier tipo de dato, pero este tipo no se especifica hasta que se instancie la clase. Por ello, la clase es genérica, de allí su nombre, también es llamada parametrizada por que el parámetro es especificado en la instanciación, es el parámetro de tipo formal.

Aunque puedo crear mis propias clases que trabajen con cualquier tipo de dato de referencia (Integer, Float, Double -- como se ve en el último ejemplo de este artículo --), la mayor utilidad que se les da a los generics es con las colecciones, ya que en ellas puedo definir con que tipo de dato trabajará la misma. Por ejemplo las clases ArrayList, Vector, HastTable y demás colecciones que en las versiones anteriores manejaban datos Object solamente, ahora podemos especificar que tipo de datos manejarán. Nuestros ejemplos usarán sólo ArrayList, sólo por utilizar alguna.

Supongamos que en la versión anterior de Java, tenemos el siguiente código:

//Codigo 1:
ArrayList strLista = new ArrayList();
ArrayList intLista = new ArrayList();

Podemos suponer por el nombre de los objetos ArrayList que el primero alvergará String y el segundo enteros, (OJO, sólo por el nombre lo suponemos) pero no es así, la verdad ambos objetos podrán trabajar con cualquier tipo de dato, ya que ArrayList trabaja con Object y este tipo de dato permite cualquier tipo de datos como Integer, String, Float o Double, etc...

Ahora veamos el siguiente código, utilizando Genéricos de java 5.0:

//Código 2:
ArrayList<String> strLista = new ArrayList<String>();
ArrayList<Integer> intLista = new ArrayList<Integer>();

Ahora si hemos especificado que strLista trabajará con cadenas de caracteres y intLista con enteros, sólo agregando entre corchetes el tipo de dato. El compilador arrojará un error si en alguna oportunidad intentamos asignar al objeto un dato que no cumpla con su norma, es decir, podremos hacer:

//Código 3:
strLista.add("Cadena 1 para strLista");
strLista.add("cadena 2 para strLista");

pero no:

//Código 4:
strLista.add(3);

Mientras que el compilador hubiera aceptado el código 4 si se hubiese creado strLista y intLista por el código 1.

A continuación las ventajas que esto trae:

* El compilador no aceptará que se agregue ningún tipo de dato distinto al especificado en la instanciación de la clase.
* No es necesario añadir los castings que eran indispensables para recuperar los datos homogéneos de una colección Object.
* Se mantiene un mayor control sobre la colección ya que si en la versión anterior la colección hubiese aceptado el código 4, al ejecutar el código 6 hubiese ocurrido un error en tiempo de ejecución que puede ser más difícil de detectar y/o manejar.

Veamos el siguiente código:

//Código 5: Lo correcto en generics


Iterator<String> strIterador = strLista.iterator();
while (strIterador.hasNext()) {
String dato = strIterador.next();
System.out.println(dato);
}



//Codigo 6: Lo que ahora no es necesario:


Iterator strIterador = strLista.iterator();
while(strIterador.hasNext()){
String dato = (String) strIterador.next();/*Este cast
ya no es necesario si se utiliza Generics*/
System.out.println(dato);
}

Aunque ambos códigos son válidos es mejor usar el código 5, por las ventajas que implica.

NOTAS IMPORTANTES:
Hay que tener en cuenta que no pueden crearse Generics con los tipos de datos primitivos como int, float, double. Si lo intentase el compilador arrojaría un error. También es necesario saber que no se permiten arreglos de Generics, el siguiente codigo no es permitido:

//Codigo 7

ArrayList<String> strLista[] = new ArrayList<String>[3];

Con el codigo 7 el compilador arrojará un error mencionando la no disponibilidad de arreglos de generics.

Acerca de los Comodines en Generics:
Para terminar sobre nuestro artículo dedicado a Generics, es necesario mencionar el tema de los comodines. En algunos momentos se quiere que una clase genérica se comporte se comporte como una super clase de otras clases genéricas, veamos el siguiente ejemplo explicativo:

//Codigo 8:


public class Comodin<E extends Number> {

E item;

public E getItem() {
return item;
}

public void setItem(E item) {
this.item = item;
}

public static void procesarNumero(Comodin<Number>
nbrComodin){
System.out.println("Procesando Number");
}

public static void procesarDouble(Comodin<Double>
dblComodin){
System.out.println("Procesando Doubles");
}

public static void procesarComodin(Comodin<?>
cmdComodin){
System.out.println("Procesando Comodin");
}

/*
* public static void procesarString(Comodin<String>
* strComodin){
*
* }
*/
public static void main(String[] args) {
Comodin<Number> nbrComodin = new Comodin<Number>();
Comodin<Double> dblComodin = new Comodin<Double>();
nbrComodin.setItem(new Double(5));
nbrComodin.setItem(new Float(3.3f));
// procesarNumero(dblComodin);
procesarNumero(nbrComodin);
procesarDouble(dblComodin);
// procesarDouble(nbrComodin);
procesarComodin(nbrComodin);
procesarComodin(dblComodin);
}
}


Es un código un poco más largo pero ejemplifica perfectamente lo que es posible con los comodines, se puede ver que la clase Comodín puede manejar cualquier tipo de dato numérico ya que se colocó Comodin<E extends Number> por ello podré realizar instancias como: Comodin<Number>, Comodin<Double> o por ejemplo puedo colocar el comodín y decir Comodin<?>, con ello estamos diciendo que en este caso podré manejar cualquier tipo de dato de referencia siempre y cuando sea Number o cualquier subtipo de ella. Por lo mismo, el método procesarString no dejará compilar el código si apareciera descomentado.

El comodín no puede utilizarse para crear instancias es sólo para métodos que reciben como parámetro una clase Genérica o para declarar clases genéricas que necesiten cualquier tipo de dato, podemos ver el ejemplo con procesarComodin en caso de métodos que reciben instancias de cualquier tipo o podemos hacer:


List<?> lista = new Arraylist<CualquierClase>();


Esto es equivalente a:

List lista = new Arraylist();


La diferencia está en que la segunda lanza una advertencia (Warning) ya que prefiere una especificación de parámetro genérico aunque sea comodín.

Además, se puede asignar a un objeto Comodin<Number> un valor Double o Integer debido a que son numéricos, esto se puede ver cuando se realiza nbrComodin.setItem(new Double(5)); , pero en el caso de que desee pasar a un método que recibe una clase genérica de Double, no puedo pasarle una Number, ni Integer, debe ser una clase Comodin<Double>, como lo indica la declaración del método, a menos que utilice el comodín "?" que especifica que puedo pasar cualquier tipo de clase numérica, por eso no puedo descomentar procesarNumero(dblComodin); ni procesarDouble(nbrComodin);, ya que no dejarían compilar el código.

Bueno, espero me haya explicado y haya servido este material para aclarar el tema de los generics de java 5.0, sin más, me despido hasta a próxima. Chao...

jueves, 29 de enero de 2009

Bienvenidos a mi blog Acerca de Java

¡Saludos compañeros!.

Reciban un cordial saludo desde Maracaibo - Venezuela.

Este blog lo he creado con la finalidad de compartir información acerca de la tecnología Java, comenzaré hablando de Java 5.0 y algunas de las innovaciones que ella trajo, para información puedo decir que ya la versión 6.0 fue liberada, pero para irnos adaptando a ella primero demos un paseo por su homólogo anterior.

Enumeremos la lista de las innovaciones que serán discuidas en las siguientes sesiones:

* Tipos Geréricos o Parametrizados (Generics)
* Boxing y Unboxing
* Bucle for mejorado
* Importaciones estáticas
* Pasar Argumentos variables a un método
* Novedades en las Enumeraciones
* System.out.printf(); //Si como lenguaje C o C++

Espero podamos compartir información valiosa para prepararnos en esta tecnología.

Por ahora me despido.
Kelvin Atencio
Maracaibo - Venezuela