Design da hierarquia de exceção

9

Na minha empresa, estamos construindo um aplicativo da web contendo serviços centrais de servidor que nós mesmos projetamos e depois especificamos como interfaces. Ou seja, as interfaces são específicas de aplicativos e, em seguida, são implementadas com bibliotecas de terceiros, que podemos alterar com o tempo. Quando se trata de exceções, percebi que as exceções lançadas por nossos serviços devem ser nossas próprias exceções específicas de aplicativos, em vez de exceções específicas de implementação.

Agora, estou me perguntando como nossas exceções devem ser estruturadas e relacionadas entre si.

Primeiro, considere uma exceção genérica MyAppException. Essa exceção indica que algo inesperado deu errado e a melhor coisa que podemos fazer é exibir uma mensagem para o usuário dizendo que algo deu errado e que estamos trabalhando nisso. O erro pode ser que o banco de dados travou ou algo parecido. Essa exceção seria praticamente lançada de todos os métodos que trabalham com o banco de dados.

Em segundo lugar, considere uma exceção MyAppDuplicateException. Essa exceção indica que o usuário tentou salvar algo no banco de dados que já estava lá. Aqui, podemos exibir uma mensagem de erro muito mais específica e essa exceção é lançada apenas nos métodos que inserem ou atualizam linhas do banco de dados.

O aplicativo também pode conter outras exceções semelhantes a MyAppDuplicateExceptionoutras situações de erro esperadas. Ex MyAppNotFoundExceptionetc ...

Agora às minhas perguntas:

  1. As outras exceções devem se estender MyAppException? Na verdade, não vejo razão para isso, acabei de vê-lo em muitos lugares e me pergunto se há um objetivo nisso. A desvantagem disso, como eu vejo, é que uma declaração de tentativa / captura não precisa se preocupar com a exceção específica nesse caso. Ele pode capturar apenas a exceção principal e, por isso, não precisa lidar com o erro específico, que era praticamente o ponto de ter a exceção específica.
  2. Se as outras exceções não se estenderem MyAppException, deve MyAppExceptionser um java.lang.RuntimeException? Isso não exigiria a execução de código para capturá-lo, o que para mim parece natural, pois o objetivo da exceção é dizer que algo desconhecido aconteceu e que o código em execução não é esperado para lidar com isso. O código no ponto de entrada da solicitação ainda pode ter uma instrução try / catch que captura MyAppExceptione garante que uma mensagem seja exibida para o usuário.

editar Não há dúvida de que as exceções específicas como MyAppDuplicateExceptiondevem ser verificadas ou não, e devem ser verificadas definitivamente.

Ludwig Magnusson
fonte

Respostas:

9
  1. Às vezes, você deseja capturar um tipo específico de exceção (por exemplo MyAppDuplicateException) e, às vezes, deseja capturar toda uma categoria de exceções (por exemplo MyAppException). Com a MyAppDuplicateExceptionextensão, MyAppExceptionvocê concede ao código de chamada um pouco mais de flexibilidade em como ele lida com as diferentes exceções.
  2. O melhor conselho que ouvi sobre isso é que, de um modo geral, você deve lançar uma exceção verificada se o que chamou de método obedeceu ao contrato. É uma maneira de dizer "aqui estão as coisas que se espera que falhem". Eu definitivamente faria MyAppDuplicateExceptione outras exceções verificadas (ou seja, não RuntimeException s).

Há um artigo muito bom aqui que deve ajudá-lo a evitar a maioria das armadilhas comuns.

vaughandroid
fonte
Entendo o seu ponto com o nº 1. No entanto, é minha experiência que nunca encontramos a situação em que queremos capturar todos os tipos de exceções de nossos serviços. Se algo der errado, nós realmente queremos saber exatamente o que é. O que ouvi de você segundo ponto é que MyAppException deve ser RuntimmeException. (os outros devem ser verificados, não há dúvida sobre isso)
Ludwig Magnusson
@vaughandroid, o link está quebrado. Aqui está o arquivo: community.oracle.com/docs/DOC-983543
user167569 20/18
@ user167569 Obrigado pelo aviso. Corrigido o link.
Vaughandroid
O @LudwigMagnusson # 1 mostra o problema quando você deseja capturar um ramo de exceções em um determinado momento, possivelmente após lidar com os mais específicos. Isso não é o mesmo que capturar todas as exceções. O problema com o nº 2 é o contexto. Você pode dizer que uma IOExceptiondeve ser uma exceção de tempo de execução para Arquivo não encontrado, se o arquivo for um recurso que deveria estar lá. No entanto, é uma exceção verificada no caso em que um usuário solicita um nome de arquivo específico que pode ou não existir. Isso é especialmente verdade ao criar bibliotecas para as quais o contexto não é conhecido antecipadamente.
Maarten Bodewes
1

Percebi que as exceções lançadas por nossos serviços devem ser nossas próprias exceções específicas de aplicativos, em oposição às exceções específicas de implementação .

Com isso, você quer dizer exceções definidas pela sua implementação de terceiros? Corrigir?

Primeiro, considere uma exceção genérica MyAppException. Esta exceção indica que algo inesperado deu errado e a melhor coisa que podemos fazer é exibir uma mensagem ao usuário dizendo que algo deu errado e que estamos trabalhando nisso. O erro pode ser que o banco de dados travou ou algo parecido. Essa exceção seria praticamente lançada em todos os métodos que trabalham com o banco de dados.

Se esse tipo de exceção representa um erro no seu programa que não é causado por uma entrada incorreta do usuário, mas por algum problema com o seu código, em Java, deve ser uma exceção de tempo de execução.

Em segundo lugar, considere uma exceção MyAppDuplicateException. Essa exceção indicaria que o usuário tentou salvar algo no banco de dados que já estava lá. Aqui, podemos exibir uma mensagem de erro muito mais específica e essa exceção é lançada apenas nos métodos que inserem ou atualizam linhas do banco de dados.

Esta é uma exceção verificada em Java.

Se as outras exceções não estenderem MyAppException, MyAppException> deve ser um java.lang.RuntimeException?

Sim.

Isso não exigiria a execução de código para capturá-lo, o que para mim parece natural, pois o objetivo da exceção é dizer que algo desconhecido aconteceu e o código de execução não é esperado para ser capaz de lidar com isso. O código no> ponto de entrada da solicitação ainda pode ter uma instrução try / catch que captura> MyAppException e garante que uma mensagem seja exibida para o usuário.

Sim está certo.

user48910
fonte
Você me entende corretamente.
Ludwig Magnusson
Quando você diz que o erro é causado por "um problema no meu código", quero apenas salientar que o problema também pode estar na conexão com o banco de dados, etc. Não apenas erros na programação.
Ludwig Magnusson