1. http://www.totalcross.com/blog
Como manipular exceções em Java
Uma das funcionalidades que tornam o Java uma linguagem robusta em relação às outras linguagens é
o conceito de exceção (Exceptions). Em outras linguagens, o uso ou não de exceções é opcional, mas
no Java é obrigatório. Entretanto, a maioria das pessoas fazem mal uso dessa funcionalidade que é
crucial no desenvolvimento de qualquer programa.
As exceções foram criadas com o objetivo principal de forçar o tratamento de um erro. Existem dois
tipos de exceção:
a. Casos em que o erro pode ocorrer e você está ciente disso
b. Casos em que o erro ocorre mas você não está preparado
Um exemplo de exceção do primeiro tipo é a FileNotFoundException, quando o arquivo não existe. São
casos em que você sabe que o erro pode ocorrer, e em geral os trata localmente, no mesmo lugar onde
o método que dispara a exceção é chamado.
As exceções do caso b, em que você não espera que ocorram, é que são as principais a serem tratadas
no programa, e a forma correta de se tratar elas é o que diferencia um programa robusto de um
programa capenga.
Existem 3 formas de tratar uma exceção:
1. try { … } catch (Exception e) {}
2. try { … } catch (Exception e) {e.printStackTrace();}
3. try { … } catch (Exception e) {tratar(e);}
A primeira forma é a pior de todas, pois você engole a exceção e o programa vai continuar funcionando
em um estado em que algo vai explodir mais a frente.
A segunda forma é um pouco menos pior, pois você ao menos imprime ela no console, e funciona muito
bem no ambiente de desenvolvimento. O problema é que em geral não é possível pegar o stack trace de
um programa em campo.
A terceira forma é a ideal, pois você está tratando a exceção. Mas qual é a melhor forma de tratar ela? O
ideal, é usar algo como o código abaixo:
public static void logException(Throwable t)
{
t.printStackTrace();
if (!Settings.onJavaSE)
try
{
File f = new File(Settings.platform.equals(Settings.ANDROID) ? “/sdcard/tcerror.log” :
“device/tc_error.log”,File.CREATE);
f.setPos(f.getSize());
String m = t.getMessage();
String c = t.getClass().getName();
String s = Vm.getStackTrace(t);
f.writeBytes(new Time().getSQLString());
f.writeBytes(“Class: “+c);
if (m != null) f.writeBytes(“Message: “+m);
f.writeBytes(“Stack trace: n”);
f.writeBytes(s);
f.close();
}
catch (Throwable tt)
{
tt.printStackTrace();
}
}
2. Nesse método, a exceção é impressa no console mas também é guardada em um arquivo, sendo que no
Android usamos o cartão de memória, e nas outras plataformas, o diretório da aplicação. E o que fazer
com esse arquivo? A melhor opção é enviar ele por email para sua empresa, assim você consegue
corrigir um erro sem que o usuário lhe comunique.
Então, supondo que você colocou o método acima na classe Utils, o tratamento ficaria assim:
3. try { … } catch (Exception e) {Utils.handleException(e);}
Ótimo, mas ainda resta um problema para exceções do tipo b, que é tão grave quanto ignora-las: ONDE
tratar a exceção?
A resposta para esse problema é: dispare a exceção para cima, até onde não conseguir mais. No
TotalCross, esses lugares são em geral dois: o construtor de uma classe qualquer que você não possa
fazer um “throws Exception”, ou no método onEvent. Por exemplo, um método onEvent ficaria assim:
public void onEvent(Event e)
{
try
{
if (e.target == ControlEvent.PRESSED)
…..
}
catch (Throwable t)
{
Utils.handleException(t);
}
}
Então, todos os métodos chamados no onEvent teriam que ter na assinatura: throws Exception.
Fazendo assim, disparando a exceção para cima e tendo um método único para tratar as exceções que
são realmente exceções (e não algo que é esperado), seu programa ficará muito mais robusto e seu
custo de suporte cairá substancialmente.
2