miércoles, 13 de junio de 2012

6.4 Manejo de objetos persistentes


Las clases presistentes son clases en una aplicación que implementan las entidades del problema empresarial (por ejemplo, Customer y Order en una aplicación de comercio electrónico). No se considera que todas las instancias de una clase persistente estén en estado persistente. Por ejemplo, una instancia puede ser transitoria o separada.

Hibernate funciona mejor si estas clases siguen algunas reglas simples, también conocidas como el modelo de programación POJO (Plain Old Java Object). Sin embargo, ninguna de estas reglas son requerimientos rígidos. De hecho, Hibernate3 asume muy poco acerca de la naturaleza de sus objetos persistentes. 

EJEMPLO:

import java.util.Set;
import java.util.Date;

public class Cat {
private Long id; // identifier
private Date birthdate;
private Color color;
private char sex;
private float weight;
private int litterId;
private Cat mother;
private Set kittens = new HashSet();
private void setId(Long id) {
this.id=id;
}
public Long getId() {
return id;
}
void setBirthdate(Date date) {
birthdate = date;
}
public Date getBirthdate() {
return birthdate;
}
void setWeight(float weight) {
this.weight = weight;
}
public float getWeight() {
return weight;
}
public Color getColor() {
return color;
}
void setColor(Color color) {
this.color = color;
}
void setSex(char sex) {
this.sex=sex;
}
public char getSex() {
return sex;
}
void setLitterId(int id) {
this.litterId = id;
}
public int getLitterId() {
return litterId;
}
void setMother(Cat mother) {
this.mother = mother;
}
public Cat getMother() {
return mother;
}
void setKittens(Set kittens) {
this.kittens = kittens;
}
public Set getKittens() {
return kittens;
}
public void addKitten(Cat kitten) {
kitten.setMother(this);
kitten.setLitterId( kittens.size() );
kittens.add(kitten);
}
}


Modelos dinámicos
Las entidades persistentes no necesariamente tienen que estar representadas como clases POJO o como objetos JavaBean en tiempo de ejecución. Hibernate también soporta modelos dinámicos (utilizando Mapeos de Mapeos en tiempo de ejecución) y la representación de entidades como árboles de DOM4J. No escriba clases persistentes con este enfoque, sólamente archivos de mapeo.
Los siguientes ejemplos demuestran la representación utilizando Mapeos. Primero, en el archivo de mapeo tiene que declararse un entity-name en lugar de, o además de un nombre de clase:

type="long"
column="ID">

column="NAME"
type="string"/>

column="ADDRESS"
type="string"/>

column="ORGANIZATION_ID"
class="Organization"/>

inverse="true"
lazy="false"
cascade="all">

>
Aunque las asociaciones se declaran utilizando nombres de clase destino, el tipo destino de una asociación puede ser además una entidad dinámica en lugar de un POJO.
Después de establecer el modo de entidad predeterminado como dynamic-map para la SessionFactory, puede trabajar en tiempo de ejecución con Mapeos de Mapeos:

Session s = openSession();
Transaction tx = s.beginTransaction();
// Crea un cliente
Map david = new HashMap();
david.put("name", "David");

// Crea una organizacion
Map foobar = new HashMap();
foobar.put("name", "Foobar Inc.");

// Liga ambos
david.put("organization", foobar);

// Guarda ambos
s.save("Customer", david);
s.save("Organization", foobar);

tx.commit();
s.close();

Una de las ventajas principales de un mapeo dinámico es el rápido tiempo de entrega del prototipado sin la necesidad de implementar clases de entidad. Sin embargo, pierde el chequeo de tipos en tiempo de compilación y muy probablemente tendrá que tratar con muchas excepciones en tiempo de ejecución. Gracias al mapeo de Hibernate, el esquema de base de datos se puede normalizar y volver sólido, permitiendo añadir una implementación apropiada del modelo de dominio más adelante.
Los modos de representación de entidad se pueden establecer por Session:
Session dynamicSession = pojoSession.getSession(EntityMode.MAP);

// Crea un cliente
Map david = new HashMap();
david.put("name", "David");
dynamicSession.save("Customer", david);
...
dynamicSession.flush();
dynamicSession.close()

lunes, 4 de junio de 2012

6.3 Operaciones básicas y tipos de acceso.

Normalmente, cuando se codifica un programa, se hace con la intención de que ese programa pueda interactuar con los usuarios del mismo, es decir, que el usuario pueda pedirle que realice cosas y pueda suministrarle datos con los que se quiere que haga algo. Una vez introducidos los datos y las órdenes, se espera que el programa manipule de alguna forma esos datos para proporcionarnos una respuesta a lo solicitado.
Además, en muchas ocasiones interesa que el programa guarde los datos que se le han introducido, de forma que si el programa termina los datos no se pierdan y puedan ser recuperados en una sesión posterior. La forma más normal de hacer esto es mediante la utilización de ficheros que se guardarán en un dispositivo de memoria no volátil (normalmente un disco).
A todas estas operaciones, que constituyen un flujo de información del programa con el exterior, se les conoce como Entrada/Salida (E/S).

Existen dos tipos de E/S; la E/S estándar que se realiza con el terminal del usuario y la E/S a través de fichero, en la que se trabaja con ficheros de disco.

Todas las operaciones de E/S en Java vienen proporcionadas por el paquete estándar de la API de Java denominado java.io que incorpora interfaces, clases y excepciones para acceder a todo tipo de ficheros. En este tutorial sólo se van a dar algunas pinceladas de la potencia de este paquete.

B. Entrada/Salida estándar.

Aquí sólo trataremos la entrada/salida que se comunica con el usuario a través de la pantalla o de la ventana del terminal.
Si creamos una applet no se utilizarán normalmente estas funciones, ya que su resultado se mostrará en la ventana del terminal y no en la ventana de la applet. La ventana de la applet es una ventana gráfica y para poder realizar una entrada o salida a través de ella será necesario utilizar el AWT.
El acceso a la entrada y salida estándar es controlado por tres objetos que se crean automáticamente al iniciar la aplicación: System.in, System.out y System.err
a.) System.in
Este objeto implementa la entrada estándar (normalmente el teclado). Los métodos que nos proporciona para controlar la entrada son:
• read(): Devuelve el carácter que se ha introducido por el teclado leyéndolo del buffer de entrada y lo elimina del buffer para que en la siguiente lectura sea leído el siguiente carácter. Si no se ha introducido ningún carácter por el teclado devuelve el valor -1.
• skip(n): Ignora los n caracteres siguientes de la entrada.
b.) System.out
Este objeto implementa la salida estándar. Los métodos que nos proporciona para controlar la salida son:
• print(a): Imprime a en la salida, donde a puede ser cualquier tipo básico Java ya que Java hace su conversión automática a cadena.
• println(a): Es idéntico a print(a) salvo que con println() se imprime un salto de línea al final de la impresión de a.
c.) System.err
Este objeto implementa la salida en caso de error. Normalmente esta salida es la pantalla o la ventana del terminal como con System.out, pero puede ser interesante redirigirlo, por ejemplo hacia un fichero, para diferenciar claramente ambos tipos de salidas.
Las funciones que ofrece este objeto son idénticas a las proporcionadas por System.out.
d.) Ejemplo
A continuación vemos un ejemplo del uso de estas funciones que acepta texto hasta que se pulsa el retorno de carro e informa del número de caracteres introducidos.

import java.io.*;
class CuentaCaracteres {
  public static void main(String args[]) throws IOException {
    int contador=0;
    while(System.in.read()!='\n')
      contador++;
    System.out.println(); // Retorno de carro "gratuito"
    System.out.println("Tecleados "+contador+" caracteres.");
  }
}




C. Entrada/Salida por fichero.


a.) Tipos de ficheros
En Java es posible utilizar dos tipos de ficheros (de texto o binarios) y dos tipos de acceso a los ficheros (secuencial o aleatorio).
Los ficheros de texto están compuestos de caracteres legibles, mientras que los binarios pueden almacenar cualquier tipo de datos (int, float, boolean,...).
Una lectura secuencial implica tener que acceder a un elemento antes de acceder al siguiente, es decir, de una manera lineal (sin saltos). Sin embargo los ficheros de acceso aleatorio permiten acceder a sus datos de una forma aleatoria, esto es indicando una determinada posición desde la que leer/escribir.
b.) Clases a estudiar
En el paquete java.io existen varias clases de las cuales podemos crear instancias de clases para tratar todo tipo de ficheros.
En este tutorial sólo vamos a trata las tres principales:
• FileOutputStream: Fichero de salida de texto. Representa ficheros de texto para escritura a los que se accede de forma secuencial.
• FileInputStream: Fichero de entrada de texto. Representa ficheros de texto de sólo lectura a los que se accede de forma secuencial.
• RandomAccessFile: Fichero de entrada o salida binario con acceso aleatorio. Es la base para crear los objetos de tipo fichero de acceso aleatorio. Estos ficheros permiten multitud de operaciones; saltar hacia delante y hacia atrás para leer la información que necesitemos en cada momento, e incluso leer o escribir partes del fichero sin necesidad de cerrarlo y volverlo a abrir en un modo distinto.
c.) Generalidades
Para tratar con un fichero siempre hay que actuar de la misma manera:
1. Se abre el fichero.
Para ello hay que crear un objeto de la clase correspondiente al tipo de fichero que vamos a manejar, y el tipo de acceso que vamos a utilizar:
TipoDeFichero obj = new TipoDeFichero( ruta );
Donde ruta es la ruta de disco en que se encuentra el fichero o un descriptor de fichero válido.
Este formato es válido, excepto para los objetos de la clase RandomAccessFile (acceso aleatorio), para los que se ha de instanciar de la siguiente forma:
RandomAccessFile obj = new RandomAccessFile( ruta, modo );
Donde modo es una cadena de texto que indica el modo en que se desea abrir el fichero; "r" para sólo lectura o "rw" para lectura y escritura.
2. Se utiliza el fichero.
Para ello cada clase presenta diferentes métodos de acceso para escribir o leer en el fichero.
3. Gestión de excepciones (opcional, pero recomendada)
Se puede observar que todos los métodos que utilicen clases de este paquete deben tener en su definición una cláusula throws IOException. Los métodos de estas clases pueden lanzar excepciones de esta clase (o sus hijas) en el transcurso de su ejecución, y dichas excepciones deben de ser capturadas y debidamente gestionadas para evitar problemas.
4. Se cierra el fichero y se destruye el objeto.
Para cerrar un fichero lo que hay que hacer es destruir el objeto. Esto se puede realizar de dos formas, dejando que sea el recolector de basura de Java el que lo destruya cuando no lo necesite (no se recomienda) o destruyendo el objeto explícitamente mediante el uso del procedimiento close() del objeto:
obj.close()
d.) La clase FileOutputStream
Mediante los objetos de esta clase escribimos en ficheros de texto de forma secuencial.
Presenta el método write() para la escritura en el fichero. Presenta varios formatos:
• int write( int c ): Escribe el carácter en el fichero.
• int write( byte a[] ): Escribe el contenido del vector en el fichero.
• int write( byte a[], int off, int len ): Escribe len caracteres del vector a en el fichero, comenzando desde la posición off.
El siguiente ejemplo crea el fichero de texto "/carta.txt" a partir de un texto que se le introduce por teclado:

import java.io.*;
class CreaCarta {
  public static void main(String args[]) throws IOException{
    int c;
    FileOutputStream f=new FileOutputStream("/carta.txt");
    while( ( c=System.in.read() ) != -1 )
      f.write( (char)c );
    f.close();
  }
}

6.2 Clasificación: Archivos de texto y binarios.

Definición de archivos de texto y binarios.

Los archivos de texto plano son aquellos que están compuestos únicamente por texto sin formato, solo caracteres. estos caracteres se pueden codificar de distintos modos dependiendo de la lengua usada. Se les conoce también como archivos de texto llano o texto simple por carecer de información destinada a generar formatos y tipos de letra.

Un archivo binario es una archivo informático que contiene información de cualquier tipo, codificada en forma binaria para el propósito de almacenamiento y procesamiento de ordenadores.

Muchos formatos binarios contienen partes que pueden ser interpretados como texto. Un archivo binario que solo contiene información de tipo textual sin información sobre el formato del mismo, se dice que es un archivo de texto plano. Habitualmente se contraponen los términos archivo binario y archivo de texto de forma que los primeros no contienen solamente texto.



EJEMPLO:

clase 1.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class Demostracionfile extends JFrame{
    private JTextArea areaSalida;
    private JScrollPane panelDespl;

    //constructor de la interfaz
    public Demostracionfile(){
            super("Ejemplo de archivos");

            areaSalida= new JTextArea();
            panelDespl=new JScrollPane(areaSalida);
            add(panelDespl,BorderLayout.CENTER);
          setSize(400,400); //establece el tamaño de la interfaz
            setVisible(true);//muestra la interfaz GUI8

            analizarRuta(); //crear y analizar un objeto File
    } // fin del contructor

    private File obtenerArchivo(){
    JFileChooser selectorArchivos=new JFileChooser();
    selectorArchivos.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
    int resultado = selectorArchivos.showOpenDialog(this);

    if(resultado == JFileChooser.CANCEL_OPTION)
        System.exit(1);
    File nombreArchivo = selectorArchivos.getSelectedFile(); //obtiene el nombre del archivo

    if ((nombreArchivo==null)||(nombreArchivo.getName().equals(""))) {
        JOptionPane.showMessageDialog(this, "nombre del archivo invalido","nombre del archivo invalido", JOptionPane.ERROR_MESSAGE );
        System.exit(1);
    }//fin del IF
    return nombreArchivo;
    }
    //yet..another class
    public void analizarRuta(){
    File nombre = obtenerArchivo();
    if (nombre.exists())
    {
        areaSalida.setText(String.format("%s%s\n%s\n%s\n%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s",nombre.getName(),"existe",
                (nombre.isFile()?"es un archivo":"no es un archivo"),
                (nombre.isDirectory() ? "no es directorio":"no es directorio"),
                (nombre.isAbsolute() ? "es una ruta absoluta":"no es un a ruta absoluta"),
                "ultima modifecacion: ",nombre.lastModified(), "tamaño: ",nombre.length(),
                "Ruta: ",nombre.getPath(), "Ruta absoluta: ",
                nombre.getAbsolutePath(),"Padre: ",nombre.getParent() ));
        if(nombre.isDirectory())//imprime el listado del directorio
        {
            String directorio[] = nombre.list();
            areaSalida.append("\n\nContenido del directorio: \n");

            for(String nombreDirectorio:directorio)
                areaSalida.append(nombreDirectorio+"\n");
        }

    }

    else
    {
        JOptionPane.showMessageDialog(this, nombre + "no existe", "ERROR",JOptionPane.ERROR_MESSAGE);

        }
    }


    }
clase 2.

 import javax.swing.JFrame;
public class pruebademostracionfile {
    public static void main(String args[]){
    Demostracionfile aplicacion = new Demostracionfile();
    aplicacion.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

}

6 Flujos y Archivos.

6.1 Definición.

Archivos.

 Los archivos tienen como finalidad guardar datos de forma permanente.Una vez que acaba la aplicación los datos almacenados están disponibles para que otra aplicación pueda recuperarlos para su consulta o modificación.

 


 La organización de un archivo define la forma en la en que se estructuran u organizan los datos. Formas de organización fundamentales:

Secuenciales: los registros se insertan en el archivo en orden de llagada. Las operaciones básicas permitidas son: escribir, añadir al final del archivo y consultar .

Directa o aleatoria:cuando un registro es directamente accesible mediante la especificación de un índice.

Flujos (Streams)

Es una abstracción, que representa a un flujo de datos entre un origen y un destino en Java. Todo proceso de entrada y salida en Java se hace a través de flujos


Entre el origen y el destino debe existir un canal , por el que viajan datos. Cuando se abre un archivo se establece una conexión entre el programa y el dispositivo que contiene ese archivo , por el canal fluirá la secuencia de datos.  Igual ocurre al intentar escribir en un archivo. 


Para obtener información de una fuente un programa abre un stream y lee la información secuencialmente.


De igual forma, un programa puede enviar información  a un destino externo abriendo un stream al destino y escribiendo la información secuencialmente.




No importa el tipo de datos ni de donde proviene ni a donde se dirige, los algoritmos para la lectura y escritura de datos son escencialmente los mismos.

sábado, 26 de mayo de 2012

5.5 Creación y manejo de excepciones definidas por el usuario.

Las excepciones predefinidas cubren las situaciones de error más habituales con las que nos podemos encontrar, relacionadas con el propio lenguaje y el hardware. Cuando se desarrollan aplicaciones existen otras situaciones de error de más ‘alto nivel’ relacionadas con la funcionalidad de nuestros programas. Imaginemos una aplicación informática que controla la utilización de los remontes de
una estación de esquí: los pases de acceso a los remontes son personales e intransferibles y dispondrán de un código de barras que los identifica. Cada vez que un usuario va a hacer uso de un remonte debe introducir su pase de acceso en una máquina de validación, que a cciona un torno y devuelve el pase.

 El sistema puede constar de un ordenador central al que le llegan telemáticamente los datos  correspondientes a los códigos de barras de los pases que en cada momento se están introduciendo en cada máquina de validación d e cada remonte; si un código de barras está en regla, el ordenador envía una orden de liberar el torno para permitir al usuario acceder al remonte. El ordenador central habitualmente recibirá códigos correctos utilizados en momentos adecuados, sin embargo, en ciertas ocasiones nos encontraremos con situaciones anómalas:

1 Código de barras ilegible

2 Código de barras no válido (por ejemplo correspondiente a un pase caducado)

3 Código de barras utilizado en otro remonte en un periodo de tiempo demasiado breve

4 etc.

DEFINICIÓN DE UNA EXCEPCIÓN DEFINIDA POR EL PROGRAMADOR.

En programación orientada a objetos lo más adecuado es que las excepciones sean objetos, por lo que en Java definiremos las excepciones como clases. Nuestras clases de excepción, en general, heredarán de la clase Exception. En las clases que nos creemos a partir de Exception, incluiremos al menos el constructor vacío y otro que contenga un String como argumento. Este String se inicializa automáticamente con el nombre de la clase; la inicialización se realiza en la superclase Throwable. El texto que pongamos al hacer uso del segundo constructor se añadirá al nombre de la clase insertado por la superclase.

UTILIZACIÓN DE UNA EXCEPCIÓN DEFINIDA POR EL PROGRAMADOR.

Una vez que disponemos de una excepción propia, podremos programar la funcionalidad de nuestras aplicaciones provocando (lanzando) la excepción cuando detectemos alguna de las situaciones anómalas asociadas.


Ejemplo:

//Demostracion del mecanismo de manejo de excepciones
//try...catch...finally

public class UsoDeExcepciones {
public static void main(String args[]){
try{
lanzaExcepcion();//llama al metodo lanzaExcepcion
}//fin de try
catch(Exception excepcion){ //excepcion lanzada por lanzaExcepcion
System.err.println("La excepcion se manejo en main ");
}//fin de catch
noLanzaExcepcion();
}//fin de main
//demuestra los bloques try...catch...finally

public static void lanzaExcepcion() throws Exception{
try{//lanza una excepcion y la atrapa de inmediato
System.out.println("Metodo lanzaExcepcion");
throw new Exception();//genera la excepcion
}//fin de try

catch (Exception excepcion){ //atrapa la excepcion lanzada en el bloque try
System.err.println("La excepcion se manejo en el metodo lanzaExcepcion ");
throw excepcion;//vuelve a lanzar para procesarla mas adelante
//no se llegaria al codigo que se coloque aqui, la excepcion se vuelve a lanzar en el bloque catch
}//fin catch
finally{//se ejecuta sin importar lo que ocurra en los bloques try..catch
System.err.println("Se ejecuto finally en lanzaExcepcion ");
}//din de finally
//no se llega al codigo que se coloque aqui, la excepcion se vuelve a lanzar en el bloque catch
}//fin del metodo lanzaException

//demuestra el uso de finally cuando no ocurre una excepcion
public static void noLanzaExcepcion(){
try{//el bloque try no lanza una excepcion
System.out.println("Metodo noLanzaExcepcion");
}//fin de try

catch(Exception excepcion){//no se ejecuta
System.err.println(excepcion);
}//fin de catch

finally{//se ejecuta sin importar lo que ocurra en los bloques try..catch
System.err.println("Se ejecuto Finally en noLanzaExcepcion");
}//fin de bloque finally

System.out.println("Fin del metodo noLanzaExcepcion");
}//fin del metodo noLanzaExcepcion

}//fin de la clase UsoDeExcepciones

5.4 Gestión de excepciones: manejo de excepciones, lanzamiento de excepciones.

Lanzamiento de excepciones: throw - throws

Muchas veces el programador dentro de un determinado método deberá comprobar si alguna condición de excepción se cumple, y si es así lanzarla. Para ello se utilizan las palabras reservadas throw y throws.
Por una parte la excepción se lanza mediante la sentencia throw:

if ( condicion_de_excepcion == true )
throw new miExcepcion
();

Se puede observar que hemos creado un objeto de la clase miExcepcion, puesto que las excepciones son objetos y por tanto deberán ser instanciadas antes de ser lanzadas.

Aquellos métodos que pueden lanzar excepciones, deben cuáles son esas excepciones en su declaración. Para ello se utiliza la sentencia throws:

tipo_devuelto miMetodoLanzador() throws miExcep1, miExcep2 {
// Codigo capaz de lanzar excepciones miExcep1 y miExcep2
}

Se puede observar que cuando se pueden lanzar en el método más de una excepción se
deben indicar en sus declaraciones separadas por comas.

Ejemplo:

Clase base
class Excepciones {

public static void main( String[] args ) {
// Para leer un fichero
FileInputStream entrada = null;

Lanzadora lanza = new Lanzadora();
int leo;

try {
entrada = new FileInputStream("fich.txt");
while ( ( leo = entrada.read() ) != -1 )
lanza.lanzaSiNegativo( leo );
System.out.println( "Todo fue bien" );
} catch ( MiExcepcion e ){ // Personalizada
System.out.println( "Excepcion: " + e.getMessage() );
} catch ( IOException e ){ // Estándar
System.out.println( "Excepcion: " + e.getMessage() );
} finally {
entrada.close(); // Así el fichero siempre queda cerrado
System.out.println( "Fichero cerrado" );
}
}
}

Clase derivada

class MiExcepcion extends Exception {
MiExcepcion(){
super(); // constructor por defecto de Exception
}
MiExcepcion( String cadena ){
super( cadena ); // constructor param. de Exception
}
}
// Esta clase lanzará la excepción
class Lanzadora {
void lanzaSiNegativo( int param ) throws MiExcepcion {
if ( param < 0 )
throw new MiExcepcion( "Numero negativo" );
}
}
class Excepciones {
public static void main( String[] args ) {
// Para leer un fichero
Lanzadora lanza = new Lanzadora();
FileInputStream entrada = null;
int leo;

try {
entrada = new FileInputStream( "fich.txt" );
while ( ( leo = entrada.read() ) != -1 )
lanza.lanzaSiNegativo( leo );
entrada.close();
System.out.println( "Todo fue bien" );
} catch ( MiExcepcion e ){ // Personalizada
System.out.println( "Excepcion: " + e.getMessage() );
} catch ( IOException e ){ // Estándar
System.out.println( "Excepcion: " + e.getMessage() );
} finally {
if ( entrada != null )

try {
entrada.close(); // Siempre queda cerrado
} catch ( Exception e ) {
System.out.println( "Excepcion: " + e.getMessage() );
}
System.out.println( "Fichero cerrado." );
}
}
}

5.3 Propagación De Excepciones.

Las instrucciones que tenemos dentro de un bloque try a menudo contienen llamadas a métodos que a su vez pueden realizar llamadas a otros métodos y así sucesivamente. Cualquiera de los métodos llamados puede provocar una excepción y cualquiera de los  métodos puede, o no, tratarla (con bloques catch). Ó Una excepción no tratada en un bloque se propaga hacia el bloque llamante. Este mecanismo de propagación continúa mientras no se trate la excepción o se llegue al método de nivel superior. Si la excepción no se trata en el método de nivel superior, se imprime un mensaje de error por consola.

Ejemplo:

try {
// codigo
Origen.CopiaFichero(Destino);
// codigo
}
catch (IOException e) {
System.out.println (“Error de lectura ¿Desea intentarlo de Nuevo?”);
..........
}
public void CopiaFichero (TipoFichero Destino) {
try {
// codigo
12
}
catch (IOException e) {
// cerrar ficheros, etc.
throw e;
}

5.2 Tipos de excepciones.

Existen varios tipos fundamentales de excepciones:

Error: Excepciones que indican problemas muy graves, que suelen ser no recuperables y no deben casi nunca ser capturadas.

Exception: Excepciones no definitivas, pero que se detectan fuera del tiempo de ejecución.

RuntimeException: Excepciones que se dan durante la ejecución del programa. 



.
Todas las excepciones tienen como clase base la clase Throwable, que está incluida en el paquete java.lang, y sus métodos son:

Trowable( String mensaje ); Constructor. La cadena es opcional

Throwable fillInStackTrace(); Llena la pila de traza de ejecución.

String getLocalizedMessage(); Crea una descripción local de este objeto.

String getMessage(); Devuelve la cadena de error del objeto.

void printStackTrace( PrintStream_o_PrintWriter s ); Imprime este objeto y su traza en el flujo del parámetro s, o en la salida estándar (por defecto).

String toString; Devuelve una breve descripción del objeto.


La superclase de todas las excepciones es la clase Throwable. Sólo las instancias de esta clase o alguna de sus subclases pueden ser utilizadas como excepciones. La clase Trowable tiene dos clases derivadas: Error y Exception.
La clase Exception sirve como superclase para crear excepciones de propósito específico (adaptadas a nuestras necesidades).

La clase Error sirve de superclase para una serie de clases derivadas ya definidas que nos informan de situaciones anormales relacionadas con errores de muy difícil recuperación producidos en el sistema.

La clase Exception tiene un amplio número de clases derivadas proporcionadas por el SDK, por ejemplo existen excepciones predefinidas para el uso de ficheros, de SQL, etc. De todas estas subclases, RuntimeExeption tiene una característica propia: no es necesario realizar un tratamiento explícito de estas excepciones (de todas las demás clases derivadas de Exception si es necesario). Esto es debido a que, al igual que con las excepciones derivadas de Error, existen pocas posibilidades de recuperar situaciones .

Entre las clases derivadas de RuntimeException se encuentran: anómalas de este tipo.


El siguiente gráfico muestra las clases más importantes en el uso de excepciones y su jerarquía . En las clases no sombreadas es obligatorio realizar un tratamiento explícito de las excepciones, en las clases sombreadas no es necesario este tratamiento


5.1 Definición.

En todo programa existen errores inesperados en tiempo de ejecución, y también errores que no consideramos debido a nuestra propia inexperiencia como programadores. Unos de estos errores ocurren por ejemplo, al intentar acceder a un elemento del arreglo que está fuera del límite de nuestro arreglo, o cuando intentamos acceder a un archivo inexistente, entre otros.

 Normalmente estos errores interrumpen el flujo de ejecución de nuestros programas, hasta el extremo de provocar la terminación del programa en forma inmediata. Java hace uso de las excepciones1.1 para poder controlar los errores en tiempo de ejecución. En Java, casi todo los tipos de errores que puedan surgir en tiempo de ejecución lanzan excepciones, es decir, cuando ocurre un error dentro de un método de JAva, este método crea un objeto Exception, dicho objeto contiene información sobre la excepción, que incluye su tipo y el estado del programa cuando ocurrió el error. El sistema de ejecución es el responsable de buscar algún código para manejar el error. El manejo de excepciones en Java sigue una estructura como esta:

try {
//Codigo donde puede ocurrir un error
}
catch (ExcepcionA ex) { // Que se va a hacer en caso que
se lanze una Excepcion A }
...
catch (ExcepcionZ ex) { // Que se va a hacer en caso que
se lanze una Excepcion Z }

Mediante las excepciones se podrá evitar repetir continuamente código, en busca de un posible error, y avisar a otros objetos de una condición anormal de ejecución durante un programa.

Las excepciones señalan errores o situaciones poco habituales en la ejecución de un programa, por ejemplo una división de un valor entre cero, un intento de acceso a un String declarado, pero no instanciado, etc.

Ejemplo :

import java.util.Scanner;
import java.util.InputMismatchException;
public class usodeExcepciones {
    public static int cociente (int numerador, int denominador) throws ArithmeticException{
        return numerador/denominador;
    }
    public static void main(String[] args) {
        Scanner explorador = new Scanner(System.in);
        boolean continuarCiclo=true;
   do{
   try{
       System.out.print("Introduce un numero entero= ");
       int numerador = explorador.nextInt();
       System.out.print("Introduce un denominador entero= ");
       int denominador = explorador.nextInt();
       int resultado = cociente (numerador, denominador);
       System.out.printf("Resultado de %d / %d = %d", numerador, denominador, resultado);
       System.out.println();
       continuarCiclo=false;
       //fin del bloque try
   }
   catch(InputMismatchException objError){
       System.err.printf("Exception: %s\n", objError);
       explorador.nextLine();
       System.out.println("Debe de introducir valores enteros. Intente de nuevo");
   }
   catch(ArithmeticException objaritmetico){
       System.out.printf("Exception: %s\n", objaritmetico);
       System.out.println("Cero es un denominador invalido. Intente de nuevo");
   }
   }while (continuarCiclo=true);
         }
}

5 Excepciones.

El término excepción es un forma corta da la frase “suceso excepcional” y puede definirse de la siguiente forma.

Definición:

Una excepción es un evento que ocurre durante la ejecución del programa que interrumpe el flujo normal de las sentencias.
Muchas clases de errores pueden utilizar excepciones — desde serios problemas de hardware, como la avería de un disco duro, a los simples errores de programación, como tratar de acceder a un elemento de un array fuera de sus límites. Cuando dicho error ocurre dentro de un método Java, el método crea un objeto ‘exception’ y lo maneja fuera, en el sistema de ejecución. Este objeto contiene información sobre la excepción, incluyendo su tipo y el estado del programa cuando ocurrió el error. El sistema de ejecución es el responsable de buscar algún código para manejar el error. En terminología java, crear una objeto exception y manejarlo por el sistema de ejecución se llama lanzar una excepción.

Algunas excepciones mas comunes


4.5 Reutilización de código.

Lo primero que se les viene a la cabeza a los estudiantes (y a muchos profesionales) cuando se les menciona la reutilización del código es el famoso copiar y pegar al que se han acostumbrado en la programación estructurada, y de echo muchos lo hacen en poo, lo cual es una de las practicas que más encarece el desarrollo de software. Como todo en Java, el problema se resuelve con las clases. Para reutilizar el código creamos nuevas clases pero, en lugar de partir de cero, partimos de clases, relacionadas con nuestra clase, que han sido ya creadas y depuradas. El truco está en usar las clases sin ensuciar el código existente.

Una forma de hacer esto es crear objetos de nuestras clases existentes dentro de la nueva clase. Esto se conoce como composición porque la nueva clase está compuesta de objetos de clases existentes. Estamos reutilizando la funcionalidad del código, y no la forma.
Otra forma es crear una nueva clase como un tipo de una clase ya existente. Tomamos la forma de la clase existente y añadimos código a la nueva, sin modificar la clase existente. Esta forma de crear nuevos objetos se llamada herencia, y lo que hacemos es extender la clase en la que nos basamos para crear la nueva.


Composición:

Hasta ahora hemos usado la composición de cierta manera, ej. cuando hacemos una interfaz gráfica de usuario, nuestra clase de interfaz gráfica esta compuesta por un frame, unos panel, botones, etc. todos estos objetos componen el objeto de interfaz gráfica. Es decir que la composición consiste en poner manejadores de objetos dentro de nuestra clase, estos manejadores de objetos no serán otra cosa que instancias de las clases en las que nos estamos basando para crear la nueva clase.

4.4 Variables polimórficas (plantillas): definición, uso y aplicaciones.

En Java, las variables que contienen objetos son variables polimórficas. El término «polimórfico»  (literalmente: muchas formas) se refiere al hecho de que una misma variable puede contener objetos de diferentes tipos (del tipo declarado o de cualquier subtipo del tipo declarado). El polimorfismo aparece en los lenguajes orientados a objetos en numerosos contextos, las variables polimórficas constituyen justamente un primer ejemplo.

Observemos la manera en que el uso de una variable polimórfica nos ayuda a simplificar nuestro método listar. El cuerpo de este método es:

for (Elemento elemento : elementos)
elemento.imprimir();
En este método recorremos la lista de elementos (contenida en un ArrayList mediante la variable elementos), tomamos cada elemento de la lista y luego invocamos su método imprimir.El uso de herencia en este ejemplo ha eliminado la necesidad de escribir dos ciclos en el método listar. La herencia evita la duplicación de código no sólo en las clases servidoras sino también en las clases clientes de aquellas.

public class CD
{
private String title;
private String artist;
private String comment;
CD(String theTitle, String theArtist)
{
title = theTitle;
artist = theArtist;
comment = " ";
}
void setComment(String newComment)
{ ... }
String getComment()
{ ... }
void print()
{ ... }
...
}


public class DVD
{
private String title;
private String director;
private String comment;
DVD(String theTitle, String theDirector)
{
title = theTitle;
director = theDirector;
comment = " ";
}
void setComment(String newComment)
{ ... }
String getComment()
{ ... }
void print()
{ ... }
...
}

class Database {
private ArrayList<CD> cds;
private ArrayList<DVD> dvds;
...
public void list()
{
for(CD cd : cds) {
cd.print();
System.out.println();  }
for(DVD dvd : dvds) {
dvd.print();
System.out.println();  }
}
}

4.3 Interfaces: definición, implementación de interfaces, herencia de interfaces.

El concepto de Interface lleva un paso más adelante la idea de las clases abstractas. En Java una interface es una clase abstracta pura, es dcir una clase donde todos los métodos son abstractos (no se implementa ninguno).

Permite al diseñador de clases establecer la forma de una clase (nombres de métodos, listas de argumentos y tipos de retorno, pero no bloques de código). Una interface puede también contener datos miembro, pero estos son siempre static y final. Una interface sirve para establecer un 'protocolo' entre clases. Para crear una interface, se utiliza la palabra clave interface en lugar de class. La interface puede definirse public o sin modificador de acceso, y tiene el mismo significado que para las clases. Todos los métodos que declara una interface son siempre public. Para indicar que una clase implementa los métodos de una interface se utiliza la palabra clave implements. El compilador se encargará de verificar que la clase efectivamente declare e implemente todos los métodos de la interface.

Una clase puede implementar más de una interface. Declaración y uso Una interface se declara:

interface nombre_interface {
tipo_retorno nombre_metodo ( lista_argumentos ) ;
. . .
}

Por ejemplo:

interface InstrumentoMusical {
void tocar();
void afinar();
String tipoInstrumento();
}

Y una clase que implementa la interface:

class InstrumentoViento extends Object implements
InstrumentoMusical {
void tocar() { . . . };
void afinar() { . . .};
String tipoInstrumento() {}
}

class Guitarra extends InstrumentoViento {
String tipoInstrumento() {
return "Guitarra";
}
}


Referencias a Interfaces

Es posible crear referencias a interfaces, pero las interfaces no pueden ser instanciadas. Una referencia a una interface puede ser asignada a cualquier objeto que implemente la interface.

Extensión de interfaces
Las interfaces pueden extender otras interfaces y, a diferencia de las clases, una interface puede extender más de una interface. La sintaxis es:

interface nombre_interface extends nombre_interface , . . . {
tipo_retorno nombre_metodo ( lista_argumentos ) ;
. . .
}

Agrupaciones de constantes

Dado que, por definición, todos los datos miembros que se definen en una interface son static y final, y dado que las interfaces no pueden instanciarse resultan una buena herramienta para implantar grupos de constantes.

public interface Meses {
int ENERO = 1 , FEBRERO = 2 . . . ;
String [] NOMBRES_MESES = { " " , "Enero" , "Febrero" , . . . };
}

Esto puede usarse simplemente:

System.out.println(Meses.NOMBRES_MESES[ENERO]);

4.2 Clases abstractas: definición, métodos abstractos, implementación de clases abstractas, modelado de clases abstractas.

Las clases abstractas en Java


Una de las características más útiles de cualquier lenguaje orientado a objetos es la posibilidad de declarar clases que definen como se utiliza solamente, sin tener que implementar método. Esto en Java se hace mediante interfaces y con clases abstractas.

Una clase abstracta es una clase de la que no se puede crear objetos. La utilidad de estas clases estriba en que otras clases hereden de ésta, por lo que con ello conseguiremos reutilizar código. Para declarar una clase como abstracta utilizamos la palabra clave abstract.

En método abstract no pude ser static, ya que estos no pueden ser redifinidos por las subclases.

Clases abstractas


Una clase que declara la existencia de métodos pero no la implementación de dichos métodos (o sea, las llaves { } y las sentencias entre ellas), se considera una clase abstracta.

Una clase abstracta puede contener métodos no-abstractos pero al menos uno de los métodos debe ser declarado abstracto.

Para declarar una clase o un metodo como abstractos, se utiliza la palabra
reservada abstract.

abstract class ejemplo

{
abstract void miMetodo(int var1, int var2);
String miOtroMetodo( ){ ... }
}

Una clase abstracta no se puede instanciar pero si se puede heredar y las clases hijas serán las encargadas de agregar la funcionalidad a los métodos abstractos. Si no lo hacen así, las clases hijas deben ser también abstractas.

4.1 Definición.

Conceptos sobre polimorfismo y programación orientada a objetos

El polimorfismo, en programación orientada a objetos, se refiere a la posibilidad de acceder a un variado rango de funciones distintas a través del mismo interfaz. O sea, un mismo identificador puede tener distintas formas (distintos cuerpos de función, distintos comportamientos) dependiendo del contexto en el que se halle. El polimorfismo se puede establecer mediante sobrecarga, sobreescritura y enlace dinámico.

Sobrecarga

Este término se refiere al uso del mismo identificador u operador en distintos contextos y con distintos significados. Si para cada funcionalidad necesitada fuese necesario escribir un método, el código resultante sería inmanejable. Supongamos que los desarrolladores de Java hubiesen creado un método para escribir en pantalla una cadena de texto, otro diferente para escribir un entero, otro para un doble, y así para todas las combinaciones posibles, sería casi imposible conocer dichos métodos en totalidad. En cambio, con “System.out.print()” o “System.out.println()” podemos escribir cualquier mensaje en pantalla.

Este tipo de codificación nos es permitido gracias a la sobrecarga, la cual se aplica a métodos y constructores.

La sobrecarga de métodos hace que un mismo nombre pueda representar distintos métodos con distinto tipo y número de parámetros, manejados dentro de la misma clase. En el ámbito de la POO, la sobrecarga de métodos se refiere a la posibilidad de tener dos o más métodos con el mismo nombre pero distinta funcionalidad. Es decir, dos o más métodos con el mismo nombre realizan acciones diferentes y el compilador usará una u otra dependiendo de los parámetros usados. Esto también se aplica a los constructores (de hecho, es la aplicación más habitual de la sobrecarga).

Sobreescritura

La sobreescritura se aplica a los métodos y está directamente relacionada a la herencia; se refiere a la redefinición de los métodos de la clase base en las subclases.

Enlace dinámico

Esto permite invocar operaciones en objetos obviando el tipo actual de éstos hasta el momento de ejecutar el código. O sea, nos permite definir elementos como un tipo e instanciarlos como un tipo heredado.







4 Polimorfismo.

El concepto de Polimorfismo es uno de los fundamentos para cualquier lenguaje orientado a Objetos, las mismas raíces de la palabra pueden ser una fuerte pista de su significado: Poli = Multiple, morfismo= Formas , esto implica que un mismo Objeto puede tomar diversas formas.
A través del concepto de Herencias ("Inheritance") es posible ilustrar este comportamiento:


El poder manipular un Objeto como si éste fuera de un tipo genérico otorga mayor flexibilidad al momento de programar con Objetos, el término Polimorfismo también es asociado con un concepto llamado Late-Binding (Ligamiento Tardío), observe el siguiente fragmento de código:

       Figura a = new Circulo();
     Figura b = new Triangulo();

Inicialmente se puede pensar que este código generaría un error debido a que el tipo de referencia es distinta a la instancia del objeto, sin embargo, el fragmento anterior es correcto y demuestra el concepto de Polimorfismo.