Não é uma boa prática lidar com exceções de tempo de execução no código?

11

Estou trabalhando em um aplicativo Java e vejo que as exceções de tempo de execução são tratadas em muitos lugares. Por exemplo,

try {
    // do something
} catch(NullPointerException e) {
    return null;
}

Minhas perguntas são: quando é uma boa prática lidar com exceções de tempo de execução? Quando as exceções devem ser deixadas sem tratamento?

Vinoth Kumar CM
fonte
7
-1: Não há uma resposta única para uma pergunta tão ampla e vaga. É impossível fornecer uma resposta única para uma pergunta tão fora de foco como essa. Esta pergunta é horrível. Por favor, forneça exemplos específicos de onde você tem dúvidas.
31511 S.Lott
@ S.Lott Eu meio que discordo nesse caso, pois parece que há um subconjunto de programadores que têm em mente que esse é o caso sem uma racionalidade "boa".
SoylentGray
2
@ Chad: "este é o caso sem" boa "racionalidade". Isso pode ser verdade. Mas a única resposta possível deve ser "depende". Portanto, a pergunta parece defeituosa.
S.Lott 11/07

Respostas:

18

Depende.

Por exemplo, Integer#parseIntlança NumberFormatException(que é um RTE) se a sequência fornecida não puder ser analisada. Mas certamente você não quer que seu aplicativo falhe apenas porque o usuário escreveu "x" em um campo de texto que era para números inteiros? E como você sabe se a string pode ser analisada, a menos que você tente analisá-la primeiro? Portanto, neste caso, o RTE é apenas um sinal de erro que deve causar algum tipo de mensagem de erro. Pode-se argumentar que deve ser uma exceção verificada, mas o que você pode fazer - não é.

Joonas Pulakka
fonte
2
Concordo com "Depende", mas seu exemplo de análise parece ser um caso de mau design de API. Integer#parseIntdeve realmente retornar um Maybe<Integer>e não lançar nenhuma exceção.
Jörg W Mittag
3
@ Jörg W Mittag: Concordo que é um design de API ruim, mas é o mundo real com o qual temos de lidar. Como lidar adequadamente com valores
jogáveis
O ponto aqui é que você pode fazer algo significativo para uma condição antecipada (entrada do usuário não número inteiro). Apenas engolir o NPE é um estilo ruim e encobrirá apenas os erros de programação existentes.
Jürgen Strobel
7

NullPointerExceptions geralmente são o sinal de uma verificação nula ausente. Portanto, em vez de capturá-lo dessa maneira, você deve adicionar a verificação nula apropriada para garantir que não lança a exceção.

Mas, às vezes, é apropriado lidar com RunTimeExceptions. Por exemplo, quando você não pode modificar o código para adicionar a verificação nula no local apropriado ou quando a exceção é algo diferente de uma NullPointerException.

Seu exemplo de como lidar com exceções é terrível. Com isso, você perde o rastreamento da pilha e informações precisas sobre o problema. E você realmente não está resolvendo isso, pois provavelmente disparará outra NullPointerException em um local diferente e obterá informações enganosas sobre o que aconteceu e como resolvê-lo.

deadalnix
fonte
1
Gostaria de acrescentar que uma verificação nula é uma decisão melhor em termos de desempenho.
Mahmoud Hossam
... ainda, se você estiver fazendo dezenas de alocações que "nunca devem falhar" em um único local, a adição de verificações nulas para cada uma delas poderá ofuscar ridiculamente o código. Uma exceção abrangente (que LIDARÁ com a situação de maneira graciosa, não apenas return null;) será uma solução melhor.
SF.
Você provavelmente está confundindo java com outra coisa (C ++, por exemplo). Quando uma alocação falha, você obtém um OutOfMemoryError ou algo semelhante, nunca um ponteiro nulo. Ocultar um retorno nulo em vez de uma exceção está ocultando o erro aguardando a explosão do código em outro lugar.
Deadalnix 11/07
newjoga std::bad_allocem C ++.
R. Martinho Fernandes
Supondo que o novo operador não esteja sobrecarregado, o que é uma prática comum. Em C ++, tudo pode acontecer;) Mas tudo bem, digamos malloc de C. O ponto importante foi que você nunca conseguiu isso em java.
deadalnix
4

Eu trato de exceções esperadas onde eu as espero. (Como erros de leitura / gravação de banco de dados). Exceções inesperadas, eu borbulha. Em outro lugar, pode estar esperando a exceção e ter a lógica para isso.

SoylentGray
fonte
2

Exceções devem ser exatamente isso ... exceções. A melhor prática ao usar exceções é usá-las para cobrir a situação em que algo contrário ao que você espera que aconteça. O exemplo clássico é o FileNotFoundException que é lançado quando um arquivo simplesmente não existe. Se você estiver testando a existência do arquivo, use File.exists (), já que está simplesmente cutucando com um bastão de 10 pés para ver se bate em alguma coisa.

Tecnicamente, você pode obter os mesmos resultados cercando-o em uma tentativa de captura e usando o arquivo como se ele existisse, mas A) as exceções geralmente são caras em termos de recursos e B) os programadores presumem que você quisesse que o arquivo existisse se existisse. em uma tentativa de captura, o que aumenta a confusão geral de um programa.

Existem muitas situações nas quais escreverei um método que busca algum valor em um banco de dados. Milhares de coisas podem dar errado e, vendo como eu só preciso de um pequeno pedaço de informação, é inconveniente cercar a chamada com uma lista de captura de tentativa que contém 5 exceções diferentes. Então, eu vou pegar exceções no método de busca. Se algo der errado, tomo a ação apropriada para fechar a conexão com o banco de dados ou outros enfeites na cláusula finally e retorno nulo. Essa é uma boa prática, não apenas porque simplifica seu código, mas também porque "null" envia a mesma mensagem que você poderia ter recebido de uma exceção ... de que algo não saiu como o planejado. Gerencie detalhes de exceção no método de busca, mas gerencie o que fazer quando as coisas não acontecerem

Por exemplo:

Integer getUserCount() {
   Integer result = null;
   try {
      // Attempt to open database and retrieve data
   } catch (TimeoutException e) {
      logger.error("Got a watch?");
   } catch (MissingDatabaseException e) {
      logger.error("What are you smoking?");
   } catch (PermissionsToReadException e) {
      logger.error("Did you *really* think you were getting away with that?");
   } catch (PressedSendButtonToHardException e) {
      logger.error("Seriously.. just back away from the computer... slowly..");
   } catch (WTFException e) {
      logger.error("You're on your own with this one.. I don't even know what happened..");
   } finally {
      // Close connections and whatnot
   }
   return result;
}

void doStuff() {
   Integer result = getUserCount();
   if(result != null) {
       // Went as planned..
   }
}
Neil
fonte
6
Se você usar File.exists () e confiar no resultado, poderá ocorrer uma condição de corrida se o arquivo for excluído entre File.exists () e File.open (). Se isso disparar um bug crítico à segurança, um invasor poderá causar essa condição de propósito. Por isso, às vezes é melhor manter a operação atômica, ou seja, tentar e capturar a exceção.
user281377
1
Além disso, existem arquivos que devem existir para a execução do aplicativo. Essas seriam condições excepcionais. Se houver um arquivo que você deve ter para que o aplicativo funcione, não há razão para não lê-lo e, em seguida, manipule a exceção para o caso excepcional. Eu acredito que isso torna a intenção mais clara.
Thomas Owens
É uma má decisão retornar nulo. Isso resultará em NullPointerException em algum momento e será muito difícil depurar o que deu errado. Porque alguém em algum momento esquecerá a verificação nula.
### deadalnix #
@deadalnix: Eu poderia argumentar que você poderia facilmente esquecer de cercar um try-catch caso contrário. A diferença é uma questão de estilo, não de funcionalidade.
Neil
@ ammoQ: Eu discordo. Eu acho que você deve usar File.exists () e, nas raras circunstâncias em que ele é excluído antes de usá-lo, uma exceção é mais do que apropriada. A diferença é onde você mantém sua captura. Basta ter um coletor de exceção geral para erros imprevistos, a fim de registrá-lo e relatá-lo.
Neil
-5

Sim, você está manipulando corretamente as exceções de tempo de execução não é uma boa prática.

prasonscala
fonte
5
Oi prassee, você pode elaborar sua resposta? As falas únicas que não são acompanhadas de fatos, referências ou experiências não são muito úteis.