Entendendo as exceções verificadas versus não verificadas em Java

703

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 catchacima)

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

Em Java, quando devo criar uma exceção verificada e quando deve ser uma exceção de tempo de execução?

Quando escolher exceções marcadas e desmarcadas

Thang Pham
fonte
6
Eu tenho um ótimo exemplo de uma exceção desmarcada. Eu tenho uma DataSeriesclasse que contém dados que sempre devem permanecer em ordem baseada no tempo. Existe um método para adicionar um novo DataPointao final de um DataSeries. Se todo o meu código estiver funcionando corretamente durante todo o projeto, DataPointnunca 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.
Erick Robertson
3
Para adicionar ainda mais confusão. Muitas pessoas estavam defendendo exceções verificadas ~ 10 anos atrás, mas hoje em dia a visão está cada vez mais mudando para "exceções verificadas são ruins". (Eu, contudo, não concordar com isso)
Kaj
10
Só é útil para lidar com uma exceção quando você tem algo útil a fazer, caso contrário, você deve deixar o chamador lidar com isso. Registrá-lo e fingir que não aconteceu geralmente não é útil. Apenas jogar novamente é inútil. O agrupamento em uma RuntimeException não é tão útil quanto se pensa, apenas faz o compilador parar de ajudá-lo. (IMHO)
Peter Lawrey
40
Deveríamos parar de usar os termos abrangente e enganosos das exceções marcadas / não verificadas . Eles devem ser chamados de exceções de verificação obrigatória x verificação não obrigatória .
Blessed Geek
3
Eu também pensei que, em seu quinto ponto, o void público method_name lança Exception {} por que algumas pessoas fazem isso?
maVenツ

Respostas:

474

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:

  1. A NumberFormatExceptionconsideração é uma exceção verificada?
    No. NumberFormatExceptionestá desmarcado (= é subclasse de RuntimeException). Por quê? Eu não sei. (mas deveria ter havido um método isValidInteger(..))

  2. É RuntimeExceptionuma exceção desmarcada?
    Sim, exatamente.

  3. 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:

    • registre-o e retorne
    • repita-o (declare-o lançado pelo método)
    • construir uma nova exceção passando a atual no construtor
  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?
    Poderia ter sido. Mas nada impede você de capturar a exceção desmarcada também

  5. Por que as pessoas adicionam classe Exceptionna 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.

Bozho
fonte
36
Em relação ao lançamento de Exceção, nem sempre é porque as pessoas são preguiçosas, também é comum que, quando você implementa estruturas, permita que os usuários da estrutura possam lançar qualquer exceção. Você pode, por exemplo, verificar a assinatura da interface Callable no JSE
Kaj
10
@ Kaj - sim, coisas gerais como Callable, interceptores e gostos são casos especiais. Mas na maioria dos casos é porque as pessoas são preguiçosos :)
Bozho
7
re: 3.1 "registre e retorne" Faça isso criteriosamente. Isso está muito perto de comer ou se esconder e de uma exceção. Eu faria isso por algo que não indica um problema, que não é realmente excepcional. Os logs são inundados e ignorados com muita facilidade.
25712 Chris
4
"quando você deseja forçar o usuário da sua API a pensar em como lidar com a situação excepcional" - você não pode forçar ninguém a pensar se não quiser. Se eles não quiserem pensar, escreverão um bloco de exceção ruim que não faz absolutamente nada, ou pior, exclui ou interfere nas informações críticas de erro. É por isso que as exceções verificadas são uma falha.
Adrianos
3
@adrianos "... você não pode forçar ninguém a pensar se não quiser ...." Com essa linha de pensamento, também poderíamos remover erros de compilação .... Não estou realmente mirando em você, ouvi isso o argumento repetidamente e ainda assim a considera a pior explicação possível para rotular Exceções Marcadas como uma falha. Como uma observação lateral, eu já vi antes uma linguagem em que compilação (e erros de tempo de execução, na verdade) eram efetivamente tornados impossíveis por desing. Essa estrada levou a alguns lugares muito escuros.
Newtopian 11/08/16
233

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 para RuntimeExceptione 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.

Por que eles deixam a exceção borbulhar? Isnt manipular erro quanto mais cedo melhor? Por que borbulhar?

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.

Michael Borgwardt
fonte
3
Obrigado! Ocasionalmente, jogo exceções fora dos meus métodos por causa do princípio da porcaria no crape out. Um dos desenvolvedores da minha equipe deseja inserir uma expressão xpath inválida, cabe a eles lidar com a exceção. No caso improvável, eles capturam uma exceção e não fazem nada que ouvirão sobre isso na revisão de código.
precisa saber é o seguinte
12
"Qualquer coisa que seja uma subclasse de Throwable, exceto RuntimeException e suas subclasses, é uma exceção verificada." - Sua declaração está incorreta. O erro também herda Throwable e está desmarcado.
22412 Bartzilla
8
@JonasEicher: basicamente, uma das principais vantagens das exceções é que elas permitem escolher onde na pilha de chamadas você deseja lidar com erros, o que geralmente é bastante alto, mantendo as camadas entre completamente livres de artefatos de manipulação de erros. As exceções verificadas destroem exatamente essa vantagem. Outro problema é que a distinção marcada / desmarcada está ligada à classe de exceção, que também representa uma categorização conceitual de exceções - misturando dois aspectos que não estão necessariamente relacionados.
precisa
2
"mas a opinião da maioria parece ser que não vale a pena os problemas de design que ela cria". - Citação por favor?
kervin
3
@Bartzilla Sim. Para completar, como o javadoc para Throwablediz: "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"
Bart van Heukelom
74
  1. O acima é considerado uma exceção verificada? Não O fato de você estar manipulando uma exceção não a torna Checked Exceptionse for a RuntimeException.

  2. É RuntimeExceptionum unchecked exception? sim

Checked Exceptionssão subclassesde java.lang.Exception Unchecked Exceptionssão subclassesdejava.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.

P: devo exibir a exceção exata ou mascará-la usando a exceção?

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 everfaça o seguinte -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Em vez disso, faça o seguinte:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

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 exceptionvolte com ou sem quebra em qualquer exceção específica do aplicativo.

Na tentativa de captura RuntimeExceptions

RuntimeExceptionComo 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 a RuntimeException. Por exemplo:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Esta é uma má prática de programação. Em vez disso, uma verificação nula deveria ter sido feita como -

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Mas há momentos em que essa verificação de erro é cara, como formatação de números, considere isso:

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

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, NullPointerExceptione NumberFormatExceptionsão os dois RuntimeExceptions, a captura de um NullPointerExceptiondeve ser substituída por uma verificação nula graciosa, enquanto eu recomendo a captura NumberFormatExceptionexplícita para evitar a possível introdução de código suscetível a erros.

d-live
fonte
Obrigado. Mais uma pergunta quando você estiver borbulhando exception, devo expor a exceção exata ou mascará-la usando Exception. Escrevendo código em cima de algum código legado e Exceptionsendo borbulhado em todos os lugares. Gostaria de saber se este é o comportamento correto?
Thang Pham 24/05
1
Esta é uma pergunta muito boa e importante, editei minha resposta para incluir a explicação.
d-live
Muito obrigado. Seria possível para você me mostrar o conteúdo de LoginFailureException(sqle)?
Thang Pham 25/05
1
Eu não tenho nenhum código para essas coisas, apenas criei os nomes etc. Se você vir java.lang.Exception, ele tem 4 construtores, dois deles aceitam java.lang.Throwable. Em fragmentos acima presumi LoginFailureExceptionestende Exceptione declara um construtorpublic LoginFailureException(Throwable cause) { super(cause) }
d-vivo
Melhor resposta sobre o tópico. Eu acho que exceções de tempo de execução não devem ser capturadas porque essas exceções ocorrem devido à falta de boa programação. Estou totalmente de acordo com a parte "Comer fora 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".
huseyin
19

1 Se você não tiver certeza sobre uma exceção, verifique a API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

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 someMethodpara 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

Por que os designers decidiram forçar um método para especificar todas as exceções verificadas não capturadas que podem ser lançadas dentro de seu escopo? Qualquer exceção que possa ser lançada por um método faz parte da interface de programação pública do método. Aqueles que chamam um método devem conhecer as exceções que um método pode lançar, para que possam decidir o que fazer sobre eles. Essas exceções fazem parte da interface de programação desse método, como seus parâmetros e valor de retorno.

A próxima pergunta pode ser: "Se é tão bom documentar a API de um método, incluindo as exceções que ele pode lançar, por que não especificar também exceções de tempo de execução?" As exceções de tempo de execução representam problemas resultantes de um problema de programação e, como tal, não se pode esperar que o código do cliente da API se recupere deles ou os manipule de qualquer maneira. Tais problemas incluem exceções aritméticas, como dividir por zero; exceções de ponteiro, como tentar acessar um objeto através de uma referência nula; e exceções de indexação, como tentar acessar um elemento da matriz por meio de um índice que é muito grande ou muito pequeno.

Há também algumas informações importantes na especificação da linguagem Java :

As classes de exceção verificadas nomeadas na cláusula throws fazem parte do contrato entre o implementador e o usuário do método ou construtor .

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.

Aleadam
fonte
Obrigado. Mais uma pergunta quando você estiver borbulhando exception, devo expor a exceção exata ou mascará-la usando Exception. Escrevendo código em cima de algum código legado e Exceptionsendo borbulhado em todos os lugares. Gostaria de saber se este é o comportamento correto?
Thang Pham
1
@Harry Vou permitir que pessoas com mais conhecimento do que eu respondam: stackoverflow.com/questions/409563/…
Aleadam
10

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 IllegalArgumentExceptionqual é uma subclasse de RuntimeException.

2) RuntimeExceptioné a raiz de todas as exceções não verificadas. Cada subclasse de RuntimeExceptionestá desmarcada. Todas as outras exceções e Throwablesão verificadas, exceto Erros (abaixo Throwable).

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 Exceptionocorre porque o programador não verificou as entradas (no caso de NumberFormatExceptionsua primeira pergunta). É por isso que é opcional capturá-los, porque existem maneiras mais elegantes de evitar gerar essas exceções.

dontocsata
fonte
Obrigado. Mais uma pergunta quando você estiver borbulhando exception, devo expor a exceção exata ou mascará-la usando Exception. Escrevendo código em cima de algum código legado e Exceptionsendo borbulhado em todos os lugares. Gostaria de saber se este é o comportamento correto?
Thang Pham
Você também pode fazer com que seu método gere Exception (o que não é o ideal). Ou pegue a exceção e ative uma exceção melhor (como IOException ou algo assim). Todas as exceções podem considerar uma exceção no construtor como uma 'causa'; portanto, você deve usá-la.
Dontocsata 25/05
8

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..

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Aqui, a exceção ocorre devido a dados incorretos e de forma alguma podem ser determinados durante o tempo de compilação.

bharanitharan
fonte
6

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/

Jatinder Pal
fonte
5

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):

Aqui está a orientação: se um cliente puder recuperar razoavelmente de uma exceção, torne-a uma exceção verificada. Se um cliente não puder fazer nada para se recuperar da exceção, torne-a uma exceção desmarcada

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.

Thomas
fonte
5

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:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

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. Jogar Exceptionsignifica "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á.

Tom Dibble
fonte
Exatamente, faça da sua declaração de exceção de verificação parte da documentação do código e ajude a pessoa que está usando o software.
Salvador Valencia
5

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.

Omer
fonte
3

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.

JAVA
fonte
Bom ponto. O que isso significa é colocá-lo na camada mais responsável que controla o fluxo lógico e supervisiona a lógica de negócios do aplicativo. Seria impossível, por exemplo, que a camada do banco de dados comunicasse ao cliente que algo crítico está ausente ou sem resposta. Quando atinge a camada superior do servidor, é fácil atualizar a exibição do cliente com uma mensagem de erro crítica.
Salvador Valencia
3

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/

Dan Moldovan
fonte
3

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 CheckedExceptionalgum lugar na assinatura do método ( CheckedExceptionpode 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

public interface IFoo {
    public void foo();
}

Agora podemos escrever muitas implementações de método foo(), como estas

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

A classe Foo está perfeitamente bem. Agora vamos fazer uma primeira tentativa na classe Bar

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

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.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

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 usar foo = new Bar();. Se o método foo () de Bar não substituir o método foo de IFoo, quando o fizer foo.foo();, não chamará a implementação de foo () de Bar.

Para fazer a public void foo() throws InterruptedExceptionsubstituição do IFoo do Bar, public void foo()DEVO adicionar throws 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 adicionasse throws InterruptedExceptionao 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.

Blueriver
fonte
2
Sim, é ruim porque você disse que não queria pegá-lo. Mas para evitar afetar a assinatura da IFOO, você precisará. Prefiro fazer isso e seguir em frente em vez de reequilibrar todas as minhas assinaturas de interfaces para evitar capturar uma exceção (apenas porque as exceções são MAUS).
Salvador Valencia
Sim, eu concordo. Eu estava um pouco confuso sobre alguma coisa. Eu quero que uma exceção se propague, para que eu possa lidar com isso em outro lugar. Uma solução é capturar a InterruptedException e lançar uma exceção não verificada. ou seja, nós evitar exceções verificadas e passar em torno de exceções não verificadas (mesmo que eles só fazem sentido como um wrapper)
Blueriver
"Isso, no entanto, causará problemas na minha classe Foo, pois a assinatura do método foo () difere da assinatura do método IFoo". Acabei de testar sua ideia e é possível compilar mesmo se adicionarmos 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çada Exception, ela apenas oferece à implementação a opção de lançar ou não uma exceção (qualquer exceção, pois Exceptionencapsula todas as exceções).
Flyout91
No entanto, admito que pode ser confuso porque, quando você implementa essa interface e clica em algo como "Adicionar métodos não implementados", eles são criados automaticamente com a throw Exceptionclá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.
Flyout91
Isso erra o ponto inteiro. O objetivo de uma interface é declarar o contrato que um cliente precisa ser satisfeito. Isso pode incluir cenários de falha com os quais ele pode lidar. Quando uma implementação encontra um erro, ele deve mapear esse erro para a falha abstrata apropriada declarada pela interface do cliente.
21718
3
  • Java distingue entre duas categorias de exceções (marcada e desmarcada).
  • Java impõe um requisito catch ou declarado para exceções verificadas.
  • O tipo de uma exceção determina se uma exceção é marcada ou desmarcada.
  • Todos os tipos de exceção que são diretos ou indiretos subclassesda classe RuntimeException são uma exceção desmarcada.
  • Todas as classes que herdam da classe, Exceptionmas não RuntimeExceptionsão consideradas checked exceptions.
  • Classes que herdam da classe Error são consideradas desmarcadas.
  • O compilador verifica cada chamada e desaceleração do método para determinar se o método é lançado checked exception.
    • Nesse caso, o compilador garante que a exceção seja capturada ou declarada em uma cláusula throws.
  • Para satisfazer a parte declarada do requisito de pegar ou declarar, o método que gera a exceção deve fornecer um throws cláusula contendo o checked-exception.
  • Exception As classes são definidas para serem verificadas quando consideradas importantes o suficiente para serem capturadas ou declaradas.
tokhi
fonte
2

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).

rghome
fonte
2

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.

Zoran Pandovski
fonte
2

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 RuntimeExceptionou Error.

Neste vídeo, ele explica exceções marcadas e desmarcadas em Java:
https://www.youtube.com/watch?v=ue2pOqLaArw

Ozgen
fonte
1

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.

mamboking
fonte
hum. se NumberFormatException for uma exceção verificada, como você diz, não contradiz o fato de ser herdada de RuntimeException ?
eis
Desculpe, eu não estava muito claro. Eu estava me referindo ao FileNotFoundException e não ao NumberFormatException. Com base nos nºs 2 e 4, parecia que ele achava que Checked vs. Unchecked se baseava em como você lida com a exceção após capturá-la. Não como foi definido.
mamboking
-1

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

Slawomir
fonte
4
Porque é apenas a maioria dos chamadores, nem todos os que chamam, que deve quebrar e retroceder. O fato de a exceção ser verificada significa que o chamador deve pensar se é um dos "mais" chamadores ou uma minoria que pode e deve lidar com a exceção.
Warren Orvalho
1
Se você gosta de verificar erros em todas as chamadas feitas, "volte" para C. As exceções são uma maneira de separar a execução normal do programa de anormal, sem poluir o seu código. As exceções garantem que você não possa ignorar um erro silenciosamente em algum nível .
Slawomir
-1

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.

  • Se estes não forem tratados adequadamente, ocorrerão erros de tempo de compilação (sem exceçã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).

Varun Vashista
fonte
-2

Todas as exceções devem ser verificadas.

  1. Exceções não verificadas são gotos irrestritos. E os gotos irrestritos são considerados uma coisa ruim.

  2. 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.

  3. 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.

shawnhcorey
fonte