Li alguns códigos de um colega e descobri que ele muitas vezes captura várias exceções e sempre lança uma 'RuntimeException'. Eu sempre pensei que isso é uma prática muito ruim. Estou errado?
java
exceptions
exception-handling
RoflcoptrException
fonte
fonte
Function
,Predicate
, etc) não têm parametrizados joga cláusulas. Isso significa que você precisa capturar, agrupar e reproduzir novamente todas as exceções verificadas no loop interno de qualquer método stream (). Isso por si só sugere o equilíbrio para mim sobre se as exceções verificadas são uma má ideia.Respostas:
Não conheço o contexto suficiente para saber se o seu colega está fazendo algo incorretamente ou não, então vou discutir sobre isso em um sentido geral.
Não acho que seja sempre uma prática incorreta transformar exceções verificadas em algum tipo de exceção de tempo de execução . As exceções verificadas geralmente são mal utilizadas e abusadas pelos desenvolvedores.
É muito fácil usar exceções verificadas quando elas não devem ser usadas (condições irrecuperáveis ou mesmo controle de fluxo). Especialmente se uma exceção verificada for usada para condições das quais o chamador não pode se recuperar, acho que é justificado transformar essa exceção em uma exceção de tempo de execução com uma mensagem / estado útil. Infelizmente, em muitos casos, quando alguém se depara com uma condição irrecuperável, eles tendem a ter um bloco de captura vazio, que é uma das piores coisas que você pode fazer. Depurar esse problema é uma das maiores dificuldades que um desenvolvedor pode encontrar.
Portanto, se você acha que está lidando com uma condição recuperável, ela deve ser tratada adequadamente e a exceção não deve ser transformada em uma exceção de tempo de execução. Se uma exceção verificada for usada para condições irrecuperáveis, a transformação em uma exceção de tempo de execução será justificada .
fonte
Ele pode ser bom . Por favor leia:
http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html
Lançar exceções verificadas e não conseguir se recuperar delas não ajuda.
Algumas pessoas até acham que as exceções verificadas não devem ser usadas. Consulte http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html
Também a partir do mesmo link:
fonte
Não, você não está errado. Sua prática é extremamente equivocada. Você deve lançar uma exceção que captura o problema que o causou. RunTimeException é amplo e abrangente. Deve ser um NullPointerException, ArgumentException etc. O que quer que descreva com precisão o que deu errado. Isso fornece a capacidade de diferenciar problemas com os quais você deve lidar e deixar o programa sobreviver versus erros que devem ser um cenário "Não passe". O que ele está fazendo é apenas um pouco melhor que "On Error Resume Next", a menos que haja algo faltando nas informações fornecidas na pergunta.
fonte
Depende.
Essa prática pode ser até sábia . Existem muitas situações (por exemplo, no desenvolvimento da Web), nas quais, se ocorrer alguma exceção, você não poderá fazer nada (porque não é possível, por exemplo, reparar o banco de dados inconsistente do seu código :-), somente o desenvolvedor pode fazê-lo). Nessas situações, é aconselhável agrupar a exceção lançada em uma exceção de tempo de execução e repeti-la novamente. Então você pode capturar todas essas exceções em alguma camada de manipulação de exceções, registrar o erro e exibir ao usuário um código de erro localizado + mensagem.
Por outro lado , se a exceção não for em tempo de execução (estiver marcada), o desenvolvedor da API indicará que essa exceção é solucionável e deve ser reparada. Se for possível, você definitivamente deve fazê-lo.
A outra solução pode ser a repetição da exceção verificada na camada de chamada, mas se você não conseguiu resolvê-la, onde ocorreu a exceção, provavelmente também não será possível resolvê-la aqui ...
fonte
exception handling layer
- por exemplo, em um aplicativo da web, um filtro.Gostaria de receber comentários sobre isso, mas acho que há momentos em que isso não é necessariamente uma prática ruim. (Ou terrivelmente ruim). Mas talvez eu esteja errado.
Muitas vezes, uma API que você está usando lança uma exceção que você não pode imaginar sendo lançada na sua base de dados específica. Nesse caso, parece perfeitamente correto lançar uma RuntimeException com a exceção capturada como causa. Se essa exceção for lançada, provavelmente será a causa do erro de programação e não estará dentro dos limites da especificação correta.
Supondo que o RuntimeException não seja capturado e ignorado posteriormente, não é o caso de um OnErrorResumeNext.
O OnErrorResumeNext ocorre quando alguém pega uma exceção e simplesmente a ignora ou apenas a imprime. Essa é uma prática muito ruim em quase todos os casos.
fonte
TL; DR
Premissa
Conclusão
Podemos repetir uma exceção verificada como uma exceção de tempo de execução se o código de propagação ou interface assumir que a implementação subjacente depende do estado externo, quando claramente não.
Esta seção discute o tópico de quando uma das exceções deve ser lançada. Você pode pular para a próxima barra horizontal se quiser ler uma explicação mais detalhada para a conclusão.
Quando é apropriado lançar uma exceção de tempo de execução? Você lança uma exceção de tempo de execução quando fica claro que o código está incorreto e que a recuperação é apropriada modificando o código.
Por exemplo, é apropriado lançar uma exceção de tempo de execução para o seguinte:
Isso gerará uma divisão por exceção de zero tempo de execução. Isso é apropriado porque o código está com defeito.
Ou, por exemplo, aqui está uma parte do
HashMap
construtor:Para corrigir a capacidade inicial ou o fator de carga, é apropriado que você edite o código para garantir que os valores corretos sejam transmitidos. Não depende de algum servidor distante estar ativo, no estado atual do disco, um arquivo ou outro programa. O construtor que está sendo chamado com argumentos inválidos depende da correção do código de chamada, seja um cálculo incorreto que levou a parâmetros inválidos ou fluxo inadequado que perdeu um erro.
Quando é apropriado lançar uma exceção marcada? Você lança uma exceção verificada quando o problema é recuperável sem alterar o código. Ou, em termos diferentes, você lança uma exceção verificada quando o erro está relacionado ao estado enquanto o código está correto.
Agora, a palavra "recuperar" pode ser complicada aqui. Isso pode significar que você encontra outra maneira de atingir a meta: por exemplo, se o servidor não responder, tente o próximo servidor. Se esse tipo de recuperação é possível para o seu caso, isso é ótimo, mas essa não é a única coisa que significa recuperação - a recuperação pode estar simplesmente exibindo uma caixa de diálogo de erro para o usuário que explica o que aconteceu ou, se for um aplicativo de servidor, pode ser enviando um email para o administrador ou simplesmente registrando o erro de forma adequada e concisa.
Vamos pegar o exemplo mencionado na resposta dos mrmuggles:
Essa não é a maneira correta de lidar com a exceção verificada. A simples incapacidade de lidar com a exceção no escopo deste método não significa que o aplicativo deve ser travado. Em vez disso, é apropriado propagá-lo para um escopo mais alto como este:
O que permite a possibilidade de recuperação pelo chamador:
As exceções verificadas são uma ferramenta de análise estática; elas deixam claro para um programador o que poderia dar errado em uma determinada chamada sem exigir que eles aprendam a implementação ou passem por um processo de tentativa e erro. Isso facilita garantir que nenhuma parte do fluxo de erros seja ignorada. A reconfiguração de uma exceção verificada como uma exceção de tempo de execução está funcionando contra esse recurso de análise estática que economiza trabalho.
Também vale a pena mencionar que a camada de chamada tem um contexto melhor do esquema maior de coisas, como foi demonstrado acima. Pode haver muitas causas para que
dataAccessCode
isso seja chamado, o motivo específico da chamada é visível apenas para o chamador - portanto, ele pode tomar uma decisão melhor na recuperação correta em caso de falha.Agora que esclarecemos essa distinção, podemos deduzir quando está correto repetir uma exceção verificada como uma exceção de tempo de execução.
Dado o exposto, quando é apropriado repetir novamente uma exceção verificada como uma RuntimeException? Quando o código que você está usando assume dependência do estado externo, mas você pode afirmar claramente que ele não depende do estado externo.
Considere o seguinte:
Neste exemplo, o código está se propagando
IOException
porque a API deReader
foi projetada para acessar o estado externo; no entanto, sabemos que aStringReader
implementação não acessa o estado externo. Nesse escopo, onde certamente podemos afirmar que as partes envolvidas na chamada não acessam o IO ou qualquer outro estado externo, podemos retroceder com segurança a exceção como uma exceção de tempo de execução, sem surpreender os colegas que desconhecem nossa implementação (e possivelmente assumindo que o código de acesso IO gerará umIOException
).O motivo para manter estritamente as exceções dependentes do estado externo verificadas é que elas não são determinísticas (diferentemente das exceções dependentes da lógica, que serão reproduzidas previsivelmente todas as vezes para uma versão do código). Por exemplo, se você tentar dividir por 0, sempre produzirá uma exceção. Se você não dividir por 0, nunca produzirá uma exceção e não precisará lidar com esse caso de exceção, porque isso nunca acontecerá. No entanto, no caso de acessar um arquivo, obter êxito uma vez não significa que você terá êxito na próxima vez - o usuário pode ter alterado as permissões, outro processo pode ter sido excluído ou modificado. Portanto, você sempre precisa lidar com esse caso excepcional ou provavelmente terá um bug.
fonte
Para aplicativos autônomos. Quando você sabe que seu aplicativo não pode lidar com a exceção, você poderia, em vez de lançar a RuntimeException verificada, lançar Error, deixar o aplicativo travar, esperar por relatórios de erros e corrigir seu aplicativo. (Veja a resposta de mrmuggles para uma discussão mais aprofundada dos prós e contras dos verificados versus não verificados.)
fonte
Essa é uma prática comum em muitas estruturas. Por exemplo,
Hibernate
faz exatamente isso. A ideia é que as APIs não sejam invasivas para o cliente eException
sejam invasivas, pois você deve escrever explicitamente o código para manipulá-las no local em que chama a API. Mas esse lugar pode não ser o lugar certo para lidar com a exceção em primeiro lugar.Na verdade, para ser sincero, esse é um tópico "quente" e muitas disputas, por isso não tomarei partido, mas direi que o que seu amigo faz / propõe não é incomum ou incomum.
fonte
A coisa toda "exceção verificada" é uma má idéia.
A programação estruturada apenas permite que informações sejam passadas entre funções (ou, na linguagem Java, métodos) quando elas estão "próximas". Mais precisamente, as informações só podem se mover entre funções de duas maneiras:
De um chamador a um chamado, via passagem de argumentos.
De um chamado para o chamador, como valores de retorno.
Isso é fundamentalmente bom. É isso que permite que você raciocine sobre o seu código localmente: se você precisar entender ou modificar uma parte do seu programa, precisará apenas olhar para essa parte e outras partes "próximas".
No entanto, em algumas circunstâncias, é necessário enviar informações para uma função "distante", sem que ninguém no meio "saiba". É precisamente quando as exceções precisam ser usadas. Uma exceção é uma mensagem secreta enviada de um raiser (qualquer parte do seu código pode conter uma
throw
instrução) para um manipulador (qualquer parte do seu código pode conter umcatch
bloco compatível com a exceção que foithrow
n).As exceções verificadas destroem o sigilo do mecanismo e, com ele, a própria razão de sua existência. Se uma função puder permitir que o chamador "conheça" uma informação, envie-a diretamente como parte do valor de retorno.
fonte
Isso pode depender caso a caso. Em certos cenários, é aconselhável fazer o que seu amigo está fazendo, por exemplo, quando você está expondo uma API para alguns clientes e deseja que o cliente tenha menos conhecimento dos detalhes da implementação, onde sabe que certas exceções de implementação podem ser específicas para detalhes de implementação e não podem ser expostos ao cliente.
Mantendo as exceções verificadas fora do caminho, você pode expor APIs que permitiriam ao cliente escrever código mais limpo, pois o próprio cliente pode estar pré-validando as condições excepcionais.
Por exemplo, Integer.parseInt (String) pega uma string e retorna o número inteiro equivalente a ela e lança NumberFormatException no caso de a string não ser numérica. Agora imagine que um envio de formulário com um campo
age
seja convertido por esse método, mas o cliente já teria garantido a validação de sua parte; portanto, não faz sentido forçar a verificação da exceção.fonte
Há realmente algumas perguntas aqui
A regra geral é que as exceções que o chamador deve capturar e recuperar devem ser verificadas. Outras exceções (aquelas em que o único resultado razoável é abortar toda a operação ou quando você as considera improváveis o suficiente para não se preocupar em se preocupar em lidar com elas especificamente) devem ser desmarcadas.
Às vezes, seu julgamento sobre se uma exceção merece captura e recuperação é diferente daquele da API com a qual você está trabalhando. Às vezes, o contexto é importante, uma exceção que vale a pena manipular em uma situação pode não valer a pena manipular em outra. Às vezes, sua mão é forçada pelas interfaces existentes. Portanto, sim, existem razões legítimas para transformar uma exceção verificada em uma exceção não verificada (ou em um tipo diferente de exceção verificada)
Primeiro e mais importante, certifique-se de usar o recurso de encadeamento de exceções. Dessa forma, as informações da exceção original não são perdidas e podem ser usadas para depuração.
Em segundo lugar, você precisa decidir que tipo de exceção usar. O uso de uma exceção simples de execução dificulta o chamador determinar o que deu errado, mas se o chamador está tentando determinar o que deu errado, isso pode ser uma indicação de que você não deveria ter alterado a exceção para torná-la desmarcada.
fonte
Em uma pergunta booleana, é difícil responder de maneira diferente após duas respostas controversas, mas eu gostaria de lhe dar uma perspectiva que, mesmo mencionada em poucos lugares, não foi enfatizada o suficiente pela importância que tem.
Com o passar dos anos, descobri que sempre alguém está confuso sobre um problema trivial, sem entender alguns dos fundamentos.
Camadas. Um aplicativo de software (pelo menos deveria ser) uma pilha de camadas, uma em cima da outra. Uma expectativa importante para boas camadas é que as camadas inferiores forneçam funcionalidade para componentes potencialmente múltiplos da camada superior.
Digamos que seu aplicativo tenha as seguintes camadas de baixo para cima NET, TCP, HTTP, REST, MODELO DE DADOS, NEGÓCIOS.
Se sua camada de negócios quiser executar uma chamada de descanso ... aguarde um segundo. Por que digo isso? Por que não disse solicitação HTTP ou transação TCP ou enviei pacotes de rede? Porque isso é irrelevante para a minha camada de negócios. Não vou lidar com eles, não vou olhar nos detalhes deles. Eu estou perfeitamente bem se eles estão profundos nas exceções que recebo como causa e não quero saber que elas existem.
Além disso, é ruim se eu souber detalhes, porque se amanhã eu quiser alterar os protocolos de transporte sublinhados que lidam com detalhes específicos do protocolo TCP, a minha abstração REST não fez um bom trabalho para se abstrair. a implementação específica.
Ao fazer a transição de uma exceção de camada para camada, é importante revisar todos os aspectos dela e que sentido isso fará para a abstração que a camada atual fornece. Pode ser substituir a exceção por outra, pode combinar várias exceções. Também pode fazer a transição deles de marcado para desmarcado ou vice-versa.
É claro que os lugares que você mencionou fazem sentido é uma história diferente, mas em geral - sim, pode ser uma boa coisa a se fazer.
fonte
Na minha opinião,
No nível da estrutura, devemos ser exceções de tempo de execução de captura para reduzir mais blocos de tentativa de captura para o invocador no mesmo local.
No nível do aplicativo, raramente capturamos exceções de tempo de execução e acho que essa prática foi ruim.
fonte