Vamos considerar a situação em que você tem o código fornecido de:
public void delete() throws IOException, SQLException { // Non-Compliant
/* ... */
}
O perigo aqui é que o código que você escreve para chamar delete()
terá a seguinte aparência:
try {
foo.delete()
} catch (Exception e) {
/* ... */
}
Isso também é ruim. E será detectado com outra regra que sinaliza a captura da classe Exception básica.
A chave é não escrever código que faça você querer escrever código incorreto em outro lugar.
A regra que você está encontrando é bastante comum. O Checkstyle tem em suas regras de design:
ThrowsCount
Restrições lança instruções para uma contagem especificada (1 por padrão).
Fundamentação da petição: Exceções fazem parte da interface de um método. Declarar um método para lançar muitas exceções com raízes diferentes torna oneroso o tratamento de exceções e leva a práticas de programação ruins, como escrever código como catch (Exception Ex). Essa verificação força os desenvolvedores a colocar exceções em uma hierarquia, de modo que, no caso mais simples, apenas um tipo de exceção precise ser verificado por um chamador, mas qualquer subclasse pode ser capturada especificamente, se necessário.
Isso descreve precisamente o problema, qual é o problema e por que você não deve fazê-lo. É um padrão bem aceito que muitas ferramentas de análise estática identificarão e sinalizarão.
E embora você possa fazer isso de acordo com o design da linguagem, e às vezes seja a coisa certa a fazer, é algo que você deve ver e imediatamente dizer "hum, por que estou fazendo isso?" Pode ser aceitável para código interno, onde todos são disciplinados o suficiente para nunca catch (Exception e) {}
, mas mais frequentemente do que nunca , vi pessoas cortando cantos, especialmente em situações internas.
Não faça as pessoas que usam sua classe desejarem escrever códigos incorretos.
Devo salientar que a importância disso é diminuída com o Java SE 7 e posterior, porque uma única instrução catch pode capturar várias exceções ( capturando vários tipos de exceção e relendo exceções com verificação de tipo aprimorada do Oracle).
Com o Java 6 e anterior, você teria um código parecido com:
public void delete() throws IOException, SQLException {
/* ... */
}
e
try {
foo.delete()
} catch (IOException ex) {
logger.log(ex);
throw ex;
} catch (SQLException ex) {
logger.log(ex);
throw ex;
}
ou
try {
foo.delete()
} catch (Exception ex) {
logger.log(ex);
throw ex;
}
Nenhuma dessas opções com o Java 6 é ideal. A primeira abordagem viola o DRY . Vários blocos fazendo a mesma coisa, repetidamente - uma vez para cada exceção. Deseja registrar a exceção e repeti-la novamente? Está bem. As mesmas linhas de código para cada exceção.
A segunda opção é pior por vários motivos. Primeiro, significa que você está capturando todas as exceções. Ponteiro nulo é pego lá (e não deveria). Além disso, você está refazendo novamente o Exception
que significa que a assinatura do método seria deleteSomething() throws Exception
apenas uma bagunça na pilha, pois as pessoas que usam seu código agora são forçadas a fazê -lo catch(Exception e)
.
Com o Java 7, isso não é tão importante porque você pode:
catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
Além disso, a verificação de tipo, se um não pegar os tipos de exceções sendo lançadas:
public void rethrowException(String exceptionName)
throws IOException, SQLException {
try {
foo.delete();
} catch (Exception e) {
throw e;
}
}
O verificador de tipos reconhecerá que e
pode ser apenas do tipo IOException
ou SQLException
. Ainda não estou muito entusiasmado com o uso desse estilo, mas ele não está causando um código tão ruim quanto no Java 6 (onde forçaria você a ter a assinatura do método como a superclasse que as exceções estendem).
Apesar de todas essas mudanças, muitas ferramentas de análise estática (Sonar, PMD, Checkstyle) ainda estão aplicando os guias de estilo do Java 6. Não é uma coisa ruim. Costumo concordar com um aviso de que eles ainda devem ser aplicados, mas você pode alterar a prioridade neles para maior ou menor de acordo com a prioridade da equipe.
Se exceções deve ser verificada ou não ... isso é uma questão de g r um e uma t debate que se pode facilmente encontrar inúmeros posts ocupando cada lado do argumento. No entanto, se você estiver trabalhando com exceções verificadas, provavelmente evite lançar vários tipos, pelo menos no Java 6.