• Nenhum resultado encontrado

Lista de Códigos

3.10 Exceções

Uma exceção é um sinal indicativo de que algum tipo de condição excepcional ocorreu durante a execução do programa. Assim, exceções estão associadas a condi- ções de erro que não tinham como ser verificadas durante a compilação do programa.

As duas atividades associadas à manipulação de uma exceção são:

• Geração: a sinalização de que uma condição excepcional (por exemplo, um erro) ocorreu;

• Captura: a manipulação (tratamento) da situação excepcional, em que as ações necessárias para a recuperação da situação de erro são definidas.

Para cada exceção que pode ocorrer durante a execução do código, um bloco de ações de tratamento (umexception handler) deve ser especificado. O compilador Java verifica e obriga que toda exceção não trivial tenha um bloco de tratamento associado.

O mecanismo de tratamento de exceções em Java, embora apresente suas particu- laridades, teve seu projeto inspirado no mecanismo equivalente da linguagem C++.

É um mecanismo adequado ao tratamento de exceções síncronas, para situações em que a recuperação do erro é possível.

A sinalização da exceção é propagada a partir do bloco de código em que ela ocorreu através de toda a pilha de invocações de métodos, até que a exceção seja capturada por um bloco de ações de tratamento (exception handler). Eventualmente, se tal bloco não existir em nenhum ponto da pilha de invocações de métodos, a sinalização da exceção atinge o métodomain(), fazendo com que a máquina virtual Java apresente uma mensagem de erro e aborte sua execução.

3.10.1 Tratamento de exceções

A captura e o tratamento de exceções em Java se dão através da especificação de blocostry, catche finally, definidos através destas mesmas palavras reserva- das da linguagem. A estruturação desses blocos obedece a sintaxe apresentada no Código 3.15.

XException e YException deveriam ser substituídos pelo nome do tipo de exceção. Os blocos não podem ser separados por outros comandos — um erro de sintaxe seria detectado pelo compilador Java nesse caso. Cada bloco try pode ser

93

seguido por zero ou mais blocos catch, e cada bloco catch refere-se a uma única exceção.

t r y {

// cód i g o que i n c l u i comandos / i n v o c açõe s de mét o d o s que podem g e r a r uma s i t u ação de e x c eção . }

c a t c h ( X E x c e p t i o n e x ) {

// b l o c o de t r a t a m e n t o a s s o c i a d o à c o n d ição de e x c eção X E x c e p t i o n ou a q u a l q u e r uma de s u a s // s u b c l a s s e s , i d e n t i f i c a d a a q u i p e l o o b j e t o e x

}

c a t c h ( Y E x c e p t i o n e y ) {

// b l o c o de t r a t a m e n t o p a r a a s i t u ação de e x c eção Y E x c e p t i o n ou a q u a l q u e r uma de s u a s s u b c l a s s e s }

f i n a l l y {

// b l o c o de cód i g o que s e m p r e s e rá e x e c u t a d o após o b l o c o t r y , i n d e p e n d e n t e m e n t e de s u a c o n c l u são // t e r o c o r r i d o n o r m a l m e n t e ou t e r s i d o i n t e r r o m p i d a

}

Código 3.15 Tratamento de exceções em Java.

O bloco finally, quando presente, é sempre executado. Em geral, ele inclui comandos os quais liberam recursos que eventualmente podem ter sido alocados durante o processamento do blocotrye que podem ser liberados, independentemente de a execução ter sido encerrada com sucesso ou ter sido interrompida por uma condição de exceção. A presença desse bloco é opcional.

Alguns exemplos de exceções já definidas no pacote java.lang incluem:

ArithmeticException: indica situações de erros em processamento aritmético, tal como uma divisão inteira por 0. A divisão de um valor real por 0 não gera uma exceção (o resultado é o valor infinito);

NumberFormatException: indica que se tentou a conversão de uma string para um formato numérico, mas seu conteúdo não representava adequadamente um número para aquele formato. É uma subclasse deIllegalArgumentException;

IndexOutOfBounds: indica a tentativa de acesso a um elemento de um agregado aquém ou além dos limites válidos. É a superclasse deStringIndexOutOfBounds, parastrings, e de ArrayIndexOutOfBoundsException, paraarrays;

NullPointerException: indica que a aplicação tentou usar uma referência, a um objeto, que ainda não foi definida;

ClassNotFoundException: indica que a máquina virtual Java tentou carregar uma classe, mas não foi possível encontrá-la durante a execução da aplicação.

Além disso, outros pacotes especificam suas exceções, referentes às suas funci- onalidades. Por exemplo, no pacote java.io, define-se IOException, que indica a ocorrência de algum tipo de erro em operações de entrada e saída (Unidade 4). É a 94

superclasse das classes que representam condições de exceção mais específicas, tais comoEOFException(fim de arquivo oustream),FileNotFoundException(arquivo especificado não foi encontrado) eInterruptedIOException (operação de entrada ou saída foi interrompida).

Uma exceção contém pelo menos umastringque a descreve, que pode ser obtida pela invocação do método getMessage(), mas pode eventualmente conter outras informações. Por exemplo, InterruptedIOException inclui o atributo público do tipo inteiro, chamadobytesTransferred, que indica quantosbytesforam transferi- dos antes de a interrupção da operação ocorrer. Outra informação que pode sempre ser obtida de uma exceção é a sequência de métodos no momento da exceção, que pode ser obtida a partir da invocação do métodoprintStackTrace().

Como exceções fazem parte de uma hierarquia de classes, exceções mais genéricas (mais próximas do topo da hierarquia) englobam aquelas que são mais específicas.

Assim, a forma mais genérica de um blocotry-catché

try{ ...

}catch (Exception e){

// código responsável pelo tratamento da exceção }

pois todas as exceções são derivadas deException. Se dois blocoscatchespecificam exceções, o tratamento da exceção derivada (ex.: FileNotFoundException) deve preceder o da mais genérica (ex.: IOException).

3.10.2 Erro eRuntimeException

Exceções em Java consistem em um caso particular de um objeto da classe Throwable. Apenas objetos dessa classe ou de suas classes derivadas podem ser gerados, propagados e capturados através do mecanismo de tratamento de exceções.

Além de Exception, outra classe derivada de Throwable é a classe Error, a qual é a raiz das classes que indicam situações as quais a aplicação não tem como ou não deve tentar tratar. Usualmente indica situações anormais, que não deveriam ocorrer. Dentre os erros definidos em Java, no pacote java.lang, estão StackOverflowErrore OutOfMemoryError. São situações em que não é possível

95

uma correção a partir de um tratamento realizado pelo próprio programa que está executando.

Há também exceções que não precisam ser explicitamente capturadas e tratadas.

São aquelas derivadas de RuntimeException, uma classe derivada diretamente de Exception. São exceções que podem ser geradas durante a operação normal de uma aplicação, para as quais o compilador Java não irá exigir que o programador realize algum tratamento (ou que propague a exceção, como escrito na Seção 3.10.3).

Nelas se incluem: ArithmeticException, IllegalArgumentException, IndexOutOfBoundsExceptione NullPointerException.

3.10.3 Propagando exceções

Embora toda exceção que não seja derivada de RuntimeException deva ser tratada, nem sempre é possível tratar uma exceção no mesmo escopo do método cuja invocação gerou a exceção. Nessas situações, é possível propagar a exceção para um nível acima na pilha de invocações.

Para tanto, o método que está deixando de capturar e tratar a exceção faz uso da cláusulathrowsem sua declaração:

v o i d m e t o d o Q u e N a o T r a t a E x c e c a o ( ) t h r o w s E x c e p t i o n { m e t o d o Q u e P o d e S i n a l i z a r E x c e c a o ( ) ;

}

Nesse caso, metodoQueNaoTrataExcecao() reconhece que em seu corpo há a possibilidade da sinalização de uma exceção, mas não se preocupa em realizar o trata- mento dessa exceção em seu escopo. Em vez disso, ele repassa essa responsabilidade para o método anterior (o método que o invocou) na pilha de chamadas.

Eventualmente, também o outro método pode repassar a exceção adiante. Porém, pelo menos no métodomain(), as exceções deverão ser tratadas ou o programa terá sua interpretação interrompida.

3.10.4 Definindo e sinalizando exceções

Exceções são classes. Assim, é possível que uma aplicação defina suas próprias exceções através do mecanismo de definição de classes.

Por exemplo, considere que fosse importante para uma aplicação diferenciar a condição de divisão por zero de outras condições de exceções aritméticas. Nesse 96

caso, uma classe DivideByZeroException (Código 3.16) poderia ser criada. O argumento para o construtor da superclasse especifica a mensagem que seria impressa quando o métodogetMessage() for invocado para essa exceção.

Para levantar uma exceção durante a execução de um método, um objeto dessa classe deve ser criado e, através do comando throw, propagado para os métodos anteriores na pilha de execução (Código 3.16, linhas 10-15).

1 p u b l i c c l a s s D i v i d e B y Z e r o E x c e p t i o n e x t e n d s A r i t h m e t i c E x c e p t i o n { 2

3 p u b l i c D i v i d e B y Z e r o E x c e p t i o n ( ) {

4 s u p e r( "O d e n o m i n a d o r na d i v i s ão i n t e i r a tem v a l o r z e r o " ) ;

5 }

6 }

7

8 p u b l i c c l a s s T e s t e D i v i s a o { 9

10 p u b l i c d o u b l e d i v i s a o (d o u b l e num , i n t den ) t h r o w s D i v i d e B y Z e r o E x c e p t i o n {

11 i f ( den == 0 ) {

12 t h r o w new D i v i d e B y Z e r o E x c e p t i o n ( ) ;

13 }

14 r e t u r n num / den ;

15 }

16

17 p u b l i c v o i d u s a D i v i s a o (d o u b l e x , i n t y ) t h r o w s D i v i d e B y Z e r o E x c e p t i o n {

18 t r y {

19 . . . // cód i g o a n t e r i o r à i n v o c ação de d i v i são

20 d i v i s a o ( x , y ) ;

21 . . . // cód i g o p o s t e r i o r à i n v o c ação de d i v i são 22 } c a t c h ( D i v i d e B y Z e r o E x c e p t i o n d b z e ) {

23 . . . // t r a t a m e n t o p a r c i a l da e x c eção

24 t h r o w d b z e ;

25 }

26 }

27 }

Código 3.16 Definindo e sinalizando exceções.

O mesmo comandothrowpode ser utilizado para repassar uma exceção após sua captura – por exemplo, após um tratamento parcial da exceção (Código 3.16, linhas 17-26). Nesse caso, a informação associada à exceção (como o seu ponto de origem, registrado internamente no atributo do objeto que contém a pilha de invocações) é preservada.