jueves, 28 de octubre de 2010
Cambio de blog
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
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
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
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
- Ir al menú Formato
- Seleccionar la opción Página
- En la ventana emergente seleccionar la pestaña Pie de página
- Activar/desactivar la casilla correspondiente.
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
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
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
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
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 a 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.
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!!!