segunda-feira, 4 de junho de 2007

Tratamento de exceções - Parte 2 – Mudanças no conceito de uso das exceções

Continuação de Tratamento de exceções - Parte 1 – Um pouco de história

Tendência mais moderna de tratar as exceções no Java.

Vamos começar dando a palavra a um dos criadores do Java, James Gosling em uma entrevista publicada em setembro de 2003 ao Bill Venners da artima:

“Lots of newbie's coming in from the C world complain about exceptions and the fact that they have to put exception handling all over the place—they want to just write their code. But that's stupid: most C code never checks return codes and so it tends to be very fragile. If you want to build something really robust, you need to pay attention to things that can go wrong, and most folks don't in the C world because it's just too damn hard.

One of the design principles behind Java is that I don't care much about how long it takes to slap together something that kind of works. The real measure is how long it takes to write something solid. ”

Como disse no blog anterior, quando aprendi Java, não questionei muito o modelo de tratamento de exceções e era um newbie vindo do mundo C. Mas, como quase todo mundo, achei um pouco complicado a obrigação tratar de exceções das classes da API do Java. Como exemplo de exceções difíceis de entender porque eram checked, lembro de algumas das exceções das versões antigas do JDBC, que ao meu ver deveriam ser consideradas como erros irrecuperáveis.

Naquela época não havia uma boa fonte para entender de forma clara como fazer tratamento de exceções como é o capítulo 8 do livro Effective Java do Joshua Bloch ou o artigo Lidando com Exceptions do nosso amigo Fábio Kung.

O Fábio abordou com muita propriedade o uso das unchecked exceptions e das checked exceptions de acordo com as recomendações do Java pois afinal a Caelum onde dá aulas, entre outras coisas, prepara alunos para certificação Java.

Vamos ver a recomendação oficial da Sun para usar as unchecked exceptions:

No fim está escrito:

“Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.”

Na visão dos tutoriais oficiais do Java, unchecked exceptions devem ser usadas só para os erros.

Este assunto das exceções do Java já causou muita briga e com certeza é um dos mais controversos da linguagem. Como já disse antes, nenhuma outra linguagem adota as checked exceptions.

São muitas as críticas em cima das checked exceptions do Java. Alguns autores as abominam e recomendam procedimentos alternativos para transformar ou embalar algumas delas em unchecked exceptions. Uma busca no google mostra que a discussão do assunto é interminável.

No meu caso, ao contrário de ter a visão newbie e estúpida citada pelo Gosling, talvez apenas não tenha enxergado com muita profundidade que as coisas poderiam ser de outro jeito e as aceitei sem discutir. Assim, minha primeira reação foi de surpresa quando li as primeiras críticas sobre as recomendações de uso das checked e unchecked exceptions. Algumas das reclamações partiram de gente muito influente na comunidade Java e causaram bastante polêmica.


O primeiro autor que vi se insurgindo contra as checked exceptions foi o Bruce Eckel, autor do livro Thinking in Java disponível para download. Na 3ª edição lançada em dezembro de 2002, no capítulo 9 Error Handling with Exceptions, vejam o título Perspectives. Nele o Bruce escreve bastante contra as checked exceptions, apesar de que na minha opinião, não resume claramente porque elas não foram uma boa idéia. Ele cita que o Martin Fowler pensava o mesmo e atribui ao Fowler a seguinte frase: “...on the whole I think that exceptions are good, but Java checked exceptions are more trouble than they are worth”. No mesmo capítulo sob o título Converting checked to unchecked exceptions há um exemplo de um wrapper para “desligar” as checked exceptions. Ver também:
http://mindview.net/WebLog/log-0025
http://www.mindview.net/Etc/Discussions/CheckedExceptions

O segundo a me alertar foi para ter cuidado com o uso delas foi Rod Johnson no livro de 2003, J2EE Design and Development. É um ótimo livro e para mim, o capítulo 4 é leitura recomendada para qualquer desenvolvedor. O capítulo 4 pode ser baixado em http://www.theserverside.com/tt/articles/article.tss?l=RodJohnsonInterview

Neste capítulo 4, sob o título Exception handling – Checked or Unchecked Exceptions, ele tece importantes considerações e diz que o uso de checked exceptions acarreta alguns problemas tais como:
  • Aumentar o tamanho do código,
  • Torna o código mais difícil de ler
  • Incentivar o empacotamento e relançamento de exceções que deveriam interromper o processamento
  • Fragilizar a assinatura dos métodos
  • Não funcionar bem com interfaces
O Rod é menos radical que o Bruce e acredita que há lugar para as checked exceptions. Porém não recomenda seu uso, a menos que se possa lidar com o problema dentro da lógica do sistema, como por exemplo um limite de gastos excedido em uma dada compra. Na dúvida sobre o que usar, sugere optar por unchecked exceptions. O seu framework Spring provê uma infra-estrutura baseada em unchecked exceptions para encapsular as inadequadas checked exceptions do JDBC e de versões antigas do Hibernate. Mas em uma das famosas brigas sobre este assunto nas discussões do TheServerSide, comentando a entrevista do James Gosling, ele escreveu:

“I actually like the fact that Java has checked exceptions. I use them to enforce callers to react to recoverable conditions. I think I would miss that in C#. It's just that I see an important role for unchecked exceptions as well.”


Acho que devo citar também a entrevista do Anders Hejlsberg na artima com o título The Trouble with Checked Exceptions onde ele defende porque o C# não adotou as checked exceptions.

Repito que durante muitos anos usei as checked exceptions sem maiores questionamentos. Talvez alguns de vocês ainda tenham a mesma posição. Mas é sintomático o que vem acontecendo:

  • No EJB até a versão 2.1, era necessário capturar ou lançar um monte de exceções sendo algumas delas de pouco significado. Definir o local para fazer o tratamento correto das exceções era uma das dificuldades de usar os já complicadíssimos EJBs. Havia também uma diferença de conceito entre as exceções unchecked e checked em que nestas últimas, o container não fazia roll back e era feito o commit da transação com erro.
  • Com o modelo de POJOs do EJB 3.0 estas questões ficaram mais simples. E das 16 exceções do EJB 3.0, 11 são do tipo unchecked
  • No EJB 3.0 apareceu a anotação @ApplicationException para indicar a política de roll back para exceção a ser lançada por erro de lógica do negócio em contraposição aos erros do sistema. Antigamente isto era papel das checked exceptions.
  • No Hibernate anterior a versão 3.0, todas as exceções lançadas eram checked. Isto foi feito influenciado pelo JDBC que somente lança este tipo. Mas exceções em operações de bases de dados em geral são erros fatais e assim muita gente fazia como o Spring e as empacotava como subtipo de RuntimeException que é unchecked. O Hibernate da versão 3.0 em diante só lança unchecked exceptions.
  • No JPA as exceções são todas unchecked possivelmente por influência da turma do Hibernate, do Toplink e do JDO que também são unchecked
  • A API do JSF se baseia em unchecked exceptions enquanto outras mais antigas como Servlets e JMS, só tem checked exceptions
  • A API java.io, seguindo o mau modelo do JDBC, usa checked exceptions enquanto o java.nio usa unchecked
  • O JDBC 4.0 que saiu com o Java 6 não mudou o conceito de checked para unchecked como muitos gostariam. Mas deu uma bela repaginada nas suas exceções permitindo mostrar erros um pouco mais significativos.

Acho que poderia encontrar mais exemplos. A lista acima mostra que o entendimento das exceções mudou, mesmo dentro da Sun. No mínimo se pode dizer que antigamente se abusava do uso das checked exceptions e que agora as novas APIs as usam menos ou usam melhor como no JDBC 4.0 e no EJB 3.0.

Se até a Sun está rediscutindo o uso das exceptions, então é claro que definir uma política coerente para tratamento das exceções deve ser motivo de discussão dentro das equipes de projeto para que esta importante facilidade do Java seja bem usada.

Sem regras claras, programadores simples mortais como nós, às vezes perdem a paciência com tanta exceção para tratar e acabam esquecendo de gravar em log. Isto é tão ruim que o Rodrigo Kumpera, cansado de tanto encontrar esta falha por aí, a denominou de Exception hidding e a incluiu no excelente texto Métrica definitiva da qualidade de um projeto J2EE.

As recomendações do Fabio Kung são um ótimo ponto de partida para as equipes que ainda não criaram suas próprias regras. E quem usa regras antigas, deve fazer como a Sun e o Gavin King do Hibernate e reavaliar como elas são aplicadas atualmente na prática.

No próximo blog vamos ver o que escrevem por aí sobre a remoção das checked exceptions do Java.

3 comentários:

Unknown disse...

Excelente post, Luca. Sinto com se tivesse acabado de sair de uma aula sobre tratamento de excessões.

Você linkou para um monte de artigos legais, mas acho que mais estes dois não fariam mal:
Effective Java Exceptions do Barry Ruzek no portal da BEA, de 2006. E esta coluna do Brian Goetz, de 2005

Luca Bastos disse...

Rafael

Na verdade eu considerei colocar mais links, inclusive estes dois que você lembrou. Não o fiz para não me perder citando muitos links e também pela existência do texto em português do Fábio.

Mas agradeço muito você ter lembrado deles.

Anônimo disse...

A gente critica, com 10 anos de estrada, problemas que ninguém previa 10 anos atrás. O problema não são as checked exceptions em si e sim o fato de que elas foram usadas (JDBC e java.io, muito bem citadas) onde unchecked exceptions eram mais apropriadas.

Quem sou eu

São Paulo/Paraty, SP/RJ, Brazil
Engenheiro estrutural COPPE/UFRJ por formação, desenvolvedor Java por experiência e poeta se sobrasse tempo