UCAN forum

Primeiro Forum criado por Informáticos Angolanos, destinado à informáticos de todos os níveis, tendo como principal foco o ramo da PROGRAMAÇÃO.Tutoriais, Exposição de dúvidas, Notícias e muito mais...
 
InícioInício  CalendárioCalendário  FAQFAQ  BuscarBuscar  Registrar-seRegistrar-se  Conectar-seConectar-se  

Compartilhe | 
 

 Java - Throw & throws

Ver o tópico anterior Ver o tópico seguinte Ir em baixo 
AutorMensagem
Josemar Jobs

avatar

Masculino Número de Mensagens : 81
Idade : 28
Localização : Luanda-Angola
Data de inscrição : 05/05/2008

MensagemAssunto: Java - Throw & throws   Seg Maio 26, 2008 8:38 pm

Throw & throws
Considere um método que deve receber como parâmetro uma referência para um arranjo de arranjos representando uma matriz quadrada. O que deve ser feito se este método receber uma referência para um arranjo representando uma matriz que não seja quadrada? A linguagem Java tem uma boa disciplina para separar o que é convencionado como “normal e esperado” e o que é considerado “excepcional”. Tanto a Máquina Virtual quanto um programa podem (i) declarar ou “lançar” erros e exceções (via comando throw), tanto a Máquina Virtual quanto um programa podem (ii) tratar ou “apanhar” erros e exceções utilizando o comando try-catch e um programa pode ainda (iii) declarar que não trata erros e exceções.

As situações de erro e exceção são materializadas na forma de uma referência para uma instância de uma classe que representa o problema. Toda situação considerada de erro ou exceção corresponde ao arremesso ou lançamento (throw) de uma referência de uma instância de uma classe adequada.

A linguagem Java tem três classes notáveis: (i)String, (ii)Object e (iii)Throwable. A classe String é a única classe que tem literais (representação de constantes). A classe Object é a única que não estende nenhuma classe em sua definição. A classe Throwable é a única classe cujas instâncias diretas ou indiretas podem ter suas referências lançadas. A classe Throwable é pré-definida na linguagem Java, juntamente com várias outras classes definindo um grande número de categorias de erro. Os programadores Java, por convenção, caso queiram criar novas exceções devem estender a classe Exception que é uma subclasse de Throwable. Duas classes descendentes da classe Throwable podem ser consideradas especiais: a classe Error e a classe RuntimeException. A linguagem Java não obriga o programador a tratar os lançamentos de exceção envolvendo instâncias da classe Error, da classe RuntimeException e das classes delas derivadas, todos os outros lançamentos de exceção devem ser tratados pelo programador.

A Máquina Virtual Java lança referências para instâncias de maneira implícita utilizando as classes pré-definidas. O programador pode utilizar o comando throw de forma explícita. Quando o fluxo de controle atinge o comando throw <expressão>, a expressão é avaliada. Esta expressão corresponde, em geral à criação de um objeto e resulta numa referência, p. ex. throw new ErroDoTipoX();. A partir daí o fluxo de controle será desviado para uma cláusula catch apropriada de algum comando try-catch. O fluxo de controle segue a cadeia dinâmica dos Registros de ativação das invocações dos métodos, ou seja a execução de um método pode terminar (i) por que o fluxo de controle atingiu o final do método (return implícito, só pode ocorrer no caso de métodos do tipo void!), (ii) porque o fluxo de controle atingiu um comando return, ou (iii) porque foi executado um trow implícito ou explícito que não foi apanhado por um comando try-catch daquele método. A procura por uma cláusula catch apropriada propaga-se na direção do método main e, não havendo tratamento, para a MVJ, neste caso a execução do programa será finalizada, com mensagem de erro provida pela MVJ dizendo que uma exceção foi lançada sem que fosse apanhada.

A linguagem Java classifica os erros e exceções em dois grupos: (i) o grupo que obriga a verificação (checked) e (ii) o grupo que não obriga verificação (nonchecked). Até este ponto da disciplina sempre utilizamos programas lidando apenas com erros e exceções do grupo que não obriga a verificação.

Para lançar uma exceção com referência para uma instância das classes de verificação obrigatória a linguagem obriga o programador a declarar no cabeçalho do método quais as classes de exceção podem ter instâncias lançadas. Portanto, o formato completo do cabeçalho de definição de um método é:
<modificadores> <tipo> <nome>(<parametros>) throws <classes>
static void m() throws ErroDoTipoX, ErroDoTipoY, ErroDoTipoZ{
...
throw new ErroDoTipoX();
...
throw new ErroDoTipoY();
...
throw new ErroDoTipoZ();
}

Observe que a cláusula throws do cabeçalho de um método tem implicações na questão da definição da relação extends entre classes. Se o programador quiser estender a classe que contém o método m acima e se o programador quiser sobrepor o método m então o novo método terá de declarar o lançamento de instâncias das mesmas classes. Isso garante que um código que trabalha com a classe base trabalhará também com as classes derivadas.

O programador pode lidar com o lançamento de exceções de verificação obrigatória de duas maneiras. A primeira opção é utilizar um comando que pode dar origem à exceção dentro do bloco try de um comando try-catch definindo uma cláusula catch adequada. A segunda opção é utilizar a cláusula throws do cabeçalho de definição de um método.
O programador pode decidir não tratar naquele método uma exceção que exige verificação, mas a linguagem obriga o programador a avisar isto através da cláusula throws.

Os programas abaixo ilustram estes conceitos.


class tstthrow{
static int hexChar2int(char c) throws Exception{
if(c>='0'& c<='9') return c-'0';
if(c>='A'& c<='F') return c-'A'+10;
if(c>='a'& c<='f') return c-'a'+10;
throw new Exception("caractere nao e hexadecimal!");
}
public static void main(String[] args){
try{
int i=hexChar2int('G');
System.out.println("Tudo ok! i iniciou com:"+i);
}
catch(Exception p){
System.out.println("problema:"+p);
}
}
}


Observação: Exception não é a melhor classe para o caso do programa acima. Uma melhor opção seria o uso da classe IllegalArgumentException. Exercício: reescreva o programa acima substituindo a classe Exception pela classe IllegalArgumentException. Neste programa foi usada a classe Exception para poder ilustrar a diferença entre exceções que precisam ser declaradas na cláusula throws da declaração de um método. As subclasses da classe RuntimeException não precisam constar na cláusula throws! A classe IllegalArgumentException é uma subclasse da classe RuntimeException.

No programa acima o método hexChar2int para poder lançar uma instância da classe Exception e declara isso no seu cabeçalho. O método main não precisa declarar isso no seu cabeçalho porque a invocação do método hexChar2int está dentro do bloco try de um comando try-catch. O programa abaixo não compila:
class tstthrow{ /* este programa nao compila */
static int hexChar2int(char c) throws Exception{
if(c>='0'& c<='9') return c-'0';
if(c>='A'& c<='F') return c-'A'+10;
if(c>='a'& c<='f') return c-'a'+10;
throw new Exception("caractere nao e hexadecimal!");
}
public static void main(String[] args){
int i=hexChar2int('G');
System.out.println("Tudo ok! i iniciou com:"+i);
}
}

A tentativa de compilação do programa acima resulto no seguinte erro:
Exception must be caught, or it must be declared in the throws clause of this method.

Uma outra solução portanto, caso o programador não queira lidar com exceções utilizando o comando try-catch, é declarar que o método main pode lançar (ou deixar passar) lançamentos de instâncias da classe Exception:
class tstthrow{
static int hexChar2int(char c) throws Exception{
if(c>='0'& c<='9') return c-'0';
if(c>='A'& c<='F') return c-'A'+10;
if(c>='a'& c<='f') return c-'a'+10;
throw new Exception("caractere nao e hexadecimal!");
}
public static void main(String[] args) throws Exception{
int i=hexChar2int('G');
System.out.println("Tudo ok! i iniciou com:"+i);
}
}

Ou seja, não existem exigências com relação às exceções do grupo nonchecked. As demais exceções para serem lançadas devem ter suas classes listadas no cabeçalho do método lançador. Um método que invoca um outro método lançador de exceções checked deve se precaver através de um comando try-catch adequado ou então deve declarar que deixa passar os lançamentos.

A figura abaixo ilustra o relacionamento entre as exceções checked e nonchecked e a hierarquia de classes com raiz na classe Throwable. Os retângulos com nomes representam classes e os triângulos representam hierarquias de classes com classe “raiz” identificada pelo retângulo da ponta superior do triângulo. Na hierarquia de classes predefinida em Java a classe Throwable tem somente duas classes filhas (Error e Exception), mas um programador Java pode definir outras hierarquias a partir da Throwable (embora isso não seja recomendável). As classes e hierarquias cujo lançamento de instâncias seja de verificação obrigatória são identificadas na cor cinza.Todas as instâncias diretas e indiretas da classe Error e da classe RuntimeException são de verificação opcional. Todas as instâncias diretas e indiretas da classe Throwable, que não sejam as instâncias diretas e indiretas das classes Error e RuntimeException, são de verificação obrigatória.



A boa disciplina sobre a escolha de uma categoria de exceção/erro ser do tipo checked ou nonchecked relaciona-se à possibilidade de recuperação. Observe por exemplo que a indexação errada de um arranjo configura um problema de programação que não deveria ocorrer e portanto é dificil imaginar que isso deve ser algo recuperável: não sendo recuperável não obrigue o programador a cuidar disso, afinal se ele fez sua tarefa de forma correta isto não vai acontecer. Uma aplicação pode verificar que um dispositivo de armazenamento está disponível e em algum momento posterior este dispositivo pode não estar mais disponível: é razoável supor que uma aplicação queira se recuperar com relação a um dispositivo não disponível (por exemplo para salvar um arquivo em outro dispositivo!), daí obrigue o programador a cuidar desta categoria de erro!


--------------------------------------------------------------------------------



Quando é feito o lançamento de um erro/exceção e é encontrado um comando try/catch, as cláusulas catch são verificadas sequencialmente. As classes das cláusulas catch, caso tenham relacionamento, só podem aparecer da mais específica para a mais genérica:

class prog{
public static void main(String[] x){
try{
throw new MinhaExcecao();
}
catch(MinhaExcecao p){}
catch(Exception p){}
}
}
class MinhaExcecao extends Exception{}
O programa não compila se classes mais genéricas precedem classes mais específicas:

class prog{
public static void main(String[] x){
try{
throw new MinhaExcecao();
}
catch(Exception p){}
catch(MinhaExcecao p){}
}
}
class MinhaExcecao extends Exception{}




--------------------------------------------------------------------------------

Conforme foi dito acima ao ser executado um lancamento de erro/exceção o fluxo de controle faz uso dos registros de ativação e, na direção do registro de ativação mais recente para o registro de ativação mais antigo é procurado um comando try/catch que pegue o lançamento. O programa abaixo ilustra o retorno do fluxo de execução ao longo de execuções aninhadas de métodos. O método main() invoca o método m(), m() invoca o método o(), o() invoca o método p(), quando p() lança uma instância de exceção, o fluxo de controle não encontra um try/catch adequado em p(), destroi o registro de ativação de p() e procura um try/catch adequado no escopo do método que invocou p() [no caso método o()]. Não encontrando um try/catch adequado em o(), destroi o registro de ativação de o() e procura um try/catch adequado no escopo do método que invocou o(). Isto ocorre até que um “catch” apropriado seja encontrado, neste caso o try/catch do método main(). A única escrita é o println() do método main().

class tstcatch{
static void m()throws Exception{ n();System.out.println("m");}
static void n()throws Exception{ o();System.out.println("n");}
static void o()throws Exception{ p();System.out.println("o");}
static void p()throws Exception{ throw new Exception();}
public static void main(String[] x){
try{ m();}
catch(Exception p){
System.out.println("o fluxo de controle veio desde p()!");
}
}
}


--------------------------------------------------------------------------------



A sintaxe básica do comando try/catch (na verdade try/catch/finally!):
try{
<comandos que podem ou nao lançar exceções>
} catch(ExcecaoTipo1 parametro){
<tratamento da instância da classe ExcecaoTipo1>
} catch(ExcecaoTipo2 parametro){
<tratamento da instância da classe ExcecaoTipo2>
} ...
} finally{
<estes comandos serão excutados com ou sem lançamento de exceção>
}

Quando o fluxo de controle chega ao comando try/catch/finally o fluxo de controle passa a percorrer o bloco try. Se uma instância de classe de exceção é lançada cada cláusula catch é examinada e o parâmetro da cláusula catch "mais adequada" recebe a referência da instância lançada e o fluxo de controle passa a percorrer o bloco da cláusula catch. Nenhuma outra cláusula catch é executada! Se nenhuma cláusula catch for adequada o lançamento da exceção será verificado por comandos try externos. O bloco da cláusula finally é opcional, mas se estiver presente será sempre executado não importando se o bloco try terminou a execução de forma normal (e não houve bloco catch executado) ou se o bloco try terminou de forma excepcional. Isto pode gerar situações curiosas:
class tstfinally{
public static void main(String[] arg){
System.out.println(desafio());
}
static int desafio(){
try{ return 1;}
finally{ return 2;}
}
}
O que é impresso pelo programa acima? (edite, compile e execute!) Existe uma "razão" do fluxo de controle entrar no bloco finally, em particular esta razão pode ser pelo fato de ter sido executado um comando return que termina a execução do bloco try de forma não excepcional. Ao entrar no bloco finally a "razão" original pode ser "esquecida". Por outro lado se o fluxo de execução for desviado para o método exit() da classe System o fluxo não retorna!
class tstcatch{
public static void main(String[] x){
try{ System.exit(0);}
finally{
System.out.println("o fluxo de execução não vem aqui!");
}
}
}

fui,...... sempre a study
Voltar ao Topo Ir em baixo
Ver perfil do usuário
 
Java - Throw & throws
Ver o tópico anterior Ver o tópico seguinte Voltar ao Topo 
Página 1 de 1
 Tópicos similares
-
» carregando mapas como Java
» Usei um código java mas parênteses aparecem no meio do post
» Codigo owned de novo , mesmo com o codigo java ativo!
» Chamar código java script
» Pac-man em JAVA

Permissão deste fórum:Você não pode responder aos tópicos neste fórum
UCAN forum :: Programação e Informática Geral :: JAVA :: JAVA Avançado-
Ir para: