Entrei em um debate entre alguns amigos e eu. Eles preferem exceções gerais como ClientErrorException
e ServerErrorException
com detalhes como campos da exceção, enquanto eu prefiro tornar as coisas mais específicas. Por exemplo, eu posso ter algumas exceções, como:
BadRequestException
AuthenticationFailureException
ProductNotFoundException
Cada uma delas foi criada com base no código de erro retornado da API.
Após as vantagens das exceções, isso parece idiomático para Java. No entanto, a opinião dos meus amigos não é exatamente incomum.
Existe uma maneira preferida em termos de legibilidade do código e usabilidade da API, ou realmente se resume apenas à preferência?
abstract
e generalizar classes de exceção com os métodos getter e, em seguida, fazer com que as granulares estendam as gerais. Por exemploAuthenticationFaliureException extends ClientErrorException
. Dessa forma, todo usuário pode escolher como gostaria de lidar com as exceções. É mais trabalho, obviamente. No entanto, ao escrever um aplicativo (em vez de uma biblioteca), é uma situação diferente IMHO. Nesse caso, eu não tornaria as exceções mais granulares do que você precisa, por uma questão de simplicidade.Respostas:
A principal diferença entre ter muitas classes de exceção diferentes e ter apenas algumas, com informações mais detalhadas no texto do erro (por exemplo), é que muitas classes de exceção diferentes permitem que o código de chamada reaja de maneira diferente a diferentes tipos de erros, enquanto possui apenas algumas classes facilitam o tratamento de todos os tipos de exceções de maneira uniforme.
Isso geralmente é uma troca. Pode ser atenuado até certo ponto usando herança (uma classe de exceção básica geral para os chamadores que desejam capturar e registrar tudo genericamente, e exceções derivadas dessa classe base para os chamadores que precisam de reações diferentes), mas mesmo isso pode produzir um muita complexidade desnecessária se você não tomar cuidado e seguir o princípio YAGNI. Portanto, a pergunta norteadora deve estar aqui:
Não existe uma solução única para isso, nenhuma "prática recomendada" que você possa aplicar em todos os lugares. A resposta a esta pergunta depende fortemente de que tipo de software ou componente você está projetando:
Em algum aplicativo, onde você ou a equipe tem toda a base de código sob seu controle?
ou algum componente reutilizável para terceiros, onde você não conhece todos os potenciais chamadores?
um aplicativo de servidor de execução longa, em que diferentes tipos de erros não devem interromper todo o sistema imediatamente e podem exigir diferentes tipos de mitigação de erros?
um processo de aplicação de curta duração em que é suficiente, em caso de erro, exibir uma mensagem de erro para o usuário e reiniciar o processo?
Portanto, quanto mais você souber sobre os potenciais chamadores do seu componente, melhor poderá decidir sobre o nível correto de detalhes para suas exceções.
fonte
A resposta depende de qual nível de relatório de erros estamos falando.
Em geral, concordo com seus amigos, você não deve torná-los mais granulares do que o necessário para transmitir a causa do problema.
Se houver uma exceção comum e bem conhecida para fazer referência a nulo (NullReferenceException), você não deve criar sua própria MyObjectIsNullException. Isso apenas acrescentaria uma camada de confusão para o intérprete humano, uma coisa adicional a aprender que não esclarece nada.
Somente quando sua exceção é tão especial que não existe uma predefinida que cubra a causa raiz, você deve criar sua própria.
No entanto, você não precisa parar por aí. O erro comum pode ocorrer em um dos seus componentes e você pode querer transmitir que houve um problema no seu componente . Portanto, não apenas o que deu errado, mas também onde. Em seguida, seria apropriado agrupar a primeira exceção em um MyComponentException. Isso lhe dará o melhor dos dois mundos.
Primeiro, ficará claro que seu componente teve problemas. Em uma alavanca mais baixa, a causa específica estaria na exceção interna.
fonte