viernes, 29 de mayo de 2009

Anotaciones en java 5

  Saludos y gracias por leer acerca de java, mi blog que en estos momentos desarrolla las ventajas e innovaciones de la programación con la versión 5 de java (J2SE 5.0). Espero le sea de ayuda.

  Ahora hablaremos de otra característica que fue agregada en java 5 que es la facilidad de metadatos a través de las llamadas anotaciones pertenecientes al paquete java.lang.annotation. Las mismas pueden utilizarse para generar o crear información adicional que beneficie tanto a los desarrolladores (documentando el código fuente, por ejemplo), como a usuarios de la aplicación que no están relacionados a la programación (metadatos en tiempo de ejecución). En anotaciones fue creado el concepto de retención, existe tres tipos de políticas de retención para las anotaciones:

    • SOURCE: la anotación sólo está disponible al momento de la programación, es decir, en el código fuente.
    • RUNTIME: la anotación puede estar disponible en tiempo de ejecución.
    • CLASS: Disponible en el archivo de clase, pero descartada en ejecución.

  En el JAVA API DE ANOTACIONES aparecen 4 anotaciones:

    • @Target: A quien podría o debe aplicarse la anotación.
    • @Documented: La anotación debe ser documentada por javadoc u otra herramientas de documentación.
    • @Inherited: Para heredar anotaciones de superclases, aunque no para interfaces.
    • @Retention:  Indica cuando va estar disponible la anotación, puede ser algunas de las tres políticas explicadas anteriormente:
@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.CLASS)

  Pero además de estas cuatro que aparecen en el JAVA API existen otras dos más:

    • @Deprecated: Para marcar un método como desaprobado, no debe ser utilizado en la programación ya que de seguro puede generar problemas, aunque esté disponible.
    • @Override: Se coloca antes de un método y se utiliza para indicar al compilador que se sobrescribirá el método de la superclase y por lo tanto este método debe estar definido en la clase primaria, de no ser así se genera un error en tiempo de compilación.
  Vamos a lo que más creo necesario, veamos un código ejemplo:

public class ClasePadre{
  public void metodo(){
        System.out.println("Metodo clase padre invocado");
  }

  @Deprecated
  public static void metodoestatico(){
    System.out.println("Estatico Desaprobado");
  }

  public static void main(String[] args) {
    ClasePadre ce = new ClasePadre ();
    ce.metodo();
    metodoestatico();/*Metodo desaprobado*/
  }
}

class ClaseHija extends ClasePadre {

  public void metodo(int x){}
  @Override
  public void metodo(){}
  @Override
  public void metodo(String cadena) {}
}
  En el código anterior la clase padre no tiene problemas y debe compilar aunque use un método desaprobado (deprecated), pero la clase hija no, veamos porque. El primer método que recibe un parámetro entero no tiene problemas ya que aunque no es heredado de la clase padre, el compilador crea este método para la clase hija, el segundo tampoco tiene problemas ya que sobrescribe el método de la súper clase (tiene la misma firma), pero el tercero si genera un error de compilación ya que el código afirma que sobrescribirá el método de la clase padre pero la firma es distinta, aquí se genera un error de compilación.
Bueno, por ahora no tengo más que decir, nos “vemos” en una próxima edición.

miércoles, 29 de abril de 2009

La Clase Scanner de java 5.

La clase Scanner que se introdujo a partir de java 5 tiene varias utilidades. Puede separar o romper su dato de entrada en subcadenas o “tokens” y además convertir estos datos en tipos primitivos como enteros, flotantes, etc. Por ejemplo, puedo pasarle un dato String como argumento al constructor, definir su patrón delimitador (por defecto: espacio en blanco) y obtener subcadenas cuyos miembros debo recoger uno a uno mediante el método next() o algunos de sus similares (nextInt(), nextByte()… para cada dato primitivo existe un next()), veamos un pequeño programa:

public static void main(String[] args) {
    String cadena = "Blog_Acerca_de_Java";
    Scanner s = new Scanner(cadena);
    s.useDelimiter("_");
    while(s.hasNext()){
        System.out.println(s.next()); //s.next() devuelve cadena token
    }
}

En este programa se separarán en subcadenas separando por “_” y se muestra cada término en una línea en la consola de java. Este tipo de uso es muy similar a usar la clase StringTokenizer.
Por otro lado, la clase Scanner también tiene un constructor que recibe un InputStream, por lo que podemos pasarle al mismo la sentencia System.in para leer datos desde el teclado:

public static void main(String[] args) {
    System.out.print("Introduzca datos: ");
    Scanner s = new Scanner(System.in);
    System.out.println(s.next());
    System.out.println(s.nextInt());
    System.out.println(s.nextLine());
}

Este último código lee datos a partir del teclado, separa en subcadenas con espacio en blanco como delimitador, lee la primera cadena y la imprime en consola, espera un espacio, después busca el siguiente dato e intenta convertirlo a entero (int) si no puede hacerlo lanza un InputMismatchException y se detiene, de no lanzar la excepción lee el siguiente dato hasta el final de la línea y lo imprime.
Otro constructor que también nos beneficia es el que recibe un archivo como parámetro. Supongamos que tenemos un archivo con esta información:

Kelvin
30
78,7
Horario: 8am a 4pm

Los datos de este archivo pueden ser tratados mediante el siguiente programa:

public static void main(String[] args) {
    try {
        Scanner s = new Scanner(new File("archivo.txt"));
        System.out.println(s.nextLine());
        System.out.println(s.nextInt());
        s.nextLine();
        System.out.println(s.nextDouble());
        s.nextLine();
        System.out.println(s.nextLine());
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (InputMismatchException e){
        e.printStackTrace();
    }
}

Recuerde colocar el archivo en la misma ruta el paquete del programa. Que fácil en comparación a los códigos de la versión anterior, ahora con la clase Scanner el manejo de archivos de acceso secuencial es mucho más fácil. Bueno, por ahora no tengo más que decir, espero esta información sea de utilidad, hasta una próxima edición.

Más información: Clase Scanner API Java

sábado, 18 de abril de 2009

Argumentos variables y System.out.printf() en Java 5.0 :

Java 5.0 introdujo la lista de argumentos variables mediante la elipsis, esto consiste en colocar tres puntos suspensivos después del tipo de dato en la declaración del método, en el último término (parámetro formal) del mismo de la siguiente manera:

public class ArgumentosVariables {

public ArgumentosVariables(){

System.out.println(sumar(2,3,4,5));

System.out.println(sumar(3,4));

}

public int sumar(int... valor){//Aquí está la elipsis

int resultado=0;

for(int i=0;i<valor.length;i++){

resultado+=valor[i];

}

return resultado;

}

public static void main(String[] args) {

ArgumentosVariables arg=new ArgumentosVariables();

}

}

La cantidad que puede recibir el método sumar puede estar entre cero a cualquiera, por lo tanto además de poder llamar al método sumar enviando dos enteros sumar(1,2) o 6 enteros sumar(1,2,3,4,5,6) también se podría llamar por sumar();y el método devolverá el resultado de la suma como resultado, ya que hace un recorrido por los valores de los argumentos (valor.length ) y suma cada término resultado+=valor[i].

Como se ha dicho, la elipsis sólo se acepta para el último término de la declaración del método, si se cambia la declaración del método sumar por el siguiente:

public int sumar(int... valor, String cadena){

Se arrojará el siguiente error de compilación:

“The variable argument type int of the method sumar must be the last parameter”.

Por lo tanto si puedo hacer:

public int sumar(String cadena, int... valor){

Bueno, en este tema no tengo más que explicar a menos que hayan dudas que quieran resolver por lo cual la parte de comentarios está abierta, por lo tanto he decidido hablar en este mismo artículo acerca del System.out.printf(); que utiliza las facilidades de los argumentos variables para imitar la capacidad de generar una salida por consola a la manera de lenguaje C, echemos un vistazo a la declaración del método printf:

printf (String format, Object... args)

Para los que no están familiarizados con el método, la cadena format indica la cadena que da formato de la salida y los objetos args son los valores que serán sustituidos en la cadena, veamos un ejemplo:

int suma=0, num1=7, num2=3;

suma=num1+num2;

System.out.printf("Al sumar %d mas %d, resulta: %d", num1, num2, suma);

//Salida generada: “Al sumar 7 mas 3, resulta: 10”;

En este caso el primer %d (%d significa numero entero) se sustituye con el primer valor ingresado después de la cadena (num1), luego, el segundo %d se sustituirá por el segundo entero y así sucesivamente, sino es así y por ejemplo se le pasa un valor double el programa compilará pero al ejecutarlo lanzará una java.util.IllegalFormatConversionException.

Si el número de variables de la cadena (tres ‘%d’ en el ejemplo) es menor al número de valores pasados como argumentos el programa compilará e ignorará los valores que están de más, pero si es mayor el programa compila pero arroja un java.util.MissingFormatArgumentException, ya que el número de valores pasados en los argumentos variables no satisface el número de valores esperados de la cadena.

Además de %d existen otros tipos por supuesto, a continuación tenemos los tipos con un ejemplo para cada uno:

%f: Para valores float o double:

System.out.printf("valor flotante: %f", 5.3f);// Salida “valor flotante: 5,300000”

%x.yf: Para float o double con formato ‘x’ dígitos ‘y’ decimales:

System.out.printf("valor pi: %6.4f", Math.PI);// Salida “valor pi: 3,1416” 6 dígitos, 4 decimales.

%x.ye %n: Para Notación científica: ‘x’ dígitos (incluyendo e+ o e-) ’y’ decimales

System.out.printf ("Notacion cientifica = %7.3e %n", 123456.0);//Salida “Notacion cientifica = 1.235e+05”

%o: Octal

System.out.printf("Octal: %o",25);// Salida “Octal: 31”

%h: Hexadecimal

System.out.printf("Hexadecimal: %h",255);

Espero información los ayude.

Bueno, por ahora es todo, hasta una próxima edición. Dios los bendiga.

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.

sábado, 28 de febrero de 2009

Bucle for mejorado en java 5.0

Otra de las novedades que tiene Java 5 es el ciclo for mejorado, de tal manera que si vamos a recorrer un arreglo de String debemos colocar:

for(String valor: nombreArreglo){
System.out.println(valor);

}

Y así se estará recorriendo e imprimiendo en pantalla todo el arreglo, se necesita el tipo de dato del valor del arreglo separado con dos puntos del nombre del arreglo. Esto es una ventaja en cuanto a legibilidad, pero para los que estamos acostumbrados podemos seguir usando el recorrido a la manera de java 1.4 que todavía tiene vigencia. Ahora una de las ventajas que de este ciclo for se ve en las colecciones, hablemos de ello:

Con java 5 no es necesario crear un iterator para realizar un recorrido a una colección, inclusive se evitan los casteos explícitos que se realizaban para obtener los valores almacenados en ella, por ejemplo:
Si para hacer el recorrido por una colección escribíamos el siguiente código, en java 1.4:

for(Iterator iter=miCollect.Iterator();iter.hasnext();){
Integer intObjeto = (Integer) iter.next();
System.out.println(“”+intObjeto);

}


Ahora desde java 5 sólo tendría que escribirse:

for(Integer intObjeto: miCollect){
System.out.println(“”+intObjeto);
}

Reduciendo así la claridad del código y haciendolo mucho más simple.

domingo, 22 de febrero de 2009

Auto boxing y unboxing desde java 5.0

Siguiendo con la temática de las innovaciones de java 5.0 hablemos ahora sobre los llamados boxing y unboxing, siendo éstas operaciones automáticas que se realizan cuando se intenta asignar a un objeto de una clase envolvente, una variable creado con su tipo primitivo correspondiente, o viceversa, veamos un ejemplo con el siguiente código:

public class Boxing {

public static void main(String[] args) {
double primitivo1, primitivo2;
Double envuelto;
primitivo1=98.15;
envuelto=primitivo1;
System.out.println(envuelto);
primitivo2=envuelto;
System.out.println(primitivo2);

}

}

Podemos ver en las primeras dos líneas de el método main que se crean tres variables, primitivo1 y primitivo2 son variables del tipo primitivo double y el tercero de nombre "envuelto" es un objeto del tipo de referencia (o envolvente) Double. Como puede verse puedo crear un dato de tipo primitivo double y asignárle su valor a un objeto de su tipo de referencia Double, como también puedo hacer lo contrario.

Al proceso se asignar al objeto de la clase envolvente un dato de su tipo primitivo correspondiente se llama boxing
(En el código: envuelto=primitivo1) y al procedimiento contrario, es decir, a asignarle a un dato primitivo un objeto de su clase envolvente se llama unboxing (En el código: primitivo2 = envuelto).

Esta operación a diferencia del casteo o moldeo es una operación implícita, es decir, la realiza java automáticamente, no es necesaria ninguna instrucción.

Veamos como esto puede simplificarnos la vida con las colecciones, tomando como ejemplo un objeto Vector:

public class Boxing {

public static void main(String[] args) {
Vector<Integer> vect = new Vector<Integer>();
int primitivo=15;
vect.add(primitivo);
}

}


En el método main de la c
lase Boxing se creó un objeto Vector con Generics que almacena Integer, si el boxing no estuviese disponible, yo tendría que haber realizado una creación de un objeto Integer, de la siguiente manera:

Integer envuelto = new Integer(primitivo);

Y después asignar al vector vect.add(envuelto) ya que Vector maneja Integer, por lo que nos ahorraríamos un línea de código, simplificando el trabajo y dejando a java resulelva esos inconvenientes. es decir, se elimina la necesidad de crear un objeto Integer para colocar un int en la colección.

Las conversiones permitidas son:

boolean <--> Boolean
byte <--> Byte
char <--> Character
short <--> Short
int <--> Integer
long
<--> Long
float <--> Float
double <--> Double


Bueno, espero haberme explicado y esta información les sea útil para conocer más herramientas sobre java 5.0, sin más, me despido hasta una próxima edición.