Está en la página 1de 79

Programación III

Clases en C++ y Java - Curso 2015-2016

Depto. de Informática y Automática


Grado en Ingeniería Informática
1 Dr. J.R. García-Bermejo Giner
Contenidos
¿Cómo es un programa en Java?
Declaración de atributos en Java
Declaración de métodos en Java
Cuerpos de los métodos en Java
Ctores en Java
Orden de ejecución de ctores
Métodos de acceso en Java
Excepciones en Java

2
• El programa más sencillo posible es una
clase con un método main(), dentro del
cual se encuentra todo el código. Esto es
como un programa en C o C++ que solo
tuviera la función main() metida en una
clase

3
• Normalmente los programas constan de
varias clases, y se utiliza como programa
principal el método main() de una de ellas.

• Las clases suelen agruparse en directorios,


que reciben el nombre de paquetes
(packages). Un programa suele tener varios
paquetes.

4
• La herramienta jar permite agrupar todas
las clases del programa en un solo archivo
de tipo .jar.

• Dentro de ese archivo .jar, que es como


un .zip, se almacenan las clases y también
otros datos propios del programa.

5
• Cada clase puede tener su propio método
main, pero se ejecuta el método main()
que se indica en el archivo manifest del
archivo .jar

• Véase el tema 0550_JAR.

6
¿Como es un programa (mínimo)
en Java?
[public] class Identificador {

[public][private][protected] característica;
...
[public][private][protected] característica;

/* El método main() es opcional */

public static void main(String[] args) {


/* Declaraciones, código, etc */
}
}
Las características pueden ser atributos o métodos.
7
HolaMundo.java

public class HolaMundo {

public static void main(String[] args) {


System.out.println("Hola, Mundo!");
}
}

8
• Para probar código, un programa como el
anterior funciona perfectamente.

• En muchas ocasiones conviene hacer una


pequeña prueba, simplicísima como esta, en
lugar de intentar incluir la prueba en un
problema más complejo.

9
• En el programa siguiente se hace lo mismo,
pero empleando un método de una clase.

10
public class HolaMundo {

public void decirHola() {


System.out.println("Hola, Mundo!");
}
public static void main(String[] args)
{
HolaMundo hm = new HolaMundo();
hm.decirHola();
}
}

11
• Se pueden añadir más métodos a la clase

12
public class HolaMundo {

public void decirHola() {


System.out.println("Hola, Mundo!");
}
public void decirAdios(){
System.out.println("Adiós, Mundo!");
}
public static void main(String[] args)
{
HolaMundo hm = new HolaMundo();
hm.decirHola();
hm.decirAdios();
}
}
13
• Lo habitual es tener una clase
independiente HolaMundo y usar sus
métodos desde otra clase que contiene el
programa principal.

14
• Esta es la clase HolaMundo, una clase
independiente que no tiene programa
principal pero si tiene métodos.

15
package testprogram;

public class HolaMundo {

public void decirHola() {


System.out.println("Hola, Mundo!");
}
public void decirAdios(){
System.out.println("Adiós, Mundo!");
}

16
• Esta otra es la clase principal, que hace uso
de la clase HolaMundo (mas bien, hace uso
de sus métodos).

17
package testprogram;

public class TestProgram {

public static void main(String[] args)


{
HolaMundo hm = new HolaMundo();
hm.decirHola();
hm.decirAdios();
}

18
• De este modo, una clase que contiene
métodos viene a ser una biblioteca de
funciones como las que se utilizan en C.

• A diferencia de C, no hay import (todavía).


Esto se debe a que las dos clases están en
el mismo paquete (en el mismo directorio,
testprogram).

19
• Las clases no solo contienen métodos,
también contienen atributos (como las
variables de una estructura). Para dar
valores iniciales a esos atributos se emplea
un “constructor”, que es un método de
nombre igual al de la clase, y que se ejecuta
automáticamente

20
Constructores

21
• Un constructor es un método que carece
de tipo proporcionado (ni siquiera void) y
cuyo nombre es igual al de la clase.

• La característica fundamental de un
constructor es q se ejecuta
automáticamente siempre q se crea un
ejemplar de la clase.

22
Ejemplo de
Constructor

23
• En el método main() de la clase Tirar1 se
crea un ejemplar de la clase Pepito, y no se
ejecuta explícitamente ningún método.

• Sin embargo, en la consola aparece un


mensaje.

24
package tirar1;

/**
*
* @author bruegel
*/
public class Tirar1 {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Pepito p = new Pepito();
}

}
25
• Esto se debe a que la clase Pepito posee un
constructor, que se ha ejecutado
automáticamente cuando se ha creado un
ejemplar de Pepito en el método main() de
Tirar1.

26
package tirar1;

/**
*
* @author bruegel
*/
class Pepito {
public Pepito() {
System.out.println(“Tócame, Roque");
}
}

27
Otro ejemplo de
Constructor

28
• En el ejemplo siguiente se crea una clase
llamada persona que tiene dos atributos,
nombre y teléfono. Los dos reciben valor
inicial en un método constructor.

• Esa es la finalidad primordial de los


constructores: dar valores a los atributos.

• Por ejemlo, el constructor puede cargar un


archivo de disco.

29
Clase con constructor
package personabasicojava;

class Persona {

String nombre; // Estos son los atributos


int tel;

public Persona() { // Esto es un constructor


nombre = "Juan";
tel = 5551234;
}

30
• La clase Persona se utiliza desde la clase
PesonaBasicoJava (podría tener cq otro
nombre).

• Como ambas clases son creadas por


NetBeans en el mismo paquete, no hace
falta importar Persona desde
PersonaBasicoJava

31
Clase con constructor
package personabasicojava;

public class PersonaBasicoJava {

public static void main(String[] args) {


Persona p = new Persona();
// Los atributos de p ya tienen el valor dado en
// el constructor
System.out.println("Nombre: " + p.nombre);
System.out.println("Telefono: " + p.tel);
return;
}

}
Proyecto: PersonaBasicoJava

32
• Se pueden crear constructores que admitan
argumentos, para sí dar valores iniciales
arbitrarios a los atributos.

• Los métodos pueden admitir tambien


argumentos, y devolver un valor como en
C.

33
• La tendencia actual parece ser un híbrido
de Java y C++; se admiten funciones fuera
de las clases y se tiende a agrupar todo el
contenido de la clase en un único bloque
de código (y en un solo archivo).

34
¿Como es una un programa
/*
en C++ (I)?
* File: Persona.h
* Author: coti
*
* Created on 18 de julio de 2015, 19:23
*/
#include <iostream>

#ifndef PERSONA_H
#define PERSONA_H

class Persona {
public:
Persona();
std::string nombre;
int tel;

};

#endif /* PERSONA_H */

35
¿Como es una un programa
en C++ (II)?
/*
* File: Persona.cpp
* Author: coti
*
* Created on 18 de julio de
2015, 19:23
*/

#include "Persona.h"

Persona::Persona() {
nombre = "Juan";
tel = 5551234;
}

36
¿Como es una un programa
/*
* File: en C++ (y III)?
main.cpp
* Author: coti
*
* Created on 16 de julio de 2011, 17:30
*
* Este programa muestra una clase básica llamada Persona.
* La clase dispone de un constructor por omisión (sin argumentos)
* y dos atributos, nombre y tel.
*/

#include <iostream>
#include "Persona.h"

using namespace std;

int main(int argc, char** argv) {

Persona p;
cout << "Nombre : " << p.nombre << endl;
cout << "Telefono : " << p.tel << endl;
return 0;
}
37
• Las clases contienen atributos (similares a
los campos de una estructura) y métodos
(similares a funciones).

38
• Los atributos tienen ambito local, es decir,
son visibles desde todos los métodos de la
clase.

39
• Los métodos también tienen ámbito local,
es decir, son visibles (y ejecutables) desde
todos los demás métodos de la clase.

40
• Se puede modificar el alcance del ámbito
de métodos y atributos individualmente,
empleando las palabras reservadas
public, protected y private.

• De hecho el ámbito de los atributos y


métodos, si no se indica nada, es el de
“package”, esto es, son visibles en todas las
clases del mismo paquete.

41
• Las variables que se declaran dentro de un
método son locales dentro de ese método
(no se ven desde otros métodos ni desde
otras clases)

42
DEMO
CrearClasesFicha

43
Declaración de
atributos en Java

• Para usar un atributo en una clase, primero hay que


declararlo.
• El formato de declaración es similar al de C, salvo
los corchetes, que normalmente se colocan antes
del nombre de variable.

44
Declaración de atributos en Java
package crearclasesficha; Ver proyecto CrearClasesFichaJava.
import java.util.Scanner;
import static coti.aux.Aux.readFloat;
import static coti.aux.Aux.readInt;
import static coti.aux.Aux.readString;

public class Ficha {


// Declaración de atributos en Java
private String nombre;
private String apellidos;
private String curso;
private String DNI;
private String grupoPracticas;
private int numNotas;
private float[] calificaciones;
private String comentarios;
public Ficha() { // Código omitido }

public Ficha(Ficha orig) { // Código omitido }

public Ficha(String no,String a,String c,String ID,String g,float[] ca,int n,String cm) { // Código omitido }

void leerDeTeclado() { // Código omitido }


void leerDeTeclado2() {// Código omitido }
void escribirEnPantalla() { // Código omitido }
}
45
Declaración de
métodos en Java
• El formato de declaración de métodos es el de una
función.
• Cada método se puede marcar individualmente
como public, private o protected.
• Por omisión (si no se indica nada) los métodos
tienen visibilidad de paquete.

46
Declaración de métodos en Java
package crearclasesficha;
import java.util.Scanner;
import static coti.aux.Aux.readFloat; Los métodos marcados con private son
import static coti.aux.Aux.readInt; privados; los marcados con public son
import static coti.aux.Aux.readString;
públicos y que no tienen modificador tienen
public class Ficha { visibilidad de paquete.
private String nombre;
private String apellidos;
private String curso; Ver proyecto CrearClasesFichaJava.
private String DNI;
private String grupoPracticas;
private int numNotas;
private float[] calificaciones;
private String comentarios;

public Ficha() {
nombre = "Nombre";
apellidos = "Apellidos";
Cuerpo del constructor sin argumentos
curso = "2014";
DNI = "01234567X";
grupoPracticas = "X7";
numNotas = 5;
calificaciones = new float[numNotas];// Imprescindible asignar memoria
for (int i = 0; i < numNotas; i++) {
calificaciones[i] = i;
}
comentarios = "Comentarios";
} 47
Cuerpos de los métodos en Java
/*
*
* El método leerDeTeclado() no utiliza Aux.
* El método leerDeTeclado2() utiliza Aux.
*
*/
package crearclasesficha; Los métodos marcados con private son
import java.util.Scanner;
privados; los marcados con public son
import static coti.aux.Aux.readFloat; públicos y que no tienen modificador tienen
import static coti.aux.Aux.readInt;
import static coti.aux.Aux.readString; visibilidad de paquete.
import static coti.aux.Aux.readString_ne;
public class Ficha {

private String nombre;


Ver proyecto CrearClasesFichaJava.
private String apellidos;
private String curso;
private String DNI;
private String grupoPracticas;
private int numNotas;
private float[] calificaciones;
private String comentarios;

public Ficha() { // Constructor sin argumentos


nombre = "Nombre";
apellidos = "Apellidos";
curso = "2011";
En Java, los cuerpos de los métodos
DNI = "01234567X";
grupoPracticas = "X7"; se escriben siempre dentro de la clase.
numNotas = 5;
calificaciones = new float[numNotas];// Ojo, imprescindible asignar memoria
for (int i = 0; i < numNotas; i++) {
calificaciones[i] = i;
}
comentarios = "Comentarios";
} 48
Cuerpos de los métodos en Java
public Ficha(Ficha orig) {
nombre = orig.nombre;
apellidos = orig.apellidos;
curso = orig.curso;
DNI = orig.DNI;
grupoPracticas = orig.grupoPracticas;
numNotas = orig.numNotas;
calificaciones = orig.calificaciones.clone();// OJO
comentarios = orig.comentarios;
}
En el segundo ctor
es preciso asignar valores
public Ficha(String nom, a los atributos de forma
String ape,
String cur, individual. ¡En Java no hay
String ID, expresiones con punteros!
String gp,
float[] cal,
int num,
String com) {
nombre = nom;
apellidos = ape;
curso = cur;
DNI = ID;
grupoPracticas = gp;
numNotas = num; En el tercer ctor se crea un
calificaciones = cal.clone(); clon de la tabla de
comentarios = com;
}
calificaciones empleando el
método clone. ¡En Java, las
matrices son objetos!

49
Cuerpos de los métodos en Java
void leerDeTeclado() { // Continúa en la transparencia siguiente
Scanner sc = new Scanner(System.in);
String temp;
boolean numeroBien = false;
do {
System.out.printf("Por favor, escriba su nombre: ");nombre = sc.nextLine();
if (nombre.isEmpty()) {
System.out.println("\nPerdón, este campo no se puede dejar en blanco\n");
}
} while (nombre.isEmpty());
System.out.printf("Por favor, escriba sus apellidos: ");apellidos = sc.nextLine();
System.out.printf("Por favor, escriba su curso: ");curso = sc.nextLine();
System.out.printf("Por favor, escriba su DNI: ");DNI = sc.nextLine();
System.out.printf("Por favor, escriba su grupo de prácticas: ");
grupoPracticas = sc.nextLine();
do {
numeroBien = false;
do {
System.out.printf("Por favor, escriba el número de calificaciones: ");
temp = sc.nextLine();

} while (temp.isEmpty());
try {
numNotas = Integer.parseInt(temp);
numeroBien = true;
} catch (Exception e) {
System.out.printf("\nPerdón, número incorrecto.Pruebe de nuevo.\n");
numeroBien = false;
}
} while (!numeroBien);

Obsérvese que no se admite que el atributo nombre esté vacío. Esto exige utilizar un bucle do-while, que
alarga el método considerablemente. Se admite que los50demás campos de tipo String estén vacíos.
Cuerpos de los métodos en Java
// Sigue el método leerDeTeclado(). Es un método largo y complicado.
calificaciones = new float[numNotas];
for (int i = 0; i < numNotas; i++) {
do {
numeroBien = false;
do {
System.out.printf(String.format("nota[%d] = ", i));
temp = sc.nextLine();

} while (temp.isEmpty());
try {
calificaciones[i] = Float.parseFloat(temp);
numeroBien = true;
} catch (Exception e) {
System.out.printf("\nPerdón, nota incorrecta. Pruebe de nuevo.\n");
numeroBien = false;
}
} while (!numeroBien);
}
System.out.printf("Por favor, escriba sus comentarios: ");
comentarios = sc.nextLine();
}

Para leer cada calificación individual se lee primero una cadena no vacía; una vez obtenida, se traduce a float y
se almacena en la tabla de calificaciones. Este procedimiento se repite para todas las notas. Una vez más, esto
alarga mucho el método, puesto que el proceso debe repetirse para cada variable individual. Sería ideal
disponer de métodos auxiliares que se encargasen de esta tarea.

51
Cuerpos de los métodos en Java
// El método leerDeTeclado2() hace mucho más que el método leerDeTeclado(),
// y hace uso de un 80% menos de código.Véase la clase coti.aux.Aux

void leerDeTeclado2() {

nombre = readString_ne("Por favor, escriba su nombre: ");


apellidos = readString("Por favor, escriba sus apellidos: ");
curso = readString("Por favor, escriba su curso: ");
DNI = readString("Por favor, escriba su DNI: ");
grupoPracticas = readString("Por favor, escriba su grupo de prácticas: ");
numNotas = readInt("Por favor, escriba el número de calificaciones: ");
calificaciones = new float[numNotas];
for (int i = 0; i < numNotas; i++) {
calificaciones[i] = readFloat(String.format("Nota[%d] = ", i));
}
comentarios = readString("Por favor, escriba sus comentarios: ");
}

void escribirEnPantalla() {
System.out.printf("Nombre :%20s%n", nombre);
System.out.printf("Apellidos :%20s%n", apellidos);
System.out.printf("Curso :%20s%n", curso);
System.out.printf("DNI :%20s%n", DNI);
System.out.printf("Prácticas :%20s%n", grupoPracticas);
System.out.printf("Notas :%20d%n", numNotas);
for (float f : calificaciones) {
System.out.printf("%33.2f%n", f);
}
System.out.printf("Comentarios :%20s%n",comentarios);

}
}
52
Constructores en Java
Existe un tipos de métodos con características especiales: los constructores.

Un constructor (ctor) es un método que se ejecuta automáticamente siempre que se declara un


objeto de una clase, bien cuando se crea el objeto directamente (declaración de variables matriciales
estáticas y automáticas) o cuando se crea dinámicamente, mediante el operador new. Toda clase
puede poseer uno o más constructores, que normalmente tendrán el especificador de acceso
public.

El nombre de un constructor es exactamente el nombre de la clase, y carece de tipo proporcionado


(ni siquiera void). Puede recibir o no argumentos.

El lenguaje Java carece de destructores.

Cuando se ejecuta un programa, la creación de un objeto da lugar a la ejecución automática de su


constructor. La memoria asociada al objeto será liberada de forma automática por el recolector
automático de basura (garbage collector). El programador no tiene control sobre el momento en
que se libera la memoria del objeto; esto sucede una vez que el entorno de ejecución observa que
no hay ningún atributo o variable local que contenga la dirección del objeto, quizá cuando la máquina
virtual necesite más memoria.

Véase el proyecto OrdenCtoresJava, que muestra el orden de ejecución de constructores en un


programa dotado de variables de duración estática y automática.
53
Orden de ejecución de ctores en Java
El programa principal de OrdenCtoresJava es el siguiente:

1- package ordenctoresjava;
2-
3- /**
4- *
5- * @author coti
6- */
7- public class OrdenCtoresJava {
8-
9- /**
10- * @param args the command line arguments
11- */
12- public static void main(String[] args) {
13- ClaseBase cb1 = new ClaseBase(1);
14- ClaseBase cb2 = new ClaseBase(2);
15- ClaseDerivada cd1 = new ClaseDerivada(3);
16- ClaseDerivada cd2 = new ClaseDerivada(4);
17- OtraClase otc = new OtraClase();
18- }
19- }

En el constructor de las líneas 13 a la 17 se pasa un argumento, un número que sirve para marcar los
ejemplares y observar así el orden de ejecución. Básicamente, se sigue un orden cronológico de atributos,
salvo los atributos static, cuyos ctores se ejecutan en primer lugar. Al igual que en C++, cuando se crea
un ejemplar de una clase derivada, se ejecuta primero54el ctor de la clase base
Orden de ejecución de ctores en Java
package ordenctoresjava;

public class ClaseBase {

int ejemplar;

public ClaseBase() {
System.out.printf("%s%n", "Ctor clase base sin argumentos.");
}

public ClaseBase(int e) {
ejemplar = e;
System.out.println("Ctor Clase Base " + ejemplar);
}
}

package ordenctoresjava;

public class ClaseDerivada extends ClaseBase {


public ClaseDerivada(int e){
ejemplar = e;
System.out.printf("Ctor clase derivada, ejemplar = %d%n", ejemplar);
}
}
55
Orden de ejecución de ctores en Java
package ordenctoresjava;

public class OtraClase {


ClaseBase atributo1 = new ClaseBase(33);
static ClaseBase atributo2;
ClaseDerivada atributo3;
static ClaseDerivada atributo4 = new ClaseDerivada(44);

public OtraClase(){
atributo2 = new ClaseBase(55);
atributo3 = new ClaseDerivada(66);
}
}

Ctor Clase Base 1


Ctor Clase Base 2 Se observa que se ha ejecutado primero el ctor
Ctor clase base sin argumentos. del atributo estático (44), después ctor del atributo
Ctor clase derivada, ejemplar = 3 automático, y por último los ctores de las
Ctor clase base sin argumentos. variables creadas en el ctor de OtraClase.
Ctor clase derivada, ejemplar = 4
Se ejecutan primero los ctores de atributos estáticos,
Ctor clase base sin argumentos.
Ctor clase derivada, ejemplar = 44 y después los ctores de atributos automáticos por
Ctor Clase Base 33 orden cronológico. Recuérdese que en el caso de una
Ctor Clase Base 55 clase derivada se ejecuta primero el ctor de la clase
Ctor clase base sin argumentos. base.
Ctor clase derivada, ejemplar = 66
56
Métodos de acceso en Java
El concepto de método de acceso es universal, y está presente de uno u otro modo en todos los lenguajes de
programación orientados a objetos. La idea es la siguiente: para cada atributo de una clase, que va a tener
normalmente acceso privado, se definen dos métodos que permiten respectivamente consultar o modificar el
valor de ese atributo. En muchos lenguajes es costumbre anteponer la palabra get al método de consulta, y la
palabra set al método de modificación.Como ejemplo, véase el proyecto CrearClasesJava/
CrearClasesPersonaJava. La clase Persona.java se muestra a continuación:

package crearclasespersonajava;

import static coti.esdia.Esdia.*;

/**
*
* @author coti
*/
public class Persona {

private String nombre;


private String direccion;
private int telefono;
private float talla;
private String DNI;

public Persona(String nombre, String direccion, int telefono, float talla, String DNI) {
this.nombre = nombre;
this.direccion = direccion;
this.telefono = telefono;
this.talla = talla;
this.DNI = DNI;
}
57
Métodos de acceso en Java
public Persona() { return telefono;
nombre = "<áéíóú>"; }
direccion = "<áéíóú>";
telefono = 5551234; public void setTelefono(int telefono) {
talla = 1.75f; // Por qué se pone la f? this.telefono = telefono;
DNI = "12345678X"; }
}
public float getTalla() {
/** return talla;
* @return the nombre }
*/
public String getNombre() { public void setTalla(float talla) {
return nombre; this.talla = talla;
} }

/** public String getDNI() {


* @param nombre the nombre to set return DNI;
*/ }
public void setNombre(String nombre) {
this.nombre = nombre;
} public void setDNI(String DNI) {
this.DNI = DNI;
public String getDireccion() { }
return direccion;
} /* Cada pareja de métodos permite consultar
o modificar un atributo. Los métodos se han
public void setDireccion(String direccion) generado automáticamente, haciendo doble
{ clic en un atributo y haciendo clic en él
this.direccion = direccion; con el botón derecho. Entonces se
} selecciona Refactor/Encapsulate Fields...,
y en el cuadro de diálogo se marca Select
public int getTelefono() { all y se hace clic en Refactor */
58
Métodos de acceso en Java
void leerDeTeclado() {
nombre = readString_ne("Por favor, escriba el nombre : ");
direccion = readString("Por favor, escriba la dirección : ");
telefono = readInt ("Por favor, escriba el teléfono : ");
talla = readFloat ("Por favor, escriba la talla : ");
DNI = readString ("Por favor, escriba el DNI: : ");

void escribirEnPantalla() {
System.out.printf("Nombre : %20s%n", nombre);
System.out.printf("Dirección : %20s%n", direccion);
System.out.printf("Teléfono : %20d%n", telefono);
System.out.printf("Talla : %20.2f%n", talla);
System.out.printf("DNI : %20s%n", DNI);
}
}

/*
Obsérvese que no se ha marcado “Use accessors even when field is accessible”.
En Java, todos los métodos son inline (no hay funciones externas).
Obsérvese también que en el método leerDeTeclado() se hace uso de los métodos
declarados en Esdia, que se ha importado al principio del archivo.
*/
59
EXCEPCIONES

60
Throwable

Error Exception

IOExce SQLExcep
RuntimeException ...
ption tion

NullPoint NumberFo IndexOut


ClassCast
erExcepti rmatExcep OfBounds
Exception
on tion Exception

El compilador nos obliga a capturar o especificar las excepciones comprobadas


(que se muestran en la parte de color azul).

61
Excepciones en Java
Las excepciones de Java son clases que se derivan de Throwable. Esta clase posee
dos subclases, Error y Exception, de las cuales se derivan las demás
excepciones de Java.Los programas escritos en Java pueden lanzar excepciones. Las
excepciones pertenecen a tres categorías:

Excepciones comprobadas. Son aquellas que derivan de Exception


directamente, pero no de Error ni de RuntimeException. Se caracterizan por
describir situaciones causadas por circunstancias internas, y de las que el
programa debe poder normalmente recuperarse. Por ejemplo, si se pasa al
constructor de FileReader el nombre de un archivo, ese constructor puede
lanzar una FileNotFoundException. Esa excepción debe ser notificada al
usuario, al que posiblemente habrá que pedir un nuevo nombre de archivo.
CUMPLEN EL REQUISITO DE CAPTURA O ESPECIFICACIÓN. El compilador
nos obliga a capturar o especificar las excepciones comprobadas.

62
Excepciones en Java

Errores. Son aquellas que derivan de Error directamente. Se deben a


circunstancias ajenas al código del programa. Si el FileReader
anterior consigue abrir el archivo y se produce un fallo en el disco, se
lanzará un IOError. El programa debe notificar al usuario la aparición
de este error, pero posiblemente no puede hacer otra cosa que
mostrar un volcado de pila y concluir la ejecución del programa. NO
CUMPLEN EL REQUISITO DE CAPTURA O ESPECIFICACIÓN.

63
Excepciones en Java

Excepciones de ejecución. Son aquellas que derivan de RuntimeException


directamente. Se caracterizan porque normalmente la aplicación no se puede
recuperar frente a ellas. Por ejemplo, si se pasa un null al constructor del
FileReader, éste lanzara una NullPointerException. La aplicación
puede capturar esta excepción, pero tiene más sentido corregir el error lógico
que hay en la aplicación, y que ha dado lugar esta excepción. No cumplen el
requisito de captura o especificación, esto es, el compilador no nos obliga a
capturarlas o especificarlas.

64
Jerarquía de excepciones en Java
Throwable

Error Exception

IOExce SQLExcep
RuntimeException ...
ption tion

NullPoint NumberFo IndexOut


ClassCast
erExcepti rmatExcep OfBounds
Exception
on tion Exception

Las excepciones comprobadas (checked exceptions) se muestran en azul en el diagrama. Todas ellas se
derivan directamente de Exception. El compilador nos obliga a capturar o especificar las
excepciones comprobadas.
Los excepciones no comprobadas (unchecked exceptions) se muestran en rojo en el diagrama. Todas
ellas se derivan directamente de Error y de RuntimeException. El compilador no obliga a
comprobarlas.
Obsérvese que RuntimeException se deriva de Exception. Por tanto, un catch() que
capture Exception procesará tanto las excepciones comprobadas como los errores de ejecución. Si
65
Excepciones en Java
El requisito de Captura o Especificación

De estas tres categorías, las excepciones que pertenecen a la primera tienen que cumplir
necesariamente el requisito de Captura o Especificación, esto es, todo bloque de código que
lance una excepción del tipo (1) tiene que capturar esa excepción, o debe notificar que puede
lanzar ese tipo de excepción. El compilador lo impone, y de hecho ofrece su ayuda. Las excepciones
de los tipos (II) y (III) no están obligadas a cumplir el requisito de captura o especificación, aunque se
admite su captura o especificación.

Para capturar una excepción, es preciso emplear un bloque catch():

catch(TipoDeExcepcionCapturado | OtroTipoDeExcepcion ex)


{
// Código que procesa esta excepción
}

Para notificar que un código pueden lanzar una excepción, es preciso emplear una sentencia throws:

throws Excepcion_1, Excepcion_2,... Excepcion_N;

66
Excepciones en Java
Sintaxis

El mecanismo de tratamiento de excepciones en Java se basa en una sentencia con tres


bloques:

try {
// Código vigilado
}
catch(ExcepcionCapturada_1 ex1) {
// Código que procesa ex1
}
catch(ExcepcionCapturada_2 ex2) {
// Código que procesa ex2
}
finally
{
// Código que se ejecuta siempre,
// tanto si se procesa una excepción como si no
}

67
Excepciones en C++
No todos los errores dan lugar al lanzamiento de una excepción, aun cuando el error cometido haga
que los resultados obtenidos sean incorrectos. Esto se hace porque la eficiencia se resentiría mucho
si se comprobasen todos los resultados. La solución de este problema es utilizar siempre tipos de
datos cuyo alcance sea mayor que el mayor resultados posible; esta medida debe complementarse con
la oportuna validación de los datos que debe procesar el programa.
#include <iostream>
#include <stdexcept>
#include <climits>
using namespace std;
int main(int argc, char** argv) {
int n1, n2, n3;
n1 = n2 = INT_MAX;
try {
n3 = n1 + n2;
cout << n1 << " + " << n2 << " = " << n3 << endl;
} catch (exception & e) {
cout << e.what();
}
cout << "\n\nY aquí no ha pasado nada!\n\n";
return 0;
}
Véase el proyecto PruebaExcepciones
68
Excepciones en Java
El manejo de excepciones en Java puede observarse en el proyecto PruebaExcepciones.
public class PruebaExcepciones {

public static void main(String[] args) {


int n1 , n2 , n3 = -1;
n1 = n2 = Integer.MAX_VALUE;
try {
n3 = n1 + n2;
System.out.printf("%d + %d = %d%n", n1, n2, n3);
} catch (Exception e) {
System.out.println(e);
}
System.out.printf("\n\nY aquí no ha pasado nada!\n\n");
n2 = 0;
// La excepción se produce al evaluar el rvalue,
// y el resultado no llega a asignarse al lvalue
try {
n3 = n1 / n2;
}
catch(RuntimeException re){
System.out.println("Excepción ---> " +re);
}
finally {
System.out.println("n3 vale "+ n3);
}
}
}
En el primer bloque try/catch no se captura el desbordamiento, aunque si la división por cero en el
segundo. 69
Excepciones en Java
El proyecto ExcepcionesEnJava muestra la diferencia entre excepciones comprobadas, como
IOException, y excepciones de ejecución, como IndexOutOfBoundsException. La primera
excepción se produce cuando hay un error de E/S; en este caso se trata de un archivo en el cual no se
puede escribir por no existir el directorio que lo contiene. La excepción no comprobada se produce
cuando se intenta acceder a un elemento inexistente de lista.

La clase ListaDeNumeros contiene dos métodos, escribirLista_1 y escribirLista_2,


cuyo código lanza excepciones comprobadas, luego esos métodos tienen que satisfacer el requisito de
Captura o Especificación. El primero cumple el requisito de especificación, mediante una cláusula
throws que indica que lanza una IOException (una clase de la cual deriva
FileNotFoundException). El segundo cumple el requisito de captura, mediante una sentencia
try/catch que contiene las llamadas que pueden producir una IOException.

Ni un método ni el otro capturan o especifican la excepción de tipo IndexOutOfBounds que


puede lanzar el método get() de ArrayList, porque es una excepción no comprobada (un error
de ejecución). Como consecuencia, si hay un error de índices (como el que se produce al intercambiar
// en las líneas 39 y 40), el programa se detendrá al producirse una excepción no capturada. ¿Cómo
se podría resolver este problema?

70
Excepciones en Java
El archivo ExcepcionesEnJava.java es como sigue:

public class ExcepcionesEnJava {

public static void main(String[] args) {


File f1 = new File("ArchivoSalida1.txt");
File f2 = new File("ArchivoSalida2.txt");
// File f1 = new File("errortonto/ArchivoSalida1.txt");
// File f2 = new File("errortonto/ArchivoSalida2.txt");

ListaDeNumeros unaLista = new ListaDeNumeros();

try {
unaLista.escribirLista_1(f1);
} catch (IOException ex) {
System.out.println("\nNo fue posible escribir en el archivo "
+ f1.getName());
System.out.println(ex);
} finally {
System.out.println("\nSe ha ejecutado el método escribirLista_1()");
}

unaLista.escribirLista_2(f2);
}
}

El método escribirLista_1() tiene que alojarse en el bloque try{}.


El método escribirLista_2() puede ejecutarse sin que resida en un try{}.
Las excepciones de tipo IndexOutOfBounds no se capturan.
71
Excepciones en Java
public class ListaDeNumeros {

private List<Integer> lista;


private static final int NUM_ELEMENTOS = 15;

public ListaDeNumeros() {
lista = new ArrayList<Integer>(NUM_ELEMENTOS);
for (int i = 0; i < NUM_ELEMENTOS; ++i) {
lista.add(new Integer(i));
}
}

public void escribirLista_1(File f) throws IOException {

FileWriter fw = new FileWriter(f);


PrintWriter salida = new PrintWriter(fw);

salida.println("Este es el archivo " + f.getName());


// for (int i = 0; i < NUM_ELEMENTOS+1; ++i) {
for (int i = 0; i < NUM_ELEMENTOS; ++i) {
salida.println("El valor situado en la posición "
+ i + " es " + lista.get(i));
}

salida.close();
}

Este método especifica la excepción que lanza el código que contiene, mediante la expresión throws
IOException.
72
Excepciones en Java
public void escribirLista_2(File f) {
PrintWriter salida = null;
try {
FileWriter fw = new FileWriter(f);
salida = new PrintWriter(fw);

salida.println("Este es el archivo " + f.getName());


for (int i = 0; i < NUM_ELEMENTOS; ++i) {
salida.println("El valor situado en la posición "
+ i + " es " + lista.get(i));
}
} catch (IOException ex) {
System.out.println("\nError:No fue posible escribir el archivo "
+ f.getName());
System.out.println(ex);
if (null != salida)
salida.close();
} finally {
System.out.println("\nSe ha ejecutado el método escribirLista_2()");
}
}
}

Este método captura la excepción que lanza el código que contiene, mediante un bloque try{} que
alberga las llamadas que pueden dar lugar a la excepción

73
Excepciones en Java
En ciertas ocasiones es preciso reaccionar frente a una excepción en más de un lugar. Esto puede
conseguirse relanzando la excepción, una vez efectuada una primera parte del procesamiento. El
proyecto PruebaRelanzarExcepcionJava muestra un ejemplo.

// Archivo RelanzarExcepcion.java
public class RelanzarExcepcion {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
PruebaRelanzar p = new PruebaRelanzar();

try {
p.lanzar_capturar_y_relanzar();
} catch (Exception e) {
System.out.println("\n\nMain; excepción capturada ---> " + e);
}
}
}

La excepción se produce en un método de PruebaRelanzar, y se captura primero en ese método.


Tras ser relanzada, se captura finalmente en RelanzarExcepcion.

74
Excepciones en Java
Para relanzar una excepción se emplea de nuevo la sentencia throw, como puede verse en el método
lanzar_capturar_y_relanzar().

public class PruebaRelanzar {

void lanzar_capturar_y_relanzar() throws Exception {


// Se lanza una excepción y se captura de inmediato
try {
System.out.println("PruebaRelanzar; lanzar_capturar_y_relanzar()\n");
throw new Exception("Lanzada desde PruebaRelanzar");
} catch (Exception ex) {
System.out.println("Exc. capturada en lanzar_capturar_y_relanzar()");
System.out.println("\nSe vuelve a lanzar la excepción");

throw ex;

} finally {
System.out.println("PruebaRelanzar: lanzar_capturar_y_relanzar()");
}
}
}

En el bloque catch() se efectúa un primer procesamiento y se relanza la excepción, que será capturada en main().

75
Excepciones en Java
Cuando se lanza una excepción, el entorno de ejecución busca un bloque catch() que contenga la
llamada causante de la excepción, y sea capaz de procesarla. Si se encuentra ese bloque, la excepción
se captura. Si no se encuentra, el flujo de control asciende por la sucesión de llamadas a métodos,
buscando un catch() apropiado. Si finalmente no se encuentra es catch(), el programa se
detiene, no por la excepción, sino por no haber encontrado un bloque adecuado para procesarla. El
proyecto RecorridoInversoDeLaPila muestra un ejemplo.

//Archivo RecorridoInversoDeLaPila
public class RecorridoInversoDeLaPila {

public static void main(String[] args) {


ClaseDePrueba cdp = new ClaseDePrueba();
try {
cdp.metodo_1();
} catch (Exception e) {
System.out.println("Catch : Excepción capturada en main: " + e);
} finally {
System.out.println("Finally : Se ha ejecutado el método 1 de ClaseDePrueba");
}
}
}

La llamada a metodo_1() da lugar a otra llamada a metodo_2(), que llama a metodo_3(), que
lanza una excepción. Esa excepción se procesa finalmente en main(), tras ascender por la pila
efectuando un recorrido inverso.

76
Excepciones en Java
El método 3 tiene que capturar o especificar la Exception que lanza. Opta por especificarla. El
método 2 tiene que capturar o especificar la Exception que produce el método 3, al cual invoca.
Opta por especificarla.El método 1 tiene que capturar o especificar la Exception que produce el
método 2. Opta por especificarla.
//Archivo ClaseDePrueba
public class ClaseDePrueba {

void metodo_3() throws Exception {


System.out.println("En el método 3");
throw new Exception("Exceptión lanzada en método 3");
}

void metodo_2() throws Exception {


System.out.println("Se llama al método 3 desde el método 2");
metodo_3();
}

void metodo_1() throws Exception {


System.out.println("Se llama al método 2 desde el método 1");
metodo_2();
}
}

Cuando se produce la excepción en el método 3, no se halla un catch() que la procese, luego se


asciende por la jerarquía de llamadas hasta el método 2. Tampoco se encuentra allí un catch()
adecuado, luego se asciende al método 1. Tampoco se encuentra allí un catch() adecuado, luego se
asciende a main(), y allí se encuentra un catch() que procesa la excepción.
Si no fuera así, el programa se detendría con un error, al no ser capaz de procesar la excepción.
77
Excepciones en Java
El manejo de excepciones en Java ofrece un sofisticado mecanismo de
control de errores. Su correcta utilización da lugar a programas que rara
vez detienen su ejecución por un error.

Cuando se produce una excepción, el programador debe buscar la forma


de recuperarse de esa situación. Si falla el nombre de un archivo o no se
encuentra, debe solicitar de nuevo el nombre del archivo. Si un valor
produce una situación de error, debe buscarse una posible solución,
leyendo de nuevo el valor, o solicitando una nueva transmisión del mismo.
Si finalmente no es posible proseguir la normal ejecución del programa,
este tiene que detenerse de manera ordenada, cerrando todos los
archivos utilizados, finalizando las comunicaciones establecidas con otras
máquinas de manera correcta, y en general dejando los recursos utilizados
en una situación adecuada para que en la próxima ejecución del programa
éste se no encuentre dificultades debidas al error producido.
78
Programación III
Clases en C++ y Java - Curso 2015-2016

Depto. de Informática y Automática


Grado en Ingeniería Informática
79 Dr. J.R. García-Bermejo Giner

También podría gustarte