Joshua Bloch em " Java eficaz " disse que
Use exceções verificadas para condições recuperáveis e exceções de tempo de execução para erros de programação (Item 58 na 2ª edição)
Vamos ver se entendi isso corretamente.
Aqui está o meu entendimento de uma exceção verificada:
try{
String userInput = //read in user input
Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
id = 0; //recover the situation by setting the id to 0
}
1. O acima é considerado uma exceção verificada?
2. RuntimeException é uma exceção desmarcada?
Aqui está o meu entendimento de uma exceção não verificada:
try{
File file = new File("my/file/path");
FileInputStream fis = new FileInputStream(file);
}catch(FileNotFoundException e){
//3. What should I do here?
//Should I "throw new FileNotFoundException("File not found");"?
//Should I log?
//Or should I System.exit(0);?
}
4. Agora, o código acima também não pode ser uma exceção verificada? Eu posso tentar recuperar a situação assim? Eu posso? (Nota: minha terceira pergunta está dentro do catch
acima)
try{
String filePath = //read in from user input file path
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
}catch(FileNotFoundException e){
//Kindly prompt the user an error message
//Somehow ask the user to re-enter the file path.
}
5. Por que as pessoas fazem isso?
public void someMethod throws Exception{
}
Por que eles deixam a exceção borbulhar? Não é melhor lidar com o erro mais cedo? Por que borbulhar?
6. Devo apresentar uma exceção exata ou mascará-la usando Exceção?
Abaixo estão minhas leituras
DataSeries
classe que contém dados que sempre devem permanecer em ordem baseada no tempo. Existe um método para adicionar um novoDataPoint
ao final de umDataSeries
. Se todo o meu código estiver funcionando corretamente durante todo o projeto,DataPoint
nunca deverá ser adicionado um ao final que tenha uma data anterior à que já está no final. Cada módulo em todo o projeto é construído com esse truísmo. No entanto, eu verifico esta condição e emito uma exceção desmarcada, se isso acontecer. Por quê? Se isso acontecer, quero saber quem está fazendo isso e corrigi-lo.Respostas:
Muitas pessoas dizem que as exceções verificadas (ou seja, aquelas que você deve capturar ou reler explicitamente) não devem ser usadas. Eles foram eliminados em C #, por exemplo, e a maioria dos idiomas não os possui. Assim, você sempre pode lançar uma subclasse de
RuntimeException
(exceção não marcada)No entanto, acho que as exceções verificadas são úteis - elas são usadas quando você deseja forçar o usuário da sua API a pensar em como lidar com a situação excepcional (se for recuperável). Só que as exceções verificadas são usadas em excesso na plataforma Java, o que faz as pessoas as odiarem.
Aqui está minha visão ampliada sobre o tópico .
Quanto às perguntas particulares:
A
NumberFormatException
consideração é uma exceção verificada?No.
NumberFormatException
está desmarcado (= é subclasse deRuntimeException
). Por quê? Eu não sei. (mas deveria ter havido um métodoisValidInteger(..)
)É
RuntimeException
uma exceção desmarcada?Sim, exatamente.
O que devo fazer aqui?
Depende de onde está esse código e o que você deseja que aconteça. Se estiver na camada da interface do usuário - pegue-a e mostre um aviso; se estiver na camada de serviço - não pegue nada - deixe borbulhar. Só não engula a exceção. Se ocorrer uma exceção na maioria dos casos, você deve escolher um destes:
Agora, o código acima também não pode ser uma exceção verificada? Eu posso tentar recuperar a situação assim? Eu posso?
Poderia ter sido. Mas nada impede você de capturar a exceção desmarcada também
Por que as pessoas adicionam classe
Exception
na cláusula throws?Na maioria das vezes, porque as pessoas têm preguiça de considerar o que pegar e o que refazer. Jogar
Exception
é uma prática ruim e deve ser evitado.Infelizmente, não existe uma regra única que permita determinar quando capturar, quando relançar, quando usar verificadas e quando usar exceções não verificadas. Concordo que isso causa muita confusão e muito código incorreto. O princípio geral é afirmado por Bloch (você citou uma parte dele). E o princípio geral é retroceder uma exceção para a camada em que você pode lidar com isso.
fonte
Se algo é uma "exceção verificada" não tem nada a ver com a captura ou com o que você faz no bloco de captura. É uma propriedade de classes de exceção. Tudo o que é uma subclasse de
Exception
exceção paraRuntimeException
e suas subclasses é uma exceção verificada.O compilador Java obriga a capturar exceções verificadas ou declara-las na assinatura do método. Era para melhorar a segurança do programa, mas a opinião da maioria parece ser que não vale a pena os problemas de design que ela cria.
Porque esse é o ponto inteiro de exceções. Sem essa possibilidade, você não precisaria de exceções. Eles permitem que você lide com os erros no nível que você escolher, em vez de forçá-lo a lidar com eles em métodos de baixo nível onde eles ocorrem originalmente.
fonte
Throwable
diz: "Throwable e qualquer subclasse de Throwable que não é também uma subclasse de qualquer RuntimeException ou erro são considerados como exceções verificadas"O acima é considerado uma exceção verificada? Não O fato de você estar manipulando uma exceção não a torna
Checked Exception
se for aRuntimeException
.É
RuntimeException
umunchecked exception
? simChecked Exceptions
sãosubclasses
dejava.lang.Exception
Unchecked Exceptions
sãosubclasses
dejava.lang.RuntimeException
As chamadas que lançam exceções verificadas precisam ser encerradas em um bloco try {} ou tratadas em um nível acima no chamador do método. Nesse caso, o método atual deve declarar que lança as referidas exceções para que os chamadores possam tomar as providências necessárias para lidar com a exceção.
Espero que isto ajude.
A: Sim, esta é uma pergunta muito boa e uma consideração importante do projeto. A classe Exception é uma classe de exceção muito geral e pode ser usada para quebrar exceções internas de baixo nível. É melhor criar uma exceção personalizada e envoltar dentro dela. Mas, e um grande problema - nunca oculto na causa raiz original subjacente. Por exemplo,
Don't ever
faça o seguinte -Em vez disso, faça o seguinte:
Consumir a causa raiz original enterra a causa real além da recuperação é um pesadelo para as equipes de suporte à produção, onde tudo o que têm acesso é logs de aplicativos e mensagens de erro. Embora o último seja um design melhor, mas muitas pessoas não o usam com frequência porque os desenvolvedores não conseguem transmitir a mensagem subjacente ao chamador. Portanto, faça uma observação firme:
Always pass on the actual exception
volte com ou sem quebra em qualquer exceção específica do aplicativo.RuntimeException
Como regra geral, os s não devem ser tentados. Eles geralmente sinalizam um erro de programação e devem ser deixados em paz. Em vez disso, o programador deve verificar a condição de erro antes de chamar algum código que possa resultar em aRuntimeException
. Por exemplo:Esta é uma má prática de programação. Em vez disso, uma verificação nula deveria ter sido feita como -
Mas há momentos em que essa verificação de erro é cara, como formatação de números, considere isso:
Aqui, a verificação de erro antes da invocação não vale o esforço, porque significa essencialmente duplicar todo o código de conversão de cadeia para número inteiro dentro do método parseInt () - e é propenso a erros se implementado por um desenvolvedor. Portanto, é melhor acabar com o try-catch.
Então,
NullPointerException
eNumberFormatException
são os doisRuntimeExceptions
, a captura de umNullPointerException
deve ser substituída por uma verificação nula graciosa, enquanto eu recomendo a capturaNumberFormatException
explícita para evitar a possível introdução de código suscetível a erros.fonte
exception
, devo expor a exceção exata ou mascará-la usandoException
. Escrevendo código em cima de algum código legado eException
sendo borbulhado em todos os lugares. Gostaria de saber se este é o comportamento correto?LoginFailureException(sqle)
?LoginFailureException
estendeException
e declara um construtorpublic LoginFailureException(Throwable cause) { super(cause) }
1 Se você não tiver certeza sobre uma exceção, verifique a API:
2) Sim, e todas as exceções que a estendem.
3) Não há necessidade de capturar e lançar a mesma exceção. Você pode mostrar uma nova caixa de diálogo de arquivo neste caso.
4) FileNotFoundException já é uma exceção verificada.
5) Se for esperado que o método que está chamando
someMethod
para capturar a exceção, o último possa ser lançado. Apenas "passa a bola". Um exemplo disso seria se você deseja lançá-lo em seus próprios métodos privados e manipular a exceção em seu método público.Uma boa leitura é o próprio documento Oracle: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html
Há também algumas informações importantes na especificação da linguagem Java :
A conclusão é que você pode pegar qualquer
RuntimeException
, mas não é necessário e, de fato, a implementação não é obrigada a manter as mesmas exceções não verificadas lançadas, pois elas não fazem parte do contrato.fonte
exception
, devo expor a exceção exata ou mascará-la usandoException
. Escrevendo código em cima de algum código legado eException
sendo borbulhado em todos os lugares. Gostaria de saber se este é o comportamento correto?1) Não, NumberFormatException é uma exceção desmarcada. Mesmo que você o tenha pego (não é necessário), porque não está marcado. Isso ocorre porque é uma subclasse da
IllegalArgumentException
qual é uma subclasse deRuntimeException
.2)
RuntimeException
é a raiz de todas as exceções não verificadas. Cada subclasse deRuntimeException
está desmarcada. Todas as outras exceções eThrowable
são verificadas, exceto Erros (abaixoThrowable
).3/4) Você pode alertar o usuário de que ele escolheu um arquivo inexistente e pedir um novo. Ou simplesmente deixe de informar ao usuário que ele inseriu algo inválido.
5) Jogar e pegar
'Exception'
é uma má prática. Mas, em geral, você pode lançar outras exceções para que o chamador possa decidir como lidar com isso. Por exemplo, se você escreveu uma biblioteca para lidar com a leitura de alguma entrada de arquivo e seu método recebeu um arquivo inexistente, você não tem idéia de como lidar com isso. O chamador quer perguntar novamente ou sair? Então você lança a exceção na cadeia de volta para o chamador.Em muitos casos, isso
unchecked Exception
ocorre porque o programador não verificou as entradas (no caso deNumberFormatException
sua primeira pergunta). É por isso que é opcional capturá-los, porque existem maneiras mais elegantes de evitar gerar essas exceções.fonte
exception
, devo expor a exceção exata ou mascará-la usandoException
. Escrevendo código em cima de algum código legado eException
sendo borbulhado em todos os lugares. Gostaria de saber se este é o comportamento correto?Verificado - propenso a acontecer. Verificado em tempo de compilação.
Por exemplo .. FileOperations
Não verificado - devido a dados incorretos. Verificado no tempo de execução.
Por exemplo..
Aqui, a exceção ocorre devido a dados incorretos e de forma alguma podem ser determinados durante o tempo de compilação.
fonte
As exceções verificadas são verificadas em tempo de compilação pela JVM e relacionadas a recursos (arquivos / db / stream / socket etc.). O motivo da exceção verificada é que, em tempo de compilação, se os recursos não estiverem disponíveis, o aplicativo deve definir um comportamento alternativo para lidar com isso no bloco catch / finalmente.
Exceções não verificadas são erros puramente programáticos, cálculos incorretos, dados nulos ou até falhas na lógica de negócios podem levar a exceções de tempo de execução. É absolutamente bom manipular / capturar exceções não verificadas no código.
Explicação retirada de http://coder2design.com/java-interview-questions/
fonte
Minha descrição favorita absoluta da diferença entre exceções não verificadas e verificadas é fornecida no artigo da trilha do Tutorial do Java, " Exceções não verificadas - a controvérsia " (desculpe-me por ficar tudo elementar neste post - mas, ei, o básico às vezes é o melhor):
O cerne de "que tipo de exceção lançar" é semântico (até certo ponto) e a citação acima fornece uma excelente diretriz (portanto, ainda estou deslumbrado com a noção de que o C # se livrou das exceções verificadas - principalmente como Liskov defende. sua utilidade).
O resto torna-se lógico: a quais exceções o compilador espera que eu responda, explicitamente? Aqueles dos quais você espera que o cliente se recupere.
fonte
Para responder à pergunta final (as outras parecem completamente respondidas acima), "Devo apresentar uma exceção exata ou mascará-la usando Exceção?"
Suponho que você queira dizer algo assim:
Não, sempre declare a exceção mais precisa possível ou uma lista dessas. As exceções que você declara que seu método é capaz de lançar fazem parte do contrato entre o método e o chamador. Arremessar
"FileNotFoundException"
significa que é possível que o nome do arquivo não seja válido e o arquivo não será encontrado; o chamador precisará lidar com isso de maneira inteligente. JogarException
significa "Ei, sh * t acontece. Acordo." O que é muito pobreAPI
.Nos comentários do primeiro artigo, existem alguns exemplos em que "throws
Exception
" é uma declaração válida e razoável, mas esse não é o caso da maioria dos "normal
" códigos que você escreverá.fonte
Exceções de tempo de execução : exceções de tempo de execução são referidas como exceções não verificadas. Todas as outras exceções são exceções verificadas e não derivam de java.lang.RuntimeException.
Exceções verificadas : uma exceção verificada deve ser capturada em algum lugar do seu código. Se você invocar um método que lança uma exceção verificada, mas não a captura em algum lugar, seu código não será compilado. É por isso que eles são chamados de exceções verificadas: o compilador verifica se é tratado ou declarado.
Vários métodos na API Java lançam exceções verificadas, portanto, você costuma escrever manipuladores de exceções para lidar com exceções geradas por métodos que não gravou.
fonte
Por que eles deixam a exceção borbulhar? Não é melhor lidar com o erro mais cedo? Por que borbulhar?
Por exemplo, digamos que você tenha algum aplicativo cliente-servidor e o cliente tenha feito uma solicitação para algum recurso que não pôde ser descoberto ou para alguma outra coisa que possa ter ocorrido no lado do servidor durante o processamento da solicitação do usuário, é dever do servidor para informar ao cliente por que ele não conseguiu o que solicitou; portanto, para isso, no lado do servidor, o código é escrito para gerar a exceção usando a palavra-chave throw em vez de engolir ou manipulá-la. então, não haverá chance de sugerir ao cliente que erro ocorreu.
Nota: Para fornecer uma descrição clara do tipo de erro, podemos criar nosso próprio objeto Exception e lançá-lo ao cliente.
fonte
Eu acho que as exceções verificadas são um bom lembrete para o desenvolvedor que usa uma biblioteca externa de que as coisas podem dar errado com o código dessa biblioteca em situações excepcionais.
Leia mais sobre exceções verificadas vs não verificadas aqui http://learnjava.today/2015/11/checked-vs-unchecked-exceptions/
fonte
Eu só quero adicionar algum raciocínio para não usar exceções verificadas. Esta não é uma resposta completa, mas acho que responde parte de sua pergunta e complementa muitas outras respostas.
Sempre que houver exceções verificadas, há
throws CheckedException
algum lugar na assinatura do método (CheckedException
pode haver qualquer exceção verificada). Uma assinatura NÃO lança uma exceção, o lançamento de exceções é um aspecto da implementação. Interfaces, assinaturas de métodos, classes pai, todas essas coisas NÃO devem depender de suas implementações. O uso das exceções marcadas aqui (na verdade, o fato de você precisar declarar othrows
assinatura do método) está vinculando suas interfaces de nível superior às suas implementações dessas interfaces.Deixe-me mostrar-lhe um exemplo.
Vamos ter uma interface agradável e limpa como esta
Agora podemos escrever muitas implementações de método
foo()
, como estasA classe Foo está perfeitamente bem. Agora vamos fazer uma primeira tentativa na classe Bar
Esta classe Bar não será compilada. Como InterruptedException é uma exceção verificada, você deve capturá-la (com um try-catch dentro do método foo ()) ou declarar que a está lançando (adicionando
throws InterruptedException
à assinatura do método). Como não quero capturar essa exceção aqui (quero que ela se propague para cima, para que eu possa lidar adequadamente com ela em outro lugar), vamos alterar a assinatura.Esta classe Bar também não será compilada! O método foo () de Bar NÃO substitui o método foo () de IFoo, pois suas assinaturas são diferentes. Eu poderia remover a anotação @Override, mas quero programar na interface IFoo like
IFoo foo;
e, posteriormente, decidir sobre qual implementação eu gostaria de usarfoo = new Bar();
. Se o método foo () de Bar não substituir o método foo de IFoo, quando o fizerfoo.foo();
, não chamará a implementação de foo () de Bar.Para fazer a
public void foo() throws InterruptedException
substituição do IFoo do Bar,public void foo()
DEVO adicionarthrows InterruptedException
à assinatura do método do IFoo. Isso, no entanto, causará problemas na minha classe Foo, pois a assinatura do método foo () difere da assinatura do método IFoo. Além disso, se eu adicionassethrows InterruptedException
ao método foo () do Foo, receberia outro erro informando que o método foo () do Foo declara que lança uma InterruptedException, mas nunca lança uma InterruptedException.Como você pode ver (se eu fiz um trabalho decente ao explicar essas coisas), o fato de eu estar lançando uma exceção verificada como InterruptedException está me forçando a vincular minha interface IFoo a uma de suas implementações, o que, por sua vez, causa estragos no IFoo. outras implementações!
Esse é um grande motivo pelo qual as exceções verificadas são ruins. Em maiúsculas.
Uma solução é capturar a exceção verificada, envolvê-la em uma exceção não verificada e lançar a exceção não verificada.
fonte
throws InterruptedException
à assinatura do método do IFoo sem lançar nada em nenhuma implementação. Portanto, isso realmente não causa nenhum problema. Se em uma interface você faz com que cada assinatura de método seja lançadaException
, ela apenas oferece à implementação a opção de lançar ou não uma exceção (qualquer exceção, poisException
encapsula todas as exceções).throw Exception
cláusula em sua assinatura, mesmo que sua implementação não atinja nada ou possa ser uma exceção mais específica. Mas ainda acho que é uma boa prática sempre lançar Exception para o método de uma interface, porque, novamente, ele dá ao usuário a opção de lançar ou não jogar nada.subclasses
da classeRuntimeException
são uma exceção desmarcada.Exception
mas nãoRuntimeException
são consideradaschecked exceptions
.checked exception
.throws
cláusula contendo ochecked-exception
.Exception
As classes são definidas para serem verificadas quando consideradas importantes o suficiente para serem capturadas ou declaradas.fonte
Aqui está uma regra simples que pode ajudá-lo a decidir. Está relacionado a como as interfaces são usadas em Java.
Leve a sua classe e imagine projetar uma interface para ela, de modo que a interface descreva a funcionalidade da classe, mas não a implementação subjacente (como uma interface deve). Finja que talvez você possa implementar a classe de outra maneira.
Veja os métodos da interface e considere as exceções que eles podem gerar:
Se uma exceção puder ser lançada por um método, independentemente da implementação subjacente (em outras palavras, ela descreve apenas a funcionalidade), provavelmente deve ser uma exceção verificada na interface.
Se uma exceção é causada pela implementação subjacente, ela não deve estar na interface. Portanto, deve ser uma exceção não verificada em sua classe (já que as exceções não verificadas não precisam aparecer na assinatura da interface) ou você deve envolvê-la e repetir como uma exceção verificada que faz parte do método da interface.
Para decidir se você deve agrupar e relançar novamente, considere novamente se faz sentido para um usuário da interface lidar com a condição de exceção imediatamente ou se a exceção é tão geral que não há nada que você possa fazer sobre isso. propagar a pilha. A exceção agrupada faz sentido quando expressa como funcionalidade da nova interface que você está definindo ou é apenas uma transportadora para um conjunto de possíveis condições de erro que também podem ocorrer com outros métodos? No primeiro caso, ainda pode ser uma exceção verificada, caso contrário, deve ser desmarcada.
Normalmente, você não deve planejar exceções de "bolha" (capturar e relançar). Uma exceção deve ser tratada pelo chamador (nesse caso, está marcada) ou deve ir até um manipulador de alto nível (nesse caso, é mais fácil se estiver desmarcada).
fonte
Apenas para salientar que, se você lançar uma exceção marcada em um código e a captura estiver alguns níveis acima, precisará declarar a exceção na assinatura de cada método entre você e a captura. Portanto, o encapsulamento está quebrado porque todas as funções no caminho de lançamento devem conhecer os detalhes dessa exceção.
fonte
Em resumo, as exceções que seu módulo ou módulos acima devem tratar durante o tempo de execução são chamadas de exceções verificadas; outros são exceções desmarcadas que são
RuntimeException
ouError
.Neste vídeo, ele explica exceções marcadas e desmarcadas em Java:
https://www.youtube.com/watch?v=ue2pOqLaArw
fonte
Todos esses são exceções verificadas. Exceções não verificadas são subclasses de RuntimeException. A decisão não é como lidar com eles, é se o seu código os lançar. Se você não quiser que o compilador diga que não tratou uma exceção, use uma exceção desmarcada (subclasse de RuntimeException). Eles devem ser salvos para situações das quais você não pode se recuperar, como erros de falta de memória e outros.
fonte
Se alguém se preocupa com mais uma prova para não gostar de exceções verificadas, consulte os primeiros parágrafos da popular biblioteca JSON:
"Embora essa seja uma exceção verificada, raramente é recuperável. A maioria dos chamadores deve simplesmente agrupar essa exceção em uma exceção não verificada e repetir novamente:"
Então, por que alguém faria os desenvolvedores continuarem verificando a exceção, se deveríamos "simplesmente envolvê-la"? ri muito
http://developer.android.com/reference/org/json/JSONException.html
fonte
Exceções verificadas :
As exceções que são verificadas pelo compilador para uma execução suave do programa em tempo de execução são chamadas Exceção Verificada.
Isso ocorre no momento da compilação.
Todas as subclasses da classe Exception, exceto RuntimeException, são Checked Exception.
Exemplo hipotético - Suponha que você esteja saindo de sua casa para o exame, mas se verificar se levou o seu ingresso para o salão em casa (tempo de compilação), não haverá nenhum problema no salão do exame (tempo de execução).
Exceção desmarcada :
As exceções que não são verificadas pelo compilador são chamadas Exceções não verificadas.
Isso ocorre em tempo de execução.
Se essas exceções não forem tratadas corretamente, elas não fornecerão erro de tempo de compilação. Mas o programa será encerrado prematuramente no tempo de execução.
Todas as subclasses de RunTimeException e Error são exceções desmarcadas.
Exemplo hipotético - Suponha que você esteja em sua sala de exames, mas de alguma forma sua escola sofreu um acidente de incêndio (tempo de execução) em que você não pode fazer nada naquele momento, mas as precauções podem ser tomadas antes (tempo de compilação).
fonte
Todas as exceções devem ser verificadas.
Exceções não verificadas são gotos irrestritos. E os gotos irrestritos são considerados uma coisa ruim.
Exceções não verificadas quebram o encapsulamento. Para processá-las corretamente, todas as funções na árvore de chamadas entre o lançador e o coletor devem ser conhecidas para evitar erros.
Exceções são erros na função que as lança, mas não erros na função que as processa. O objetivo das exceções é conceder ao programa uma segunda chance, adiando a decisão de se é um erro ou não para outro contexto. É somente no outro contexto que a decisão correta pode ser tomada.
fonte