jueves, 28 de octubre de 2010

Cambio de blog

Hola,
he decidido mudarme a un nuevo servicio de blogging, podrás encontrarme en:

http://franciscoguemes.wordpress.com

En los días sucesivos a esta entrada iré pasando las distintas entradas de un sitio a otro, para después continuar editando en el nuevo sitio.
Saludos.

domingo, 10 de octubre de 2010

Comparar dos vectores

Suponiendo el caso de que se tienen dos vectores (a1 y a2) de int, boolean, double, float, long, char, byte e incluso Object, la forma mas rápida de comparar estos dos array en Java es:

java.util.Arrays.equals(a1,a2);

Esta simple línea de código evita métodos static (o posibles códigos duplicados) similares al siguiente:



/**
* Comprueba que los dos array de double contienen exáctamente los mismos
* valores, y por tanto son iguales.
*
* @param a1 Primer array de números reales.
* @param a2 Segundo array de números reales.
* @return Verdadero si los array son iguales. Falso en caso contrario.
*/
private boolean compareArray(double [] a1, double [] a2){
boolean equals = false;
if(a1.length == a2.length){
int emembers =0;
for(int i=0 ; i < a1.length ; i++){
if(a1[i] == a2[i])
emembers++;
}
if(emembers == a1.length)
equals=true;
}
return equals;
}

sábado, 9 de octubre de 2010

Leer de la línea de comandos

Leer una entrada del usuario de la línea de comandos en Java a priori no es tan intuitivo como puede ser en C o C++.En Java existen 2 opciones para llevar esto a cabo.

Usando streams
Es la forma mas extendida, se usa el flujo de entrada por defecto (System.in),el cuál se recubre creado un InputStreamReader (transforma los bytes en caracteres) y este último se usa para construir un flujo de entrada con buffer.


BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
String line = in.readLine();
} catch (IOException e) {
//Hacer lo que sea si falla...
e.printStackTrace();
}


Usando la clase Console
Esta opción no es tan extendida. Se usa la clase Console, la cuál por debajo hace uso de streams. Esta forma es muy similar a como se haría en C#.

java.io.Console c = System.console();
String name = c.readLine();


El método console de la clase System puede retornar null si el sistema operativo no tiene una consola asociada o porque no permite este tipo de operaciones (esto se suele dar en hardware básico, teléfonos móviles, router, etc ...), o bien porque se está lanzando la aplicación desde un entorno no interactivo como puede ser un IDE (Eclipse,NetBeas, etc...).

Apariencia de un JFrame

La problemática no es crear un JFrame, ya que cualquier programador sabe crear una clase que herede de JFrame. El problema es que la nueva ventana tenga la apariencia deseada. Así que en el siguiente ejemplo se recogen unas cuantas líneas de código típicas a la hora de cambiar el aspecto que tiene por defecto un JFrame:


public class MainFrame extends JFrame {

MainFrame(){
this.setTitle("Mi ventana Java");

//Fija el tamaño de la ventana
this.setSize(300,300);

//Cambia el icono de la taza de café
this.setIconImage(new ImageIcon("mi_imagen.png").getImage());

//Hace que la ventana no se pueda redimensionar
this.setResizable(false);

//Hace que la ventana aparezca centrada en la pantalla
this.setLocationRelativeTo(null);

}
}


Otras opciones que pueden resultar interesantes

Dimensionar la ventana al tamaño de la pantalla:
Hacer que la ventana tenga el mismo tamaño que la pantalla en la que va a aparecer:

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setSize(screenSize);


Maximizar la ventana:
Es decir que la ventana aparezca de entrada ya maximizada en la pantalla.

this.setExtendedState(JFrame.MAXIMIZED_BOTH);


Quitar el marco de la ventana:
Quita el marco en el que aparece el título de la ventana y los botones de minimizar, maximizar y cerrar la ventana:

this.setUndecorated(true);

Ajustar la ventana:
Hacer que toda la jerarquía de componentes contenidos en la ventana, se vaya ajustando a sus respectivos tamaños, partiendo del tamaño de la ventana. (Produce una serie de llamadas en cascada al método pack de cada componente contenido en la ventana). Este método siempre debe ser el último en ser llamado en el constructor del JFrame personalizado que se esté creando.

this.pack();


Mostrar el JFrame
Finalmente para que el JFrame sea visible, hay que invocar el método setVisible. Una buena práctica es invocar este método en la línea de código siguiente a la instanciación del objeto derivado de JFrame. De esta forma se evitan posibles errores lógicos en el constructor de la clase implementada, ya que algunas llamadas a determinados métodos no tienen efecto una vez que la ventana es visible. En el siguiente ejemplo se ha creado una clase llamada StartPoint que será el punto de comienzo de la aplicación.

public class StartPoint {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MainFrame mf = new MainFrame();
mf.setVisible(true);
}
});
}
}

jueves, 7 de octubre de 2010

Quitar el encabezamiento / pie de página en Calc

Para quitar el pie de página en OpenOffice Calc hay que seguir los siguientes pasos:
  1. Ir al menú Formato
  2. Seleccionar la opción Página
  3. En la ventana emergente seleccionar la pestaña Pie de página
  4. Activar/desactivar la casilla correspondiente.
Para activar/desactivar el encabezamiento hay que seguir los mismos pasos, pero en el paso 3, seleccionar la pestaña Encabezamiento.
Con esto se consigue evitar (o forzar) que el programa imprima por defecto el número de página y de hoja, o cualquier otro encabezado o pié de página que el usuario haya podido configurar.

miércoles, 6 de octubre de 2010

Números aleatorios

Para crear un número aleatorio en Java (mejor dicho pseudoaletorio, ya que siendo purista, hay que matizar que la aleatoriedad como tal, no existe en la informática) lo mas sencillo es usar la siguiente sentencia de código:

double randomNumber = java.lang.Math.random();

Esto creará un double comprendido en el intervalo [0,1).
Si lo que interesa es crear un número comprendido dentro de otro rango, por ejemplo [a,b] entonces se puede usar una expresión del tipo:

randomNumber = (randomNumber +1) * (b-a) + a-2;

o lo que es lo mismo:

randomNumber = randomNumber * (b-a) + b - 2;

Aunque nunca se llegará realmente a conseguir el número b, si se conseguirán valores muy próximos. Este tipo de expresiones solían hacerse en programación C.
Java ofrece una forma alternativa de obtener un número real en el rango [0,1), esta forma es creando una instancia de la clase java.uti.Random:

java.util.Random r = new java.util.Random();
double randomNumber = r.nextDouble();

La principal ventaja de usar la case Random es que tiene unos cuantos métodos para generar números pseudoaletarios de distintos tipos. Entre estos métodos cabe destacar el constructor parametrizado de la clase y el método nextInt:

long seed = 1001;
java.util.Random r = new java.util.Random(seed);
int integer = r.nextInt(10);

El número 1001 (valor arbitrario de la variable seed) es la semilla del generador de números pseudoaleatorios. Esta semilla determinará la secuencia de números aleatorios a producir (solo para números enteros). El método nextInt generará números enteros comprendidos en el rango [0,9].

martes, 5 de octubre de 2010

Caracter separador de directorios

Si se desarrollan aplicaciones Java, que pretendan ser multiplataforma, y estas aplicaciones acceden a distintos recursos de sistema (ficheros, dispositivos, etc ...), usando rutas relativas o bien absolutas, dependiendo de en que plataforma se ejecute la aplicación, el carácter separador de directorios cambiará dependiendo del sistema operativo anfitrión.

En Windows será el Backslash "\" y en linux/Unix será el Slash "/". Con el fin de evitar porciones de código específicas para cada sistema (como lo visto en la anterior entrada: Averiguar el Sistema Operativo Anfitrión), Java trae de serie la posibilidad de ahorrar este trabajo sucio al programador mediante cualquiera de estos códigos:

char c = java.io.File.separatorChar;
String s = java.io.File.separator


El primero devuelve el separador como un tipo de dato char, y el segundo como un objeto String.

viernes, 1 de octubre de 2010

Averiguar el Sistema Operativo Anfitrión

Para averiguar el sistema operativo anfitrión basta con ejecutar la siguiente línea de código:

String os = System.getProperty("os.name");

El contenido de la cadena "os" puede ser:
  • AIX
  • Digital Unix
  • FreeBSD
  • HP UX
  • Irix
  • Linux
  • Mac OS
  • Mac OS X
  • MPE/iX
  • Netware 4.11
  • OS/2
  • Solaris
  • Windows 2000
  • Windows 7
  • Windows 95
  • Windows 98
  • Windows NT
  • Windows Vista
  • Windows XP
Con lo cuál el programa puede elegir que hacer, si es que hay alguna parte específica que dependa del sistema operativo anfitrión:

if(os.startsWith("Windows")){
//Hacer lo que sea ...
}else{
//Ya se sabe que el sistema no es de la familia Windows ...
//Hacer lo que corresponda
}


jueves, 4 de marzo de 2010

Nested Classes, las grandes desconocidas.

¿Qué son las Nested Classes? Básicamente son clases embebidas dentro de otras clases, en castellano sería algo así como clases internas. Se pueden subdividir en 2 categorías:

  • Clases internas estáticas (Static Nested Classes)
  • Clases internas no estáticas (Inner Classes)

Clases internas estáticas

Una clase interna de este tipo puede interactuar con la clase contenedora igual que lo haría cualquier otra clase externa a la clase contenedora. Es decir, una clase interna estática no puede acceder a las variables de instancia o métodos de la clase contenedora de forma directa y viceversa, debe hacerlo a través de una referencia a la clase contenedora (igual que lo harían el resto de clases). Esto se ve mejor con un pequeño ejemplo:

   1: public class ClaseContenedora {



   2:     private int a;



   3:     



   4:     public ClaseContenedora(int n){ this.a=n; }



   5:     



   6:     public int getA(){ return this.a; }



   7:     



   8:     public static class ClaseInterna{    



   9:         public void imprimirClaseContenedora(ClaseContenedora cc){



  10:             //System.out.println(a);



  11:             System.out.println(cc.getA());



  12:         }    



  13:     }



  14:     



  15:     public static void main(String[] args) {



  16:         ClaseContenedora cc = new ClaseContenedora(5);



  17:         ClaseContenedora.ClaseInterna ci = new ClaseContenedora.ClaseInterna();



  18:         ci.imprimirClaseContenedora(cc);



  19:     }



  20: }




En el ejemplo se ve como desde la clase interna no se pueden acceder a los miembros de la clase contendora directamente si no es por medio de una referencia a la clase contenedora. Si se descomenta la línea 10 el compilador dará un error, ya que la clase interna no puede acceder al atributo “a” de la clase contenedora.

Clases internas no estáticas o Inner Classes

Son las mas empleadas, tanto para esconder funcionalidad dentro de una clase, como para el manejo de eventos.

Las Inner Classes si son capaces de acceder directamente a los miembros de la clase contenedora (incluso si estos han sido declarados como privados). Mientras que la clase contenedora accede imagea la clase interna igual que lo haría con cualquier otra clase externa a la misma (a través de una referencia de la clase). Una instancia de una clase interna puede existir solo dentro de una clase contenedora.

En la imagen se aprecia como la clase interna no estática se encapsula dentro de la clase contenedora quedando totalmente oculta al exterior. Es decir no puede haber instancias de una Inner class fuera de la clase contenedora.

Las Inner class se puede subdividir en 3 grupos:

  • Inner class Miembros
  • Inner class Locales
  • Inner class Anónimas

Inner class Miembros


Es una clase interna declarada como un miembro de la clase contenedora. Veamos el ejemplo anterior pero ahora aplicado a un Inner Class miembro:



   1: public class ClaseContenedora {



   2:     private int a;



   3:     



   4:     public ClaseContenedora(int n){ this.a=n; }



   5:     



   6:     public void imprimirNumero(){



   7:         InnerClass ic = new InnerClass();



   8:         ic.imprimirClaseContenedora();



   9:     }



  10:     



  11:     public class InnerClass{    



  12:         public void imprimirClaseContenedora(){



  13:             System.out.println(a);



  14:         }    



  15:     }



  16:     



  17:     public static void main(String[] args) {



  18:         ClaseContenedora cc = new ClaseContenedora(5);



  19:         cc.imprimirNumero();



  20:     }



  21: }


En el ejemplo se puede apreciar como la clase interna accede directamente al atributo “a” de la clase contenedora, sin necesidad de una referencia a la clase contenedora ni de invocar al método “getA” como se hacía en el ejemplo anterior. Este tipo de Inner class junto con las clases anónimas son las mas utilizadas.

Inner class Locales

Es muy similar al tipo anterior, solo que la clase interna se define dentro del cuerpo de un método de la clase contenedora, y por tanto solo estará disponible para ese método. Esto se aprecia mejor en el siguiente ejemplo:



   1: public class ClaseContenedora {



   2:     private int a;



   3:     



   4:     public ClaseContenedora(int n){ this.a=n; }



   5:     



   6:     public void imprimirNumero(){



   7:         class InnerClass{    



   8:             public void imprimirClaseContenedora(){



   9:                 System.out.println(a);



  10:             }    



  11:         }



  12:         InnerClass ic = new InnerClass();



  13:         ic.imprimirClaseContenedora();



  14:     }



  15:     



  16:     public void imprimirNumero2(){



  17:         //InnerClass ic = new InnerClass();



  18:     }



  19:     



  20:     public static void main(String[] args) {



  21:         ClaseContenedora cc = new ClaseContenedora(5);



  22:         cc.imprimirNumero();



  23:         cc.imprimirNumero2();



  24:     }



  25: }


En este ejemplo en el cuerpo del método “imprimirNumero” se define la Inner Class y por tanto solo se podrá usar en el cuerpo de ese método, ya que fuera de ahí para el compilador no existe esa clase. Si pruebas a descomentar la línea 17 verás como el compilador te da un error, ya que en el cuerpo del método “imprimirNumero2” no se puede acceder a la clase interna.

Inner class Anónimas


Se suelen emplear para el manejo de eventos, aunque el ejemplo que he puesto aquí sigue la línea de los anteriores y no tiene nada que ver con ese tema. Este tipo de clases se llaman así porque se definen sin nombre y se usan como cuerpo de un método, generalmente para ahorrarnos implementar alguna interfaz, tal y como muestra el ejemplo:





   1: public interface Imprimible {



   2:     



   3:     public void Imprimir();



   4:  



   5: }






   1: public class ClaseContenedora {



   2:     private int a;



   3:     



   4:     public ClaseContenedora(int n){ this.a=n; }



   5:     



   6:     public void imprimirNumero(){



   7:         new Imprimible(){



   8:             public void Imprimir(){



   9:                 System.out.println(a);



  10:             }



  11:         }.Imprimir();



  12:     }



  13:     



  14:     public static void main(String[] args) {



  15:         ClaseContenedora cc = new ClaseContenedora(5);



  16:         cc.imprimirNumero();



  17:     }



  18: }




En el ejemplo (aunque reconozco que es un tanto absurdo) hemos conseguido no implementar explícitamente la interfaz Imprimible en la clase contenedora, y esconder la implementación de la interfaz dentro de una clase anónima en el cuerpo del método “imprimirNumero”, sé que ahora esto te parecerá una estupidez, pero cuando veas el manejo de eventos le verás la utilidad.

En conclusión


Las clases internas son una forma de agrupar la lógica de tu programa de forma mas compacta o de esconder al exterior cierta funcionalidad dentro de una clase.


El caso mas evidente en el que se deben usar clases internas es cuando una clase solo le es útil a otra clase, entonces esa clase debe ser una clase interna.

sábado, 27 de febrero de 2010

Recuperar argumentos de la línea de comandos.

Cuando se ejecuta un programa Java desde la línea de comandos:

java miprograma argumento1 argumento2

Puede ser interesante recuperar estos argumentos en nuestra aplicación. Es conveniente saber que los argumentos pasados en la línea de comandos son introducidos dentro de un vector de cadenas (args), lo único que hay que hacer es recorrer dicho vector de cadenas. El primer argumento corresponde al primer elemento del vector y así sucesivamente. El siguiente código recupera los argumentos y los muestra por pantalla:

public class Prueba{
    public void main(String args[]){
        for(int i=0; i<args.length; i++){
            System.out.println(args[0]);
        }
    }
}

Observa que puedes producir el mismo efecto que el típico programa "HolaMundo" de la siguiente forma:


java Prueba Hola Mundo!!!