Quando escolher exceções marcadas e desmarcadas

213

Em Java (ou qualquer outro idioma com exceções verificadas), ao criar sua própria classe de exceção, como você decide se deve ser verificada ou desmarcada?

Meu instinto é dizer que uma exceção verificada seria solicitada nos casos em que o chamador pudesse se recuperar de alguma maneira produtiva, onde, como uma exceção não verificada, seria mais para casos irrecuperáveis, mas eu estaria interessado nos pensamentos de outras pessoas.

Matt Sheppard
fonte
11
Barry Ruzek escreveu um excelente guia sobre como escolher exceções marcadas ou não.
sigget

Respostas:

241

As exceções marcadas são ótimas, desde que você entenda quando elas devem ser usadas. A API principal do Java falha ao seguir essas regras para SQLException (e algumas vezes para IOException), e é por isso que elas são tão terríveis.

As exceções verificadas deve ser usado para previsíveis , mas inevitáveis erros que são razoáveis para se recuperar de .

Exceções não verificadas devem ser usadas para todo o resto.

Vou explicar isso para você, porque a maioria das pessoas não entende o que isso significa.

  1. Previsível, mas inevitável : O chamador fez tudo o que estava ao seu alcance para validar os parâmetros de entrada, mas alguma condição fora de seu controle causou uma falha na operação. Por exemplo, você tenta ler um arquivo, mas alguém o exclui entre o momento em que verifica se ele existe e o momento em que a operação de leitura começa. Ao declarar uma exceção verificada, você está dizendo ao chamador para antecipar esta falha.
  2. Razoável para se recuperar : Não faz sentido dizer aos chamadores que antecipem exceções das quais não podem se recuperar. Se um usuário tentar ler um arquivo inexistente, o chamador poderá solicitar um novo nome de arquivo. Por outro lado, se o método falhar devido a um erro de programação (argumentos de método inválidos ou implementação de método de buggy), não há nada que o aplicativo possa fazer para corrigir o problema no meio da execução. O melhor que pode fazer é registrar o problema e aguardar que o desenvolvedor o conserte posteriormente.

A menos que a exceção que você está lançando atenda a todas as condições acima, ela deve usar uma exceção não verificada.

Reavaliar em todos os níveis : Às vezes, o método que captura a exceção verificada não é o lugar certo para lidar com o erro. Nesse caso, considere o que é razoável para os seus chamadores. Se a exceção for previsível, imprevisível e razoável para a recuperação, então você deve lançar uma exceção marcada. Caso contrário, você deve agrupar a exceção em uma exceção desmarcada. Se você seguir esta regra, você se converterá exceções verificadas em exceções não verificadas e vice-versa, dependendo da camada em que se encontra.

Para exceções marcadas e desmarcadas, use o nível de abstração correto . Por exemplo, um repositório de código com duas implementações diferentes (banco de dados e sistema de arquivos) deve evitar expor detalhes específicos da implementação, jogando SQLExceptionou IOException. Em vez disso, ele deve agrupar a exceção em uma abstração que abranja todas as implementações (por exemplo RepositoryException).

Gili
fonte
2
"você tenta ler um arquivo, mas alguém o exclui entre o momento em que você verifica se ele existe e o momento em que a operação de leitura começa." => Como isso é 'esperado'? Para mim, parece mais: Inesperado e evitável. Quem esperaria que um arquivo fosse excluído apenas entre duas instruções?
Koray Tugay
9
@KorayTugay Expected não significa que o cenário seja típico. Significa apenas que podemos prever que esse erro ocorra antes do tempo (em comparação com erros de programação que não podem ser previstos com antecedência). Inevitável é o fato de que o programador não pode fazer nada para impedir que o usuário ou outros aplicativos excluam um arquivo entre o momento em que verificamos se ele existe e o momento em que a operação de leitura é iniciada.
Gili
Portanto, qualquer problema relacionado ao banco de dados dentro do método deve gerar uma exceção verificada?
ivanjermakov
59

De um aluno de Java :

Quando uma exceção ocorre, você precisa capturar e manipular a exceção ou informar ao compilador que não pode manipulá-la declarando que seu método lança essa exceção, então o código que usa seu método precisará lidar com essa exceção (até mesmo também pode optar por declarar que lança a exceção se não puder lidar com isso).

O compilador verificará se fizemos uma das duas coisas (pegar ou declarar). Portanto, essas são chamadas exceções verificadas. Porém, erros e exceções de tempo de execução não são verificados pelo compilador (mesmo que você possa escolher capturar ou declarar, isso não é obrigatório). Portanto, esses dois são chamados de exceções não verificadas.

Os erros são usados ​​para representar as condições que ocorrem fora do aplicativo, como falhas do sistema. As exceções de tempo de execução geralmente ocorrem por falha na lógica do aplicativo. Você não pode fazer nada nessas situações. Quando ocorrer uma exceção de tempo de execução, você precisará reescrever o código do programa. Portanto, eles não são verificados pelo compilador. Essas exceções de tempo de execução serão reveladas no período de desenvolvimento e teste. Em seguida, precisamos refatorar nosso código para remover esses erros.

Espo
fonte
13
Essa é a visão ortodoxa. Mas há muita controvérsia sobre isso.
Artbristol
49

A regra que eu uso é: nunca use exceções não verificadas! (ou quando você não vê nenhuma maneira de contornar isso)

Há um argumento muito forte para o contrário: nunca use exceções verificadas. Estou relutante em tomar partido no debate, mas parece haver um amplo consenso de que a introdução de exceções verificadas foi uma decisão errada em retrospectiva. Por favor, não atire no mensageiro e consulte esses argumentos .

Konrad Rudolph
fonte
3
IMHO, as exceções verificadas poderiam ter sido um recurso importante se houvesse uma maneira fácil de um método declarar que não está esperando que os métodos chamados em um bloco de código específico lançem certas exceções (ou nenhuma) e que qualquer verificação as exceções lançadas contrárias a essa expectativa devem ser agrupadas em algum outro tipo de exceção e reapresentadas. Eu diria que 90% do tempo em que o código não está preparado para lidar com uma exceção verificada, esse empacotamento e repetição seria a melhor maneira de lidar com isso, mas porque raramente há suporte para o idioma.
supercat
@supercat Essencialmente é isso: eu sou um fã obstinado de verificação estrita de tipo e exceções verificadas são uma extensão lógica disso. Eu abandonei completamente as exceções verificadas, apesar de eu conceitualmente gostar muito delas.
Konrad Rudolph
1
Uma irritação que tenho com o design de exceções, que o mecanismo que descrevi solucionaria, é que, se fooestiver documentada como lançada barExceptionao ler o final de um arquivo e foochamar um método que lança, barExceptionmesmo que foonão esteja esperando, o código que chama fooachará que o final do arquivo foi atingido e não terá idéia de que algo inesperado aconteceu. Eu consideraria essa situação como aquela em que as exceções verificadas devem ser mais úteis, mas também é o único caso em que o compilador permitirá exceções verificadas não tratadas.
supercat
@ supercat: Já existe uma maneira fácil de o código fazer o que você deseja no primeiro comentário: agrupar o código em um bloco try, capturar Exception e agrupar a Exception em um RuntimeException e repetir.
Warren Orvalho
1
@KonradRudolph supercat se refere a "um bloco de código específico"; dado que o bloco deve ser definido, a sintaxe declarativa não reduziria significativamente o inchaço. Se você está pensando que isso seria declarativo para toda a função, isso encorajaria uma programação ruim, pois as pessoas apenas aderiram à declaração em vez de realmente olhar para as exceções verificadas potencialmente capturadas e garantir que não haja outra maneira melhor para lidar com eles.
Warren Orvalho
46

Em qualquer sistema grande o suficiente, com muitas camadas, as exceções verificadas são inúteis, pois, de qualquer maneira, você precisa de uma estratégia de nível arquitetural para lidar com como a exceção será tratada (use uma barreira de falha)

Com exceções verificadas, sua estratégia de tratamento de erros é microgerenciada e insuportável em qualquer sistema grande.

Na maioria das vezes, você não sabe se um erro é "recuperável" porque não sabe em que camada o chamador da sua API está localizado.

Digamos que eu crie uma API StringToInt que converta a representação de string de um número inteiro em um Int. Devo lançar uma exceção verificada se a API for chamada com a string "foo"? É recuperável? Eu não sei porque na camada dele, o chamador da minha API StringToInt já pode ter validado a entrada, e se essa exceção for lançada, é um bug ou uma corrupção de dados e não é recuperável para essa camada.

Nesse caso, o chamador da API não deseja capturar a exceção. Ele só quer deixar a exceção "borbulhar". Se eu escolher uma exceção marcada, esse chamador terá bastante bloco de captura inútil apenas para repetir artificialmente a exceção.

O que é recuperável depende na maioria das vezes do chamador da API, não do gravador da API. Uma API não deve usar exceções verificadas, pois somente as exceções não verificadas permitem escolher capturar ou ignorar uma exceção.

Stephane
fonte
3
Isso é muito próximo ao userstories.blogspot.com/2008/12/…
alexsmail
15
@alexsmail Internet nunca deixa de surpreender-me, na verdade, é o meu blog :)
Stephane
30

Você está certo.

Exceções não verificadas são usadas para deixar o sistema falhar rapidamente, o que é uma coisa boa. Você deve indicar claramente qual é o seu método esperado para funcionar corretamente. Dessa forma, você pode validar a entrada apenas uma vez.

Por exemplo:

/**
 * @params operation - The operation to execute.
 * @throws IllegalArgumentException if the operation is "exit"
 */
 public final void execute( String operation ) {
     if( "exit".equals(operation)){
          throw new IllegalArgumentException("I told you not to...");
     }
     this.operation = operation; 
     .....  
 }
 private void secretCode(){
      // we perform the operation.
      // at this point the opreation was validated already.
      // so we don't worry that operation is "exit"
      .....  
 }

Apenas para colocar um exemplo. O ponto é que, se o sistema falhar rapidamente, você saberá onde e por que falhou. Você obterá um rastreamento de pilha como:

 IllegalArgumentException: I told you not to use "exit" 
 at some.package.AClass.execute(Aclass.java:5)
 at otherPackage.Otherlass.delegateTheWork(OtherClass.java:4569)
 ar ......

E você saberá o que aconteceu. O OtherClass no método "delegateTheWork" (na linha 4569) chamou sua classe com o valor "exit", mesmo quando não deveria etc.

Caso contrário, você teria que espalhar as validações por todo o código e isso é propenso a erros. Além disso, às vezes é difícil rastrear o que deu errado e você pode esperar horas de depuração frustrante

O mesmo acontece com NullPointerExceptions. Se você tiver uma classe de 700 linhas com cerca de 15 métodos, que usa 30 atributos e nenhum deles pode ser nulo, em vez de validar cada um desses métodos para a nulidade, você pode tornar todos esses atributos somente leitura e validá-los no construtor ou método de fábrica.

 public static MyClass createInstane( Object data1, Object data2 /* etc */ ){ 
      if( data1 == null ){ throw NullPointerException( "data1 cannot be null"); }

  }


  // the rest of the methods don't validate data1 anymore.
  public void method1(){ // don't worry, nothing is null 
      ....
  }
  public void method2(){ // don't worry, nothing is null 
      ....
  }
  public void method3(){ // don't worry, nothing is null 
      ....
  }

Exceções verificadas São úteis quando o programador (você ou seus colegas de trabalho) fez tudo certo, validou a entrada, executou testes e todo o código está perfeito, mas o código se conecta a um serviço da web de terceiros que pode estar inoperante (ou um arquivo você estava usando foi excluído por outro processo externo, etc). O serviço da web pode até ser validado antes da tentativa de conexão, mas durante a transferência de dados algo deu errado.

Nesse cenário, não há nada que você ou seus colegas de trabalho possam fazer para ajudá-lo. Mas você ainda precisa fazer alguma coisa e não deixar que o aplicativo morra e desapareça aos olhos do usuário. Você usa uma exceção marcada para isso e lida com a exceção, o que você pode fazer quando isso acontece ?, na maioria das vezes, apenas para tentar registrar o erro, provavelmente salve seu trabalho (o trabalho do aplicativo) e apresente uma mensagem ao usuário . (O site blabla está fora do ar, tente novamente mais tarde etc.)

Se a exceção verificada for usada em excesso (adicionando a "exceção de lançamento" em todas as assinaturas de métodos), seu código se tornará muito frágil, porque todo mundo ignorará essa exceção (porque é muito geral) e a qualidade do código será seriamente comprometida.

Se você usar a exceção desmarcada, algo semelhante acontecerá. Os usuários desse código não sabem se algo pode dar errado; muitas tentativas {...} catch (Throwable t) aparecerão.

OscarRyz
fonte
2
Bem dito! +1. Surpreende-me sempre este chamador distinção (desmarcado) / receptor (marcado) não é mais óbvio ...
VonC
19

Aqui está minha 'regra final'.
Eu uso:

  • exceção não verificada no código do meu método para uma falha devido ao chamador (que envolve uma documentação explícita e completa )
  • exceção marcada para uma falha devido ao chamado que eu preciso tornar explícito para quem quiser usar meu código

Compare com a resposta anterior, esta é uma lógica clara (sobre a qual uma pessoa pode concordar ou discordar) para o uso de um ou outro (ou ambos) tipos de exceções.


Para essas duas exceções, criarei minha própria exceção não verificada e verificada para o meu aplicativo (uma boa prática, conforme mencionado aqui ), exceto para uma exceção não verificada muito comum (como NullPointerException)

Por exemplo, o objetivo desta função específica abaixo é criar (ou obter, se já existir) um objeto, o que
significa:

  • o contêiner do objeto para criar / obter DEVE existir (responsabilidade da CHAMADA
    => exceção desmarcada E limpar o comentário javadoc para essa função chamada)
  • os outros parâmetros não podem ser nulos
    (escolha do codificador para colocá-lo na CHAMADA: o codificador não verificará o parâmetro nulo, mas o codificador DOCUMENTA)
  • o resultado NÃO PODE SER NULO
    (responsabilidade e escolha do código do chamado, escolha que será de grande interesse para o chamador
    => exceção verificada, pois todos os chamadores DEVEM tomar uma decisão se o objeto não puder ser criado / encontrado e que A decisão deve ser executada no momento da compilação: eles não podem usar esta função sem precisar lidar com essa possibilidade, ou seja, com essa exceção verificada ).

Exemplo:


/**
 * Build a folder. <br />
 * Folder located under a Parent Folder (either RootFolder or an existing Folder)
 * @param aFolderName name of folder
 * @param aPVob project vob containing folder (MUST NOT BE NULL)
 * @param aParent parent folder containing folder 
 *        (MUST NOT BE NULL, MUST BE IN THE SAME PVOB than aPvob)
 * @param aComment comment for folder (MUST NOT BE NULL)
 * @return a new folder or an existing one
 * @throws CCException if any problems occurs during folder creation
 * @throws AssertionFailedException if aParent is not in the same PVob
 * @throws NullPointerException if aPVob or aParent or aComment is null
 */
static public Folder makeOrGetFolder(final String aFoldername, final Folder aParent,
    final IPVob aPVob, final Comment aComment) throws CCException {
    Folder aFolderRes = null;
    if (aPVob.equals(aParent.getPVob() == false) { 
       // UNCHECKED EXCEPTION because the caller failed to live up
       // to the documented entry criteria for this function
       Assert.isLegal(false, "parent Folder must be in the same PVob than " + aPVob); }

    final String ctcmd = "mkfolder " + aComment.getCommentOption() + 
        " -in " + getPNameFromRepoObject(aParent) + " " + aPVob.getFullName(aFolderName);

    final Status st = getCleartool().executeCmd(ctcmd);

    if (st.status || StringUtils.strictContains(st.message,"already exists.")) {
        aFolderRes = Folder.getFolder(aFolderName, aPVob);
    }
    else {
        // CHECKED EXCEPTION because the callee failed to respect his contract
        throw new CCException.Error("Unable to make/get folder '" + aFolderName + "'");
    }
    return aFolderRes;
}
VonC
fonte
19

Não se trata apenas da capacidade de recuperar-se da exceção. O que importa mais, na minha opinião, é se o chamador está interessado em capturar a exceção ou não.

Se você escrever uma biblioteca para ser usada em outro lugar ou uma camada de nível inferior em seu aplicativo, pergunte a si mesmo se o chamador está interessado em capturar (conhecer) sua exceção. Se ele não estiver, use uma exceção não verificada, para não sobrecarregá-lo desnecessariamente.

Essa é a filosofia usada por muitos frameworks. Spring e hibernate, em particular, vêm à mente - eles convertem a exceção verificada conhecida em exceção não verificada precisamente porque as exceções verificadas são usadas em excesso no Java. Um exemplo em que consigo pensar é na JSONException do json.org, que é uma exceção verificada e é principalmente irritante - deve ser desmarcada, mas o desenvolvedor simplesmente não pensou nisso.

A propósito, na maioria das vezes o interesse do chamador na exceção está diretamente correlacionado à capacidade de recuperar-se da exceção, mas esse nem sempre é o caso.

Yoni
fonte
13

Aqui está uma solução muito simples para o seu dilema Marcado / Não verificado.

Regra 1: Pense em uma exceção não verificada como uma condição testável antes da execução do código. por exemplo…

x.doSomething(); // the code throws a NullPointerException

onde x é nulo ...… o código deve ter o seguinte…

if (x==null)
{
    //do something below to make sure when x.doSomething() is executed, it won’t throw a NullPointerException.
    x = new X();
}
x.doSomething();

Regra 2: Pense em uma exceção verificada como uma condição não testável que pode ocorrer enquanto o código é executado.

Socket s = new Socket(“google.com”, 80);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

… No exemplo acima, o URL (google.com) pode não estar disponível devido ao servidor DNS estar inativo. Mesmo no instante em que o servidor DNS estava funcionando e resolvia o nome 'google.com' para um endereço IP, se a conexão fosse feita ao google.com, a qualquer momento, a rede poderia cair. Você simplesmente não pode testar a rede o tempo todo antes de ler e gravar em fluxos.

Há momentos em que o código simplesmente deve ser executado antes que possamos saber se há algum problema. Ao forçar os desenvolvedores a escrever seu código de maneira a forçá-los a lidar com essas situações por meio da Checked Exception, tenho que dar gorjeta ao criador de Java que inventou esse conceito.

Em geral, quase todas as APIs em Java seguem as 2 regras acima. Se você tentar gravar em um arquivo, o disco poderá ser preenchido antes de concluir a gravação. É possível que outros processos tenham causado o disco ficar cheio. Simplesmente não há como testar essa situação. Para aqueles que interagem com o hardware onde, a qualquer momento, o uso do hardware pode falhar, as exceções verificadas parecem ser uma solução elegante para esse problema.

Há uma área cinza nisso. No caso de serem necessários muitos testes (uma declaração alucinante se com muitos && e ||), a exceção lançada será uma CheckedException simplesmente porque é muito trabalhoso acertar - você simplesmente não pode dizer esse problema é um erro de programação. Se houver muito menos que 10 testes (por exemplo, 'if (x == null)'), o erro do programador deve ser uma UncheckedException.

As coisas ficam interessantes ao lidar com intérpretes de idiomas. De acordo com as regras acima, um erro de sintaxe deve ser considerado uma exceção verificada ou não verificada? Eu argumentaria que, se a sintaxe do idioma puder ser testada antes de ser executada, deve ser uma UncheckedException. Se o idioma não puder ser testado - semelhante à maneira como o código de montagem é executado em um computador pessoal, o Erro de sintaxe deve ser uma exceção verificada.

As 2 regras acima provavelmente removerão 90% de sua preocupação sobre a escolha. Para resumir as regras, siga este padrão… 1) se o código a ser executado puder ser testado antes de ser executado corretamente e se ocorrer uma exceção - também conhecido como erro de programador, a exceção deve ser uma UncheckedException (uma subclasse de RuntimeException ) 2) se o código a ser executado não puder ser testado antes de ser executado corretamente, a exceção deve ser uma exceção verificada (uma subclasse de exceção).

user3598189
fonte
9

Você pode chamá-lo de uma exceção marcada ou desmarcada; no entanto, os dois tipos de exceção podem ser capturados pelo programador, portanto, a melhor resposta é: escreva todas as exceções como desmarcadas e documente-as. Dessa forma, o desenvolvedor que usa sua API pode escolher se deseja capturar essa exceção e fazer alguma coisa. As exceções verificadas são um desperdício completo do tempo de todos e isso torna seu código um pesadelo chocante de se ver. O teste de unidade adequado trará quaisquer exceções que você possa ter que capturar e fazer alguma coisa.

Colin Saxton
fonte
1
+1 Para mencionar que os testes de unidade podem ser uma maneira melhor de resolver o problema, as exceções verificadas se destinam a resolver.
Keith Pinson
+1 para teste de unidade. O uso de exceções marcadas / não marcadas tem pouco impacto na qualidade do código. Portanto, o argumento de que se alguém usar exceções verificadas resultaria em melhor qualidade de código é um argumento falso e completo!
user1697575
7

Exceção verificada: se o cliente puder se recuperar de uma exceção e desejar continuar, use a exceção verificada.

Exceção não verificada: se um cliente não puder fazer nada após a exceção, aumente a exceção não verificada.

Exemplo: Se você espera executar operações aritméticas em um método A () e com base na saída de A (), você deve executar outra operação. Se a saída for nula do método A () que você não espera durante o tempo de execução, é esperado que você ative Exceção de ponteiro nulo, que é exceção de tempo de execução.

Consulte aqui

Alcances
fonte
2

Concordo com a preferência por exceções não verificadas como regra, especialmente ao criar uma API. O chamador sempre pode optar por capturar uma exceção documentada e não marcada. Você simplesmente não está forçando desnecessariamente o chamador.

Acho as exceções verificadas úteis no nível inferior, como detalhes da implementação. Muitas vezes, parece um mecanismo de fluxo de controle melhor do que ter que gerenciar um erro "código de retorno" especificado. Às vezes, também pode ajudar a ver o impacto de uma ideia para uma alteração de código de nível baixo ... declarar uma exceção verificada no downstream e ver quem precisaria se ajustar. Este último ponto não se aplica se houver muitos itens genéricos: catch (Exceção e) ou lança Exception, que geralmente não é muito bem pensada.

Scott Kurz
fonte
2

Aqui está, quero compartilhar minha opinião que tenho após muitos anos de experiência em desenvolvimento:

  1. Exceção marcada. Isso faz parte do caso de uso de negócios ou do fluxo de chamadas, parte da lógica do aplicativo que esperamos ou não. Por exemplo, conexão rejeitada, a condição não é satisfeita etc. Precisamos lidar com isso e mostrar a mensagem correspondente ao usuário com instruções sobre o que aconteceu e o que fazer em seguida (tente novamente mais tarde, etc.). Eu costumo chamar isso de exceção de pós-processamento ou exceção de "usuário".

  2. Exceção desmarcada. Isso faz parte da exceção de programação, algum erro na programação de código de software (bug, defeito) e reflete uma maneira como os programadores devem usar a API conforme a documentação. Se um documento externo da lib / framework disser que espera obter dados em algum intervalo e não nulos, porque o NPE ou o IllegalArgumentException serão lançados, o programador deve esperar e usar a API corretamente conforme a documentação. Caso contrário, a exceção será lançada. Eu geralmente chamo de exceção de pré-processamento ou exceção de "validação".

Por público-alvo. Agora, vamos falar sobre o público-alvo ou grupo de pessoas em que as exceções foram criadas (conforme minha opinião):

  1. Exceção marcada. Público-alvo são usuários / clientes.
  2. Exceção desmarcada. O público-alvo são desenvolvedores. Por outras palavras, a exceção desmarcada foi projetada apenas para desenvolvedores.

Por fase do ciclo de vida de desenvolvimento de aplicativos.

  1. A exceção verificada foi projetada para existir durante todo o ciclo de vida da produção, como mecanismo normal e esperado, de um aplicativo para lidar com casos excepcionais.
  2. A exceção não verificada foi projetada para existir apenas durante o ciclo de vida de desenvolvimento / teste do aplicativo, todos eles devem ser corrigidos durante esse período e não devem ser lançados quando um aplicativo já estiver em execução na produção.

A razão pela qual as estruturas geralmente usam exceções não verificadas (Spring, por exemplo) é que a estrutura não pode determinar a lógica de negócios do seu aplicativo; cabe aos desenvolvedores capturar e projetar a própria lógica.

Denys
fonte
2

Temos que distinguir esses dois tipos de exceção com base no erro do programador ou não.

  • Se um erro é um erro de programador, deve ser uma exceção não verificada . Por exemplo: SQLException / IOException / NullPointerException. Essas exceções são erros de programação. Eles devem ser manuseados pelo programador. Enquanto na API JDBC, SQLException é exceção verificada, no Spring JDBCTemplate é uma exceção não verificada. O programador não se preocupa com SqlException, quando usa Spring.
  • Se um erro não é um erro do programador e o motivo é externo, deve ser uma exceção verificada. Por exemplo: se o arquivo for excluído ou a permissão do arquivo for alterada por outra pessoa, ele deverá ser recuperado.

FileNotFoundException é um bom exemplo para entender diferenças sutis. FileNotFoundException é lançado caso o arquivo não seja encontrado. Há dois motivos para essa exceção. Se o caminho do arquivo for definido pelo desenvolvedor ou obtendo do usuário final via GUI, deve ser uma exceção não verificada. Se o arquivo for excluído por outra pessoa, deve ser uma exceção verificada.

A exceção verificada pode ser tratada de duas maneiras. Eles estão usando try-catch ou propagam a exceção. No caso de propagação de exceção, todos os métodos na pilha de chamadas serão fortemente acoplados devido ao tratamento de exceções. É por isso que temos que usar a exceção verificada com cuidado.

Caso você desenvolva um sistema corporativo em camadas, é necessário escolher a exceção não verificada a ser lançada, mas não se esqueça de usar a exceção verificada para o caso de não poder fazer nada.

ailhanli
fonte
1

As exceções marcadas são úteis para casos recuperáveis ​​em que você deseja fornecer informações ao chamador (por exemplo, permissões insuficientes, arquivo não encontrado, etc.).

Exceções não verificadas são usadas raramente, se houver, para informar o usuário ou programador sobre erros graves ou condições inesperadas durante o tempo de execução. Não jogue-os se estiver escrevendo código ou bibliotecas que serão usadas por outros, pois eles podem não estar esperando que seu software gere exceções não verificadas, pois o compilador não os força a serem capturados ou declarados.

David Crow
fonte
Não concordo com a sua afirmação "Exceções não verificadas são usadas raramente, se é que existem" de fato devem ser opostas! Use excprions não verificados por padrão ao criar a hierarquia de exceções do aplicativo. Permita que os desenvolvedores decidam quando querem lidar com a exceção (por exemplo, eles não são forçados a colocar blocos catch ou cláusula throws se não souberem como lidar com isso).
user1697575
1

Sempre que uma exceção é menos provável, e podemos prosseguir mesmo depois de capturá-la, e não podemos fazer nada para evitar essa exceção, então podemos usar a exceção verificada.

Sempre que queremos fazer algo significativo quando uma exceção específica acontece e quando essa exceção é esperada, mas não certa, podemos usar a exceção verificada.

Sempre que a exceção navega em camadas diferentes, não precisamos capturá-la em todas as camadas; nesse caso, podemos usar a exceção de tempo de execução ou agrupar a exceção como exceção não verificada.

A exceção de tempo de execução é usada quando a exceção é mais provável de ocorrer, não há como ir além e nada pode ser recuperável. Portanto, neste caso, podemos tomar precauções com relação a essa exceção. EX: NUllPointerException, ArrayOutofBoundsException. É mais provável que isso aconteça. Nesse cenário, podemos tomar precauções durante a codificação para evitar essa exceção. Caso contrário, teremos que escrever blocos try catch em todos os lugares.

Exceções mais gerais podem ser feitas Desmarcadas, menos gerais são verificadas.

ramu p
fonte
1

Penso que podemos pensar nas exceções de várias perguntas:

por que a exceção acontece? O que podemos fazer quando isso acontece

por engano, um bug. como um método de objeto nulo é chamado.

String name = null;
... // some logics
System.out.print(name.length()); // name is still null here

Esse tipo de exceção deve ser corrigido durante o teste. Caso contrário, ele interrompe a produção e você tem um bug muito alto que precisa ser corrigido imediatamente. Esse tipo de exceção não precisa ser verificado.

por entrada de externo, você não pode controlar ou confiar na saída do serviço externo.

String name = ExternalService.getName(); // return null
System.out.print(name.length());    // name is null here

Aqui, pode ser necessário verificar se o nome é nulo se você quiser continuar quando for nulo; caso contrário, poderá deixá-lo em paz e ele será interrompido aqui e dará ao chamador a exceção do tempo de execução. Esse tipo de exceção não precisa ser verificado.

por exceção de tempo de execução de externo, você não pode controlar ou confiar no serviço externo.

Aqui, pode ser necessário capturar todas as exceções do ExternalService se você quiser continuar quando isso acontecer, caso contrário, poderá deixar em paz e ele será interrompido aqui e dará ao chamador a exceção do tempo de execução.

por exceção verificada de externo, você não pode controlar ou confiar no serviço externo.

Aqui, pode ser necessário capturar todas as exceções do ExternalService se você quiser continuar quando isso acontecer, caso contrário, poderá deixar em paz e ele será interrompido aqui e dará ao chamador a exceção do tempo de execução.

Nesse caso, precisamos saber que tipo de exceção aconteceu no ExternalService? Depende:

  1. se você pode lidar com alguns tipos de exceções, precisa capturá-las e processá-las. Para outros, borbulhe-os.

  2. se você precisar de log ou resposta para executar a execução específica, poderá capturá-los. Para outros, borbulhe-os.

Jacky
fonte
0

Eu acho que, ao declarar uma exceção de aplicativo, deve ser uma exceção não verificada, ou seja, subclasse de RuntimeException. O motivo é que ele não irá desorganizar o código do aplicativo com try-catch e lança a declaração no método. Se seu aplicativo estiver usando o Java Api, que lança exceções verificadas que de qualquer maneira precisam ser manipuladas. Para outros casos, o aplicativo pode lançar uma exceção desmarcada. Se o chamador do aplicativo ainda precisar lidar com a exceção não verificada, isso poderá ser feito.

Akash Aggarwal
fonte
-12

A regra que eu uso é: nunca use exceções não verificadas! (ou quando você não vê nenhuma maneira de contornar isso)

Do ponto de vista do desenvolvedor que usa sua biblioteca ou do usuário final que usa sua biblioteca / aplicativo, é realmente péssimo ser confrontado com um aplicativo que trava devido a uma exceção não solicitada. E contar com um catch-all também não é bom.

Dessa forma, o usuário final ainda pode receber uma mensagem de erro, em vez de o aplicativo desaparecer completamente.


fonte
1
Você não explica o que acha errado com um exemplo geral para a maioria das exceções não verificadas.
Matthew Flaschen
Completamente em desacordo com a sua resposta un-argumentado: "nunca use exceções não verificadas"
user1697575