menu NoteBooks!

CUADERNO DE JAVA

Lenguaje de programacion de proposito general completamente orientado a objetos. Tiene dos manera de trabajo con el mismo:

  • JSE (Java Standart Edition) incluye el lenguaje de programacion, el runtime y un conjunto de herramientas de desarrollo.
  • JEE (Java Enterprise Edition) biblioteca orientada al desarrollo de aplicaciones empresariales.

INDICE

  1. Introduccion al lenguaje JAVA
  2. POO
  3. Acceso a bases de datos (JDBC)
  4. Disenio de aplicaciones JAVA (1/2)
  5. Interfaces graficas (JavaFX)
  6. Multithreading (hilos)
  7. Networking
  8. Disenio de aplicaciones JAVA (2/2)
  9. Estructuras de datos dinamicas
  10. Parametrizacion mediante XML
  11. Introspeccion de clases y objetos
  12. Generalizaciones y desarrollo de frameworks
  13. Entrada/Salida
  14. Consideraciones finales
  15. ORM y persistencia de datos
  16. Inversion de control por inyeccion de dependencias
  17. Actualizacion a Java 8


1 - Introduccion al lenguaje JAVA

Un hola mundo en java se veria de la siguiente manera:

 package libro.cap1;

 public class HolaMundo{
   public static void Main(String[] args){
   	System.out.printIn("Hola Mundo!");
   }
 }

Ahora vamos a probar a leer datos por teclado.

 package libro.cap1;

 import java.util.Scanner; //Import clase

 public class HolaMundo{
   public static void Main(String[] args){
     //Esta clase permite leer datos por teclado
     Scanner scanner = new Scanner(System.in);
     System.out.print("Introduce su nombre >> ");

    //Leemos valor
    String nombre = scanner.nextLine();
    System.out.println("Te llamas: " + nombre);
  }
 }

Dato: println agrega un salto de linea al final y print normal no

Declaracion de variables

Se hace como en C++, se indica el tipo y luego el identificador. Para leer por teclado se usa scanner.nextInt() se varia int por el tipo de dato y con string se omite.

Admite datos String y boolean.

Estructuras condicionales

En JAVA existen tres tipos de condicionales:

  • Condicional simple: if
  • Condicional compuesto: switch
  • Condicional in-line: (a>b) ? "Caso verdadero": "Caso falso";

Estructuras repetitivas

Son exactamente las mismas de en C++, while, do-while y for.

Definicion de contantes

Las constantes se definen como metodos de una clase con el modificador “final”.

Se recomienda definir constantes siempre en mayusculas.

package libro.cap1;

public class constantes {

  public static final String NOMBRE = "Andres"; //Constante

  public static void main(String[] args){
    //Codigo
  }
}

Arrays

Los arrays son como en C++, son estaticos, es decir, una vez declarado el numero de elementos este no se puede aumentar y tienen tipo unico.
Declaracion: int miArray[] = new int[10];
Si se conocen los elementos que tiene se puede definir asi: int miArray[] = {1,2}

miArray.length devuelve el numero de datos de el array

Matrices

Son como los arrays bidimensionales de C++, se definen primero las filas y luego las columnas.
Sintaxis: int miMatriz [] [] = new int [f] [c];

Tratamiento de Strings

Aqui aprenderemos mas a detalle el manejo de Strings.

  • Acceso a un caracter de la cadena = String.charAt(int posicion);
  • Busca si una cadena contine el caracter desde inicio = String.indexOf("");
  • Busca si una cadena contine el caracter desde fin = String.lastIndexOf("");
  • Obten porciones de una cadena = String.substring(int inicio, int fin);
  • Verificar el inicio de una cadena = String.startWith("");
  • Verificar el final de una cadena = String.endWith("");
  • Concatenar cadenas:
    • Con el operador +
    • Con StringBuffer. Instancio una variable StringBuffer sb = new StringBuffer(); y aniado datos con .append() al final se debe pasar el objeto a cadena con .toString()
  • Conversiones:
    • Integer.toString(int);
    • Integer.parseInt(String);
    • Float.toString(float);
    • Float.parseFloat(String);
  • Particionar Strings:
    • Dividir sin expresiones regulares. Devuelve un array. = String.split("");
    • Con expresiones regulares se usa StringTokenizer. Se define la variable StringTokenizer st = new StringTokenizer(String, "");
  • Comparar cadenas = String.equals(String);

La maquina virtual y JDK

Los programas en JAVA se ejecutan sobre una maquina virtual normalmente llamada JVM (Java Virtual Machine) o JRE (Java Runtime Enviroment). Estos dos permiten ejecutar aplicaciones JAVA.

Si ademas de ejecutarlas como usuario queremos compilarlas y realizar tareas de desarrollo vamos a nacesitar el paquete JDK (Java Development Kit).

2 - POO

Java es un lenguaje fuertemente tipado, esto quiere decir que a todo recurso que se vaya a usar se le tiene que definir un tipo.

En POO tenemos unos conceptos clave:

  • Objetos = son variables cuyo tipo de dato es una clase
  • Clase = estructura que agrupa datos y la manera de trabajar con ellos
  • Atributos = son la variables dentro de la clase, suelen ser private
  • Metodos = son las funciones que permiten trabajar estos datos

Se recomienda como buena practica de Java definir “getters” y “setters” para los atributos a los que queramos que el usuario tenga acceso.

Metodo “toString()”

Este es un metodo de Java que se auto invoca al meter una clase en una salida por consola. El metodo se puede sobreescribir gracias a que Java lo soporta. Es util para elegir la manera en que se visualizan los datos.

Metodo “equals()”

Es un metodo que permite elegir la manera en la que se coparan dos elementos de la misma clase.

Definicion y creacion de objetos

Ejemplo de una clase y una definicion de objeto:

import java.util.Scanner;

public class PC{
  //Atributos
  private int memoriaRAM;
  private int memoriaROM;

  //Constructor
  public PC(int ram, int rom){
    memoriaRAM = ram;
    memoriaROM = rom;
  }

  //Getters
  public int getRAM(){return memoriaRAM;}
  public int getROM(){return memoriaROM;}

  //Setters
  public void setRAM(int ram){memoriaRAM = ram;}
  public void setROM(int rom){memoriaROM = rom;}

  public String toString(){
  	return "RAM = "+memoriaRAM+" ROM = "+memoriaROM;
  }
  public boolean equals(Object o){
    PC obj = (PC)o; //Declaro un objeto tipo PC
    return (memoriaRAM >= obj.memoriaRAM) && (memoriaROM >= obj.memoriaROM);
  }
}

Java tiene soporte para sobrecarga, es decir se pueden definir varios metodos de mismo nombre pero variando argumentos. Los atributos o metodos “static” son comunes a todas las instancias de la clase

Encapsulamiento

Los metodos y atributos en Java pueden ser de cuatro tipos:

  • Se pueden ver dentro de clases heredadas y fuera de clase = public
  • Esta encapsulado y solo se tiene acceso mediante esa clase = privado
  • Solo visible por la cadena de herencia = protected
  • Visible para las clases del mismo paquete = friendly

    El tipo friendly no se define, simplemente al no tener ninguno de los anteriores se declara como friendly

Packages

Los paquetes en Java son una manera de organizar las clases de Java, esto se hace mediante carpetas.
Ejemplo el paquete “java.cap2.fecha” esta hubicado en una carpeta llamada “cap2” y luego la carpeta ‘‘fecha’’.

APIs

Es el conjunto de paquetes (clases y metodos) que tenemos disponibles para crear una aplicacion, estos paquetes se compilan en el formato “.jar”

JavaDoc

Es una utilidad incluida en eclipse que permite documentar un proyecto en java generando de manera automatica archivos HTML. Investigar mas adelante.

Incluir clases de otros paquetes

Para esto hacemos uno del comando import mas la ruta hacia el paquete donde se encuentra la clase que queremos importar.

Herencia

En java todas las clases heredan de la clase padre Object pero aparte de esto podemos definir clases padre e hijo de la siguiente forma:

public class ClaseHijo extends ClasePadre{
  //Codigo de la clase hijo
  
  public ClaseHijo(String a){ //Argumentos que necesita contruct padre
    super(a); //Pasamos los argumentos al constructor padre
  }
}

Java no tiene herencia multiple

En la herencia en Java existen dos palabras importantes:

  • super = hace referencia a la clase padre, es decir, super.saluda() invoca el metodo saluda de la clase padre.
  • this = hace referencia otros metodos y atributos de la misma clase.

Polimorfismo

Pendiente de investigacion.

Clase abstracta

Son clases con metodos que no pueden ser definidos por falta de informacion. Es algo asi como crear un esqueleto de atributos y metodos pero sin definirlos.

public abstract class FigurasGeometricas(){
  public abstract double area(); //No se define
  
  public String toString(){
    return "El area es = "+area(); //Esto es posible
  }
}

// -Otro Archivo-

public class Rectangulo extends FigurasGeometricas(){
  private int base;
  private int altura;
  
  public Rectangulo (int b, int h){
    this.base = b;
    this.altura = h;
  }
  
  //Defino aqui el metodo abstracto
  public double area(){
    return base * altura;
  }
}

Las clases abstractas necesitan ser heredadas por otras para ser instanciadas, es decir, no puedo instanciar la clase “FigurasGeometricas” pero si puedo instanciar la clase “Rectangulo”.

El metodo “finalize”

Es identico al destructor de clases que tiene C++

public void finalize(){
  //Codigo
}

Clases Utilitarias

Tipo de clases con metodos estaticos.
Los metodos estaticos son todos aquellos que se pueden invocar sin la necesidad de crear un objeto de la clase.

public class Operaciones(){
  public static int suma(int a, int b){
    return a + b;
  }
}

Operaciones.suma(4,9);

Clases genericas

Son clases que agrupan objetos y se les puede definir el tipo de objeto con el que van a trabajar. Esto se puede usar en parametros de argumentos y en tipos de metodos.

//Ejemplo tenermos una clase que agrupa elementos
public class miColeccion<T>{ 
  //Codigo
}

//Instancio la clase
miColeccion<String> coleccionCadenas = new miColeccion<String>

Las clases genericas se usan con dos estructuras de datos:

  • PIlas: agrupan elementos uno sobre otro y el ultimo es el que se obtiene al desapilar.
  • Colas: se agrupan uno al final de otro y al eliminar se quitan elementos del principio.

Tienes que desarrollarlos, no existe un estandar.

Interfaces

Son una especie de clases que sirven para implementar en otras clases. Son la solucion ante la falta de herencia multiple en java.

public interface Idioma{
  public void saludo();
}

public class Ingles implements Idioma{
  public void saludo(){
    System.out.println("Hello! :D");
  }
}

El programa anterior define que todos los idiomas tienen una manera de saludar pero no la define, mas tarde el idioma ingles IMPLEMENTA esta interface y define como se saluda en ingles.

Metodo COMPARABLE

Para entender este metodo y las interfaces vamos a hacer un sistema que ordene alumnos por su nombre.

/*
Interfaz Comparable
Este programa define una interfaz generica que tiene un metodo no
definido que compara dos objetos tipo T.
*/
public interface Comparable<T>{
  public int compareTo(T objeto);
}
/*
Clase Alumno
Esta clase implementa la interfaz Comparable y define el tipo de 
objeto a tratar. Despues sobreescribe el metodo "compareTo" y hace 
que devuelva 1 si el primer elemento resulta ganador y dos en caso 
de que sea al reves.
*/
public class Alumno implements Comparable<Alumno> {
  public String nombre;
  private int notaMedia;

  public Alumno(String n, int nm){
    this.nombre = n;
    this.notaMedia = nm;
  }

  public String getNombre(){
    return this.nombre;
  }

  public int compareTo(Alumno objeto){
    if(this.nombre.charAt(0) <= objeto.getNombre().charAt(0)){
      return 1;
    } else {
      return 2;
    }
  }
}
/*
Clase Util
Esta clase contiene el metodo estatico ordenar, este mediante el
algoritmo de burbuja permite ordenar un array de objetos con la 
interface Comparable.
*/
public class Util {
  public static void ordenar (Comparable arr[]){
    boolean ordenado = false; 
    while(!ordenado){
      ordenado = true;
      for(int i = 0; i<arr.length-1; i++){
        if (arr[i+1].compareTo(arr[i]) == 1) {
          Comparable aux = arr[i];
          arr[i] = arr[i+1];
          arr[i+1] = aux;
          ordenado = false;
        }
      }
    }
  }
}

Este algoritmo compara pares de elementos y los intercambia poco a poco. (Buscar en google “algoritmo de la burbuja para un mejor entendimiento”)

/*
Clase Main
Crea un array de 3 alumnos y ordena sus nombres
*/
public class Main {
  public static void main(String[] args){
    Alumno arr[] = {
      new Alumno("Juan", 7),
      new Alumno("Pedro", 3),
      new Alumno("Andres", 7),
    };

    Util.ordenar(arr);
    for(int i = 0; i < arr.length; i++){
      System.out.println(arr[i].getNombre());
    }
  }
}

Colecciones

Llamamos coleccion a un grupo de datos determinado, por ejemplo un String[ ] es un grupo de String.
Para agrupar elementos Java provee la interface Collection. Las clases ArrayList y Vector implementan esta interface.

import java.Util.Vector;

public class TestVector{
  public static void main(String[] args){
    Vector<String> VNombres = new Vector<String>();
    
    VNombres.add("Andres");
    VNombres.add("Pedro");
    VNombres.add("Maria");
    
    String aux;
    
    for(int i = 0; i<VNombres.size(); i++){
      aux = VNombres.get(i);
      System.out.println(aux);
    }
  }
}

No hay que confundir un Array con un Vector, el Array esta definido por defecto por el lenguaje de programacion pero el Vector es algo programable.

Excepciones

Es la manera de manejar los fallos que ocurren mientras la ejecucion del programa.

try{
  //Codigo que puede dar un error
} catch (/*Excepcion especifica sino "Exception e"*/){
  //Codigo si ocurre este error
} catch (){
  //Codigo para otro error.
} finally{
  //Codigo que se ejecuta al final independientente de si falla.
}

3 - Acceso a bases de datos (JDBC)

En este capitulo se vera conceptos basicos sobre bases de datos relacionales y SQL .

Conceptos basicos SQL

Las bases de datos se componen de tablas y cada tabla tiene unos campos definidos.
Ejemplo: nombre ( VARCHAR(15), NOT NULL )

En las tablas puede darse el caso de que un campo este relacionado con otro campo de otra tabla. A esto se le llama relacion foranea.

Para acceder a los datos entro de una BBDD se necesitas unas determinadas instrucciones:

  • Query = SELECT * FROM usuarios
  • Join =
    SELECT u.user, u.pass, t.ntrabajo 
    FROM users u, trabajos t 
    WHERE u.trabajo = t.ntrabajo
    
  • Insert = INSERT INTO users (nombre, pass) VALUES ("Andres", 1235)
  • Update = UPDATE users SET nombre = "Pedro" WHERE nombre = "Andres"
  • Delete = DELETE FROM users WHERE nombre = "Andres"

JDBC

Java ofrece la posibilidad de conectarse con cualquier base de datos (hace falta un driver para java). Esto facilita el cambio entre bases de datos ya que el codigo Java dedicado a DBs sera rehusable en un 90%.
Esta portabilidad es posible gracias a que todas las clases de acceso a DB implementan la misma interface.

/*
* Ejemplo de conexion a DB
*/

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class TestDB (){
  public static void main (String[] args){
    //Variables de conexion
    String usr = "root";
    String pswd = "";
    String driver = "org.hsqldb.jdbcDriver";
    String url = "jdbc:hsqldb:hsql://localhost/xdb";
    
    Connection conexion = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    
    try{
      Class.forName(driver); //Extraigo el driver
      conexion = DriverManager.getConnection(url, usr, pswd);
      
      //Defino el query
      String consulta = "SELECT id, username, password, sexo ";
      consulta += "FROM usuarios";
      
      //Preparo el query
      ps = conexion.prepareStatement(sql);
      
      //Realizo la consulta
      rs = ps.executeQuery();
      
      //Muestro los resultados
      while (rs.next()){
        System.out.println(rs.getInt("id"));
        System.out.println(rs.getString("username"));
        System.out.println(rs.getString("password"));
        System.out.println(rs.getString("sexo"));
      }
    }
    catch(Exception ex){
      ex.printStackTrace();
      throw new RuntimeException(ex);
    }
    finally{
      try{
        //Cierro recursos en orden inverso a su invocacion
        if(rs != null) rs.close();
        if(ps != null) ps.close();
        if(conexion != null) conexion.close();
      }
      catch(Exception ex){
        ex.printStackTrace();
        throw new RuntimeException(ex);
      }
    }
  }
}

Para hacer inserts en JDBC se puede optar por definir los values con ? y luego mas tarde definirlos. (Parametrizacion)

String sql;
sql += "INSERT INTO usuarios (id, username, password, sexo)";
sql += "VALUES(?,?,?,?)";

ps = conexion.prepareStatement(sql);

if(true){
  ps.setInt(1, 25);
  ps.setString(2, "Manolo");
  ps.setString(3, "1111");
  ps.setString(4, "Asexual");
}

/*
* executeUpdate() and executeQuery()
* Se pone update porque cambia algo de la tabla
*/
int affectedRows = ps.executeUpdate();

El valor de “affectedRows” sera el numero de filas que se ven afectadas por el cambio, en este caso es una, haciendo un if podemos ver si se ha hecho todo bien o no.

Patron de disenio: Singleton

Un patron de disenio sugiere una solucion eficiente para resolver un problema. El problema que tenemos en este caso es:

  • No poder mantener una estancia de clase (no mantener la conexion) ```java /*
  • Patron de disenio Singleton
  • Esta solucion consiste en crear una constante de clase “conexion”
  • y un metodo estatico que compruebe su valor y en caso de nulo
  • lo defina. */

public class UConnection{ private static Connection conexion;

public static Connection obtenerConexion(){ if(conexion == null){ conexion = DriverManager.getConnection(url, usr, pswd); } return conexion; } }


#### InnerClasses
Work in Progress

#### Manejo de transacciones
Podemos hacer que la manera de realizar consultas o actualizaciones en la base de datos se asemeje a la manera en que trabaja git. <br>
Esto lo conseguiremos definiendo `conexion.setAutoCommit(false)` tras ejecutarlo dejara de commitear las cosas automaticamente. El mayor uso de esto es con "affectedRows" para que tras comprobar a cuantas filas afecta se de el visto bueno con la instruccion `conexion.commit()` en caso de que afectara a mas o menos filas se puede usar `conexion.rollback()` para cancelar.

#### Acceso a MetaDatos y BatchUpdates
Me lo salto, no lo veo util. (Pag 138 - 139) (Pag 141 - 142)

#### QueryFetchSize
Es una manera de traer muchos datos de la base de datos de golpe y almacenarlos en memoria local para reducir consumo de red. <br>
```java
int n = 100;
pr.setFetchSize(n);

En la primera consulta rs.next() traera “n” resultados y en las demas va de uno en uno desde memoria local.

4 - Disenio de aplicaciones JAVA (1/2)

En el arte del disenio de las aplicaciones tienes que crear productos que sean:

  • Mantenibilidad: es la capacidad de adaptarla a otras variantes
  • Escalabilidad: es si tu aplicacion esta hecha de manera que permite ampliarla.
  • Extensibilidad: si se puede aumentar su utilidad con poco dinero.
  • Otros atributos: disponibilidad, confiabilidad, seguridad…

    En el desarrollo de una aplicacion se define un diagrama UML de casos de uso en el que se definen diferentes maneras de uso de la aplicacion.

Aplicaciones por capas

Al hacer una aplicacion hay que distinguir bien entre dos partes: la logica de negocio (backend) y la logica de presentacion (frontend). Es decir, la parte que muestra datos e interactua con el usuario y la que los procesa y calcula.

Estructura de una aplicacion

  • El usuario solo interactua con el frontend
  • El frontend solo tiene acceso a el Facade que es una clase con funciones sencillas para obtener datos del backend
  • DAO (Data Access Object) = Es un objeto que accede a los datos de la DB. Un DAO por cada tabla
  • DTO (Data Transfer Object) = Un objeto que modela los datos de la DB. Uno por tabla
  • Los nombres de DAOs y DTOs se definen como: nombreTablaDAO y nombreTablaDTO.

    La estructura quedaria: Usuario -> Frontend -> Facade -> Backend Y el orden de desarrollo seria: DAO -> DTO -> Facade -> Frontend (personal)

Portabilidad entre DBs

Aunque JDBC provee de un sistema universal de consutas hay algunas instrucciones que no reconocen ciertas DBs, esto se puede solucionar creando DAOs abstractos y definiendo subclases nombreTablaDAOmiDB que definan estos metodos abstractos.

5 - Interfaces graficas (JavaFX)

La GUI en Java se desarrolla con JavaFX. Un programa con GUI se compone de 3 partes:

  • El archivo FXML: es como la estructura y el estilo de la app (como el html y css)
  • El controlador de FXML: por cada archivo FXML debe haber un controlador que maneje los eventos de la vista
  • Resto de la aplicacion (Backend)

Para ver ejemplos de proyectos en JavaFX:

6 - MultiThreading