Manipuladores de exceções - IME-USP

Propaganda
Seminário:
Manipulação de exceções em Java
Fabiana Piesigilli
Rodrigo Mendes Leme
MAC 441 - Programação Orientada a
Objetos
Introdução
Introdução
 Mundo ideal: dados estão sempre na forma
certa, arquivos desejados sempre existem,
etc.
 Mundo real: dados ruins e bugs podem
arruinar o programa.
Introdução
 Necessidade de mecanismos para
tratamento de erros.
 Antes da POO:


Variável global inteira com valores de 0 até n.
Na ocorrência de uma exceção:
Variável assumia um valor.
 Remetia uma mensagem de erro.
 Encerrava o programa.

Introdução
 Depois da POO:




Classes de erros.
Possíveis tipos de erros e seus tratamentos são
agrupados.
Não há necessidade de interromper o programa.
O mesmo erro é tratado quantas vezes for
necessário.
Introdução
 Idéia básica: “código ruim não será
executado”.
 Nem todos os erros podem ser detalhados
em tempo de compilação.
 Os que não podem devem ser lidados em
tempo de execução.
 Estes últimos são o alvo da manipulação de
exceções.
Introdução
 Premissa básica: separar o processamento
normal da manipulação de erros.
 Vantagens desse mecanismo:



Permite concentrar em lugares diferentes o
“código normal” do tratamento do erro.
Simplifica a criação de programas grandes
usando menos código.
Torna o código mais robusto, ao garantir que
não há erros sem tratamento.
Exceções - básico
Hierarquia de exceções de Java
Throwable
Error
Exception
...
...
IOException
RunTimeException
...
...
 Exceção: problema que impede a
continuação do método ou escopo em
execução.
 Importante: exceção  problema normal.
 Problema normal: há informação suficiente
no contexto atual para lidar com ele.
 Exceção: não há informação suficiente.
 Disparar uma exceção: sair do contexto
atual e relegar a solução a um contexto mais
abrangente.
Exceções: Básico
 Ao disparar-se uma exceção, ocorre a
seguinte sequência de eventos:




Um objeto exceção é criado.
A execução é interrompida.
O mecanismo de manipulação de exceções
assume o controle o procura o manipulador de
exceção adequado.
O manipulador da exceção trata o problema.
 Exemplo: seja t uma referência para um
objeto, que pode não ter sido inicializado.
if (t == null)
throw new NullPointerException();
 A palavra chave throw dispara uma
exceção e dá início à sequência de eventos
citada anteriormente.
 Outra versão:
if (t == null)
throw new NullPointerException
(“t = null”);
 Este construtor permite colocar informações
pertinentes na exceção, que posteriormente
podem ser extraídas usando outros métodos.
 Em resumo, disparar uma exceção é fácil:



1) Escolha uma classe de exceção apropriada.
2) Instancie um objeto dessa classe.
3) Dispare-o.
throw new EOFException();
(3)
(2)
(1)
Capturando exceções
Capturando exceções
 Quando uma exceção é disparada, em
algum lugar ela deve ser capturada.
 Região protegida: trecho de código que
pode gerar exceções.
 Manipuladores de exceções: tratam as
exceções que ocorreram dentro da região
protegida. Vêm imediatamente após a
mesma.
 Em Java:


try: indica a região protegida.
catch: manipula uma exceção.
Formato básico:
try {
// Código
}
catch(ClasseDeExceção e) {
// Manipula aquele tipo de erro
}
 Pode-se usar vários manipuladores:
try { ...
}
catch(ClasseDeExcecao1 c1) { ...
}
catch(ClasseDeExcecao2 c2) { ...
}
catch(ClasseDeExcecao3 c3) { ...
}
...
Capturando exceções
 Processo:
 A exceção é disparada dentro de um bloco
try.
 O mecanismo de manipulação de exceção
procura o primeiro catch cujo tipo de
exceção bata com a exceção disparada.
 O mecanismo entra no bloco do catch e o
erro é tratado.
 Exemplo: método para ler caracteres de um
arquivo.
public static String readString()
{
int carac;
String cad = “”;
boolean terminou = false;
while (!terminou)
{
try
{
carac = System.in.read();
if (carac < 0 ||
(char) carac == `\n`)
terminou = true;
else
cad = cad + (char) carac;
}
catch(IOException e) {
terminou = true;
} ...
CRIANDO SUAS PRÓPRIAS
EXCEÇÕES
class MyException extends Exception {
public MyException() {}
public MyException(String msg) {
super(msg);
}
}
public class Inheriting {
public static void f() throws MyException {
System.out.println("Throwing MyException from f()");
throw new MyException();
}
public static void g() throws MyException {
System.out.println("Throwing MyException from g()");
throw new MyException("Originated in g()");
}
public static void main(String[] args) {
try {
f();
} catch(MyException e) {
e.printStackTrace();
}
try {
g();
} catch(MyException e) {
e.printStackTrace();
}
}
}
Criando suas próprias exceções
Throwing MyException from f()
MyException
at Inheriting.f(Inheriting.java:16)
at Inheriting.main(Inheriting.java:24)
Throwing MyException from g()
MyException:Originated in g()
at Inheriting.g(Inheriting.java:20)
at Inheriting.main(Inheriting.java:29)
Criando suas próprias exceções
class MyException2 extends Exception
{
public MyException2() {}
public MyException2(String msg) {
super(msg);
}
public MyException2(String msg, int x) {
super(msg);
i = x;
}
public int val() {
return i;
}
private int i;
}
public class Inheriting2 {
public static void f() throws MyException2 {
System.out.println( "Throwing MyException2 from f()");
throw new MyException2();
}
public static void g() throws MyException2 {
System.out.println( "Throwing MyException2 from g()");
throw new MyException2("Originated in g()");
}
public static void h() throws MyException2 {
System.out.println( "Throwing MyException2 from h()");
throw new MyException2( "Originated in h()", 47);
}
public static void main(String[] args) {
try {
f();
} catch(MyException2 e) {
e.printStackTrace();
}
try {
g();
} catch(MyException2 e) {
e.printStackTrace();
}
try {
h();
} catch(MyException2 e) {
e.printStackTrace();
System.out.println("e.val() = " + e.val());
}
}
}
Criando suas próprias exceções
Throwing MyException2 from f()
MyException2
at Inheriting2.f(Inheriting2.java:22)
at Inheriting2.main(Inheriting2.java:34)
Throwing MyException2 from g()
MyException2: Originated in g() at
Inheriting2.g(Inheriting2.java:26)
at Inheriting2.main(Inheriting2.java:39)
Throwing MyException2 from h()
MyException2: Originated in h()
at Inheriting2.h(Inheriting2.java:30)
at Inheriting2.main(Inheriting2.java:44)
e.val() = 47
Criando suas próprias exceções
class SimpleException extends Exception
{ }
Especificação de Exceções
Especificação de Exceções
void f() throws tooBig, tooSmall,
divZero {
//...
}
void f() {
// ...
}
EXCEÇÕES PADRÃO DO JAVA
Exceções padrão do Java
Throwable:
 Error
 Exception
Exceções padrão do Java
http://java.sun.com
Exceções padrão do Java
Todas as classes herdam de
java.lang.Exception
Mas nem todas estão definidas em java.lang.
Por exemplo:
java.io.IOException
Exceções padrão do Java
RuntimeException
Exceções padrão do Java:
RuntimeException
if(t == null) throw new
NullPointerException();
Exceções padrão do Java:
RuntimeException
public class NeverCaught {
static void f() {
throw new
RuntimeException("From f()");
}
static void g() {
f();
}
public static void main(String[] args) {
g();
}
}
Exceções padrão do Java:
RuntimeException
java.lang.RuntimeException: From f()
at NeverCaught.f(NeverCaught.java:9)
at NeverCaught.g(NeverCaught.java:12)
at NeverCaught.main(NeverCaught.java:15)
Exceções padrão do Java:
RuntimeException
Se uma RuntimeException chega ao main
sem ser capturada,
printStackTrace( )
é chamado, e o programa sai.
Exceções padrão do Java:
RuntimeException
Uma RuntimeException significa um erro de
programação:


Um erro do programador cliente, que passou um
ponteiro nulo, causando uma
NullPointerException
Um erro seu, que não verificou se estava
acessando um índice válido do vetor, e causou
uma
ArrayIndexOutOfBoundsException
Finally
 Frequentemente existe algum trecho de
código que deve ser executado
independente de uma exceção ter ou não ter
sido disparada.
 Problema: se o método alocou um recurso e
uma exceção foi disparada, o recurso pode
não ter sido liberado.
 Apesar de Java possuir coleta de lixo, pode
ser necessário retornar algum recurso não
relacionado a memória para seu estado
original.
 Exemplos: fechar um arquivo, fechar uma
conexão de rede, redesenhar algum
componente na tela, etc.
 Em Java:

finally: indica o trecho de código que
sempre será executado.
Formato básico:
try {
// Código
}
catch(ClasseDeExcecao e) {
// Manipulador da exceção
}
finally { ... // Código que será
}
// executado sempre
 Exemplo: em quaisquer circunstâncias,
Java executará g.dispose().
Graphics g = image.getGraphics();
try {
...
}
catch(IOException e) {
terminou = true;
}
finally {
g.dispose();
}
 Possibilidades de execução do finally:



O código não dispara exceções: tudo o que
estiver no try e, em seguida, no finally, é
executado.
O código dispara uma exceção que é capturada
por um catch: tudo o que estiver no try até a
exceção ser disparada é executado. Depois,
executa o código do catch e, por fim, o
finally.
O código dispara uma exceção que não é
capturada por nenhum catch: tudo o que
estiver no try até a exceção ser disparada é
executado. Depois, executa o código do
finally.
Restrições a exceções
 Existe uma tendência a se abusar de
exceções.
 Exceções podem diminuir muito o
desempenho do código.
 Algumas dicas devem ser seguidas quando
se está usando exceções.
 Testes simples não devem ser substituídos
por manipulação de exceções.
 Exemplo: tentar desempilhar 1.000.000 de
vezes uma pilha vazia.
1)if (!pilha.empty())
pilha.pop();
---> 6 s
2)try { pilha.pop(); }
---> 64 s
catch(EmptyStackException e){...}
 Conclusão: use exceções apenas para
circunstâncias excepcionais.
 Não microgerencie exceções.
 Exemplo: gravar os elementos de uma pilha
num arquivo.
for (i = 0; i < 100; i++) {
try { n = pilha.pop(); }
catch(EmptyStackException s){...}
try { out.writeInt(n); }
catch(IOException e){...}
}
 Se a pilha estiver vazia, continuará vazia; se
houver um erro no arquivo, ele não sumirá.
 Faz mais sentido colocar toda a operação no
try.
try {
for (i = 0; i < 100; i++) {
n = pilha.pop();
out.writeInt(n);
}
catch(IOException e) {...}
catch(EmptyStackException s){...}
}
 Conclusão: o código fica mais limpo,
garantindo a premissa básica.
 Não bloqueie exceções.
 Exemplo: carregar uma imagem de arquivo.
Image loadImage(String nomearq)
{
try {
// Inúmeras linhas
}
// de código
catch (ClasseDeExcecao e)
{}
}
 Conclusão: o programador deve se esforçar
para gerenciar exceções corretamente.
Construtores
import java.io.*;
class InputFile {
private BufferedReader in;
InputFile(String fname) throws Exception {
try {
in = new BufferedReader(new FileReader(fname));
// Other code that might throw exceptions
} catch(FileNotFoundException e) {
System.out.println( "Could not open " + fname);
// Wasn't open, so don't close it
throw e;
} catch(Exception e) {
// All other exceptions must close it
try {
in.close();
} catch(IOException e2) {
System.out.println( "in.close() unsuccessful"); }
throw e;
} finally {
// Don't close it here!!!
}
}
String getLine() {
String s;
try {
s = in.readLine();
}
catch(IOException e) {
System.out.println( "readLine() unsuccessful");
s = "failed";
}
return s;
}
void cleanup() {
try {
in.close();
} catch(IOException e2) {
System.out.println( "in.close() unsuccessful");
}
}
}
Construtores
public class Cleanup {
public static void main(String[] args){
try {
InputFile in = new
InputFile("Cleanup.java");
String s;
int i = 1;
while((s = in.getLine()) != null)
System.out.println(""+ i++ + ": " +
s);
in.cleanup();
} catch(Exception e) {
System.out.println( "Caught in main,
e.printStackTrace()");
e.printStackTrace();
}
}
}
Contrutores
String getLine() throws
IOException {
return in.readLine();
}
Casamento de Exceções
Casamento de Exceções
class Annoyance extends Exception {}
class Sneeze extends Annoyance {}
public class Human {
public static void main(String[] args) {
try {
throw new Sneeze();
} catch(Sneeze s) {
System.out.println("Caught Sneeze");
} catch(Annoyance a) {
System.out.println("Caught
Annoyance");
}
}
}
Casamento de Exceções
try {
throw new Sneeze();
} catch(Annoyance a) {
System.out.println("Caught
Annoyance");
} catch(Sneeze s) {
System.out.println("Caught
Sneeze");
}
Conclusão
Conclusão
Use exceções para:
1)
Consertar o problema e chamar o método que causou a exceção de
novo
2)
Contornar o erro e continuar sem tentar o método novamente
3)
Calcular algum resultado alternativo em vez daquele que o método
deveria produzir
4)
Fazer o que for possível no contexto atual e lançar a mesma exceção
para o contexto superior
5)
Fazer o que for possível no contexto atual e lançar uma exceção
diferente para o contexto superior
6)
Terminar o programa
7)
Simplificar. Se seu esquema de exceções complica as coisas, então
ele será ruim para ser usado
8)
Tornar sua biblioteca e seu programa mais seguros
Download