Checked e unchecked exceptions nas camadas

Lendo o Mundo Java 33, sobre EJBs e Spring, na parte de controle de transações, fala que ambas as tecnologias fazem rollback da transação quando encontram unchecked exceptions, mas com as checked deixam rolar, supõem que o desenvolvedor queria que isso aconteça.

Fiquei pensando no caso de uma exceção na camada de persistência, como uma SQL ou IOException, normalmente não são esperadas pela aplicação.

A camada deveria tratar esses erros e transformá-los em erros do sistema quando a requisição voltar para a camada que a chamou? Acho meio infeliz dar um catch e um throw logo depois só pra transformar a exceção. O que tem de “checado” numa exceção dessas?

[quote=Bruno Laturner]Lendo o Mundo Java 33, sobre EJBs e Spring, na parte de controle de transações, fala que ambas as tecnologias fazem rollback da transação quando encontram unchecked exceptions, mas com as checked deixam rolar, supõem que o desenvolvedor queria que isso aconteça.

Fiquei pensando no caso de uma exceção na camada de persistência, como uma SQL ou IOException, normalmente não são esperadas pela aplicação.

A camada deveria tratar esses erros e transformá-los em erros do sistema quando a requisição voltar para a camada que a chamou? Acho meio infeliz dar um catch e um throw logo depois só pra transformar a exceção. O que tem de “checado” numa exceção dessas?[/quote]

oi

aqui o cara que organizou o tratamento de excessões pensou que devemos sempre tratar todas as excessões checked possíveis e só em ultimo caso lançar uma unchecked

por exemplo, na camada DAO, eu teria algo assim

try { // consulta aqui } catch(NonUniqueResultException e) { return null; } catch(EntityNotFoundException e) { return null; } catch(HibernateException e) { logger.log(Level.SEVERE, e.getMessage()+"\n"+e); throw new RuntimeException(e); }

assim eu consigo garantir que se um runtime ocorrer é porque eu não encontrei a entidade ou ela não era única… na minha opinião, quanto menos unchecked você retornar, principalmente para uma aplicação J2EE, melhor

abs

Olá Bruno,

Esse é um bom ponto. Muitos consideram que essas exceptions (SQL, IO, por exemplo), não deveriam ser checadas. É um erro de projeto da linguagem.

Por isso, somos praticamente obrigados a fazer o que você falou. Tratar para transformar.

[]´s

Olá Bruno,

Esse é um bom ponto. Muitos consideram que essas exceptions (SQL, IO, por exemplo), não deveriam ser checadas. É um erro de projeto da linguagem.

Por isso, somos praticamente obrigados a fazer o que você falou. Tratar para transformar.

[]´s[/quote]

É, tava pensando a mesma coisa, erro de projeto. Antes de ver a revista já até tinha lido um pouco sobre o assunto, em especial a Trilogia de Tratamento das exceções no Java do Luca (Parte 1 - Parte 2 - Parte 3).

É… complicado.

O Sérgio também tem vários artigos:
Exceções: Conceitos
Exceções: Boas práticas, más práticas
Exceções: Classe Utilitárias

Li um pouco na parte de Boas práticas, em Camadas e exceções

Bem, é a regra de que cada camada sabe tratar o que vem de baixo, seja retorno ou exceção, enquanto a que tá em baixo nem sabe que a de cima existe, então mesmo junto com essas novas regras de un/checked exceptions que outros frameworks usam, parece que tem q tratar tudo. Ou pelo menos transformar mesmo.

Um ou dois tostões sobre o assunto…

http://leandrosilva.com.br/2008/08/12/cuidado-com-suas-excecoes

[quote=Bruno Laturner]

O Sérgio também tem vários artigos:
Exceções: Conceitos
Exceções: Boas práticas, más práticas
Exceções: Classe Utilitárias

Li um pouco na parte de Boas práticas, em Camadas e exceções

Bem, é a regra de que cada camada sabe tratar o que vem de baixo, seja retorno ou exceção, enquanto a que está em baixo nem sabe que a de cima existe, então mesmo junto com essas novas regras de un/checked exceptions que outros frameworks usam, parece que tem q tratar tudo. Ou pelo menos transformar mesmo.[/quote]

Em inglês existe o termo “handle” (manipular) que é diferente de resolver.
Quando uma camada recebe uma exceção da camada inferior que ela não sabe resolver, mesmo assim ela têm que a manipular (handle). Em bom protugues, ela tem que fazer o try-catch. Mas isso apenas para a encapsular em uma outra Exceção da própria camada.

Por exemplo, quando vc comunica com o banco de dados via jdbc a exceção que é retornada é SQLException, sempre. Mesmo quando o erro é um IOException ( por exemplo, connectino timeout).

A dificuldade do encapsulamento advém do fato que simplesmente jogar todas as exceções das camadas inferirors no mesmo bolo não ajuda nada. ( por exemplo um SQLException de “sem conexão” deveria ser um exception de uma classe filha de SQLException). Seguindo a boa prática “Seja especifico” vc deve encapsular as exceções mais baixas em exceções da camada mas de forma categorizada. Todas elas herdam da exceção “mãe” da camada mas são mais especificas.

Por exemplo, numa camada de acesso a dados genérica poderíamos ter a exceção mae “DataAcessException” e como filhas poderíamos ter “ConnectionException” , “DatabaseNotFoundException” , “AutenticationException” , “DuplicateRegistryException” e “ConcurrencyException”. Todas elas são DataAcessException, mas todas significam erros de categorias diferentes.

finalmente as classe de exceção mãe deve ser filha de RuntimeException. Apenas deve ser filha de Exception se a camada representa algum subsistema fora do escopo da aplicação. ( por exemplo IOException é checked porque representa o o subsistema de arquivos do OS e a SQLException o subsistema de banco de dados)

Eu sou daqueles que acham que as Checked Exceptions do Java nunca deveriam existir pois mais atrapalham que ajudam. De qualquer forma isso é opinião e há controvérsias.

Eu discordo. Acho que checked exceptions são importantes, apenas foram usadas da forma errada desde o começo da linguagem.

Há uma RFE que acho legal atacando exatamente este problema da linguagem:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6534270

[quote=victorwss]…
Eu discordo. Acho que checked exceptions são importantes, apenas foram usadas da forma errada desde o começo da linguagem.
…[/quote]

Concordo plenamente!

O pessoal usa certas coisas de maneira exagerada/errada e com isso aquilo que foi usado dessa forma é visto como uma porcaria, etc

Eu discordo. Acho que checked exceptions são importantes, apenas foram usadas da forma errada desde o começo da linguagem.

Há uma RFE que acho legal atacando exatamente este problema da linguagem:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6534270[/quote]
Se você acha tão importante, apresente aqui um exemplo de uma situação que não seja possível resolver com unchecked exceptions ou seja necessário muito trabalho para alcançar o mesmo resultado.

[quote=ASOBrasil][quote=victorwss]…
Eu discordo. Acho que checked exceptions são importantes, apenas foram usadas da forma errada desde o começo da linguagem.
…[/quote]

Concordo plenamente!

O pessoal usa certas coisas de maneira exagerada/errada e com isso aquilo que foi usado dessa forma é visto como uma porcaria, etc[/quote]
A questão aqui não foi usar de maneira errada, o que eu concordo que aconteceu bastante, mas a questão é que é inútil a existência das checked exceptions, mais uma vez na minha opinião. Caso você ache o contrário, apresente algum bom argumento para tal, assim como pedi ao colega acima.

E pra finalizar, eu posso tratar uma unchecked exception se eu quiser, eu só não sou forçado a faze-lo …

[]s

Ok, como vc lidaria se SQLException fosse unchecked?

Quer um bom argumento!? Um exemplo!? Então vamos lá:

Que tal o InvocationTargetException dos métodos de reflection? Qualquer método chamdo por reflection pode lançar uma exceção, e simplesmente lançá-la para cima de qualquer jeito pode ser desastroso (afinal, você normalmente não sabe o que significa essa exceção). Assumir que o método nunca falhará normalmente significa uma falha de projeto, logo nada mais normal do que ser obrigado a tratar a exceção.

Um outro exemplo (usando aquela cláusula suppresses sugerida na RFE):

[code]/**

  • Liga o aparelho que mede a incidência de luz solar

  • @throws EstaChovendoException Se estiver chovendo, o aparelho detecta isso

  • e retorna um status de falha indicando chuva.
    */
    public void ligarAparelhoLuzSolar()
    suppresses IOException, EstaDeNoiteException
    throws EstaChovendoException
    {
    // Se ocorrer uma falha de comunicação, não há muito o que fazer.
    // Lança o IOException não verificado.

    // Se for de noite, isso é um erro de programação,
    // deve-se verificar se não é noite antes de chamar este método.

    // Mas, quem chamar este método, deve esperar uma possível falha porque
    // esteja chovendo. Não podemos separar isso em um método estaChovendo()
    // porque a comunicação com o aparelho é muito cara.
    }[/code]

Ok, como vc lidaria se SQLException fosse unchecked?[/quote]
Já experimentou um Try-Cath? Bem basico e funciona que é uma beleza.

Você não acha mais simples tratar o que for necessário, ao invés de tentar ignorar o que você não quer tratar?

Ok, como vc lidaria se SQLException fosse unchecked?[/quote]
Já experimentou um Try-Cath? Bem basico e funciona que é uma beleza.[/quote]

Sim, mas ai eu opto por faze-lo: o compilador não me obriga.

Ok, como vc lidaria se SQLException fosse unchecked?[/quote]
Já experimentou um Try-Cath? Bem basico e funciona que é uma beleza.[/quote]

Sim, mas ai eu opto por faze-lo: o compilador não me obriga.[/quote]
Vamos imaginar a seguinte cenário:

  • Objeto A envia uma mensagem ao Objeto B.
  • Objeto B retorna uma exception para o Objeto A como resposta a sua mensagem.

Eu suponho que o Objeto A que tenha a noção se esse erro ele quer/vai/precisa tratar de alguma forma. Portanto, me parece mais lógico que ele não seja obrigado a tratar. Caso contrário, O Objeto que recebeu a mensagem (no caso Objeto B) está tomando uma decisão que não lhe cabe(ou se preferir, o Objeto B está impondo uma decisão ao Objeto A).

Mas nesse caso o objeto A sabe do comportamento do objeto B pelo contrato e B parece ser incapaz de tratar um eventual erro, sem falar que B poderia ser, então, refatorado para B’ e trabalhar como vc achar melhor. Enfim é só uma observação.

Sim, eu entendi o que você quis dizer, mas qual seria o outro caso?

[quote=Emerson Macedo]…
Vamos imaginar a seguinte cenário:

  • Objeto A envia uma mensagem ao Objeto B.
  • Objeto B retorna uma exception para o Objeto A como resposta a sua mensagem.

Eu suponho que o Objeto A que tenha a noção se esse erro ele quer/vai/precisa tratar de alguma forma. Portanto, me parece mais lógico que ele não seja obrigado a tratar. Caso contrário, O Objeto que recebeu a mensagem (no caso Objeto B) está tomando uma decisão que não lhe cabe(ou se preferir, o Objeto B está impondo uma decisão ao Objeto A).[/quote]

Exatamente como o peczenyj falou, você coloca checked exceptions se você quiser! E se eu definir que o método que chamar a minha implementação deva tratar aquela exception então eu posso definir explicitamente e pronto! Entendeu que o negócio é opcional? A linguagem é aberta para isso e ela permite que cada pessoa trabalhe da maneira que achar melhor. Assim como você pode deixar tudo como “unchecked” porque você acha que é a melhor solução.

SQLException é um típico caso em que a API não foi bem projetada. Erros como SQLException, HibernateException, IOException, e etc são erros que não tem como ser remediado e geralmente o usuário do sistema não tem controle sobre a situação que gerou o erro, diferente de DataDeVencimentoInvalidaException ou DataSelecionaEhDiaUtilException (nome horrivel, eu admito).

Checked exceptions não devem ser tratadas na maioria dos casos, se você esta num ambiente “gerenciado” deixe seu application server\servlet container logar a exceção, configure o logger do servidor de forma correta e coerente com a forma como sua equipe lida com erros em produção e mostre uma tela de erro feliz para o usuário.

[quote=ASOBrasil][quote=Emerson Macedo]…
Vamos imaginar a seguinte cenário:

  • Objeto A envia uma mensagem ao Objeto B.
  • Objeto B retorna uma exception para o Objeto A como resposta a sua mensagem.

Eu suponho que o Objeto A que tenha a noção se esse erro ele quer/vai/precisa tratar de alguma forma. Portanto, me parece mais lógico que ele não seja obrigado a tratar. Caso contrário, O Objeto que recebeu a mensagem (no caso Objeto B) está tomando uma decisão que não lhe cabe(ou se preferir, o Objeto B está impondo uma decisão ao Objeto A).[/quote]

Exatamente como o peczenyj falou, você coloca checked exceptions se você quiser! E se eu definir que o método que chamar a minha implementação deva tratar aquela exception então eu posso definir explicitamente e pronto! Entendeu que o negócio é opcional? A linguagem é aberta para isso e ela permite que cada pessoa trabalhe da maneira que achar melhor. Assim como você pode deixar tudo como “unchecked” porque você acha que é a melhor solução.
[/quote]
Curioso é você definir que quem manda mensagem para teu objeto deva tratar alguma coisa. Eu acho isso péssimo. Acho muito mais lógico eu notifica-lo que algum problema aconteceu (i.e. lançando uma exception) e ele decidir qual ação vai tomar dado a mensagem de retorno. É o caso da SQLException. Quem a criou “definou” que agente tinha que tratar e no final das contas agente viu no que deu.