try / catch versus throws Exception


117

Essas declarações de código são equivalentes? Existe alguma diferença entre eles?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

3
Não é realmente uma resposta, mas você pode estar interessado no artigo de Ned Batchelder, Exceptions in the Rainforest , que ajuda a explicar os casos gerais em que um estilo ou outro deve ser preferido.
Daniel Pryden

1
em vez de ter "showException (e)" na captura, você estava perguntando se tinha "joga e" na captura (ou não tinha o try / catch de jeito nenhum)?
MacGyver

Respostas:


146

Sim, há uma grande diferença - o último engole a exceção (mostrando, é certo), enquanto o primeiro vai deixá-la se propagar. (Presumo que showExceptionisso não o relembre.)

Portanto, se você chamar o primeiro método e "fazer algo" falhar, o chamador terá que lidar com a exceção. Se você chamar o segundo método e "fazer algo" falhar, o chamador não verá nenhuma exceção ... o que geralmente é uma coisa ruim, a menos que showExceptiontenha genuinamente tratado a exceção, corrigido o que quer que esteja errado e, geralmente, tenha certeza que calculateAreaalcançou seu propósito.

Você vai ser capaz de dizer isso, porque você não pode chamar o primeiro método, sem qualquer captura Exception-se ou declarar que seu método pode jogá-lo também.


12
Quando você menciona que "A menos que tenha genuinamente tratado a exceção", esse é um ponto importante. Eu apenas pensei em acrescentar que capturar a "Exceção" em si raramente leva ao "tratamento" inteligente da exceção real, que é o motivo pelo qual as pessoas recomendam que você capture a exceção mais específica possível.
Bill K

17
+1. Porque Jon Skeet precisa de mais reputação. Ah, e a resposta também foi boa.
Jonathan Spiller

20

Primeiro throws Exception, então o chamador precisa lidar com o Exception. O segundo captura e trata Exceptioninternamente, para que o chamador não precise fazer nenhum tratamento de exceção.


Portanto, em poucas palavras, devo sempre usar o segundo. Estou certo? O primeiro é na verdade um método que é usado em diferentes pontos do programa. É por isso que decidi agrupar as instruções para uso posterior, mas tendo feito isso, agora percebo que T estava cometendo um grande erro ..
carlos

9
Não, ambos os padrões são necessários. Se o seu método pode manipular a exceção, use o segundo padrão; do contrário, use o primeiro para notificar o chamador.
Andreas Dolk

A versão que você usa depende dos seus requisitos - basicamente, em que nível você precisa para lidar com essa exceção. O chamador precisa ser codificado de acordo. Se um chamador estava chamando a primeira versão e você substitui a definição do método pela segunda versão, o código do chamador será forçado a tratar a exceção, pois esta é uma exceção verificada.
samitgaur

16

Sim. A versão que declara throws Exceptionexigirá o código de chamada para tratar a exceção, enquanto a versão que explicitamente trata isso não.

ou seja, simplesmente:

performCalculation();

vs. transferir o fardo de lidar com a exceção para o chamador:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}

6

Sim, existe uma grande diferença entre eles. No primeiro bloco de código, você passa a exceção para o código de chamada. No segundo bloco de código, você mesmo lida com isso. O método correto depende inteiramente do que você está fazendo. Em alguns casos, você deseja que seu código trate a exceção (se um arquivo não for encontrado e você deseja criá-lo, por exemplo), mas em outros, você deseja que o código de chamada trate a exceção (um arquivo não foi encontrado e eles precisam especificar um novo ou criá-lo).

De modo geral, você não deseja capturar uma exceção genérica. Em vez disso, você desejará capturar apenas alguns específicos, como FileNotFoundExceptionou IOExceptionporque podem significar coisas diferentes.


3

Existe um cenário particular onde não podemos usar arremessos, temos que usar try-catch. Existe uma regra "Um método sobrescrito não pode lançar nenhuma exceção extra que não seja aquela que sua classe pai está lançando". Se houver alguma exceção extra que deve ser tratada usando try-catch. Considere este trecho de código. Existe uma classe base simples

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

e sua classe derivada:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

Quando temos que chamar thread.sleep (), somos forçados a usar try-catch, aqui não podemos usar:

 public void show() throws InterruptedException

porque o método sobrescrito não pode lançar exceções extras.


Acredito que nem todos estão cientes dessa advertência. Bem apontado.
ivanleoncz

1

Suponho que por "idêntico" você está se referindo ao comportamento.

O comportamento de uma função pode ser determinado por:

1) Valor devolvido

2) Exceções lançadas

3) Efeitos colaterais (ou seja, mudanças no heap, sistema de arquivos, etc.)

Nesse caso, o primeiro método propaga qualquer exceção, enquanto o segundo não lança nenhuma exceção verificada e também engole a maioria das exceções não verificadas, de modo que o comportamento É diferente.

No entanto, se você garantir que "fazer algo" nunca lança uma exceção, o comportamento seria idêntico (embora o compilador exija que o chamador trate a exceção, na primeira versão)

--editar--

Do ponto de vista do design da API, os métodos são completamente diferentes em seu contrato. Além disso, lançar a classe Exception não é recomendado. Tente lançar algo mais específico para permitir que o chamador trate melhor a exceção.


1

Se você lançou uma exceção, o método filho (que substitui isso) deve lidar com a exceção

exemplo:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}

0

Muitas vezes, você deseja que o chamador trate a exceção. Digamos que você faça o chamador chamar um método que chama outro método que chama outro método, em vez de cada método tratar a exceção, você pode tratá-lo apenas no chamador. A menos que você queira fazer algo em um dos métodos quando esse método falhar.


0

O chamador desse método precisará capturar essa exceção ou declará-la para ser relançada em sua assinatura de método.

private void calculateArea() throws Exception {
    // Do something
}

No exemplo de bloco try-catch abaixo. O chamador deste método não precisa se preocupar em lidar com a exceção, pois ela já foi tratada.

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}

0
private void calculateArea() throws Exception {
    ....do something
}

Isso lança a exceção, de modo que o chamador é responsável por lidar com essa exceção, mas se o chamador não lidar com a exceção, então pode ser que ele será fornecido para jvm, o que pode resultar no encerramento anormal do programa.

Considerando que no segundo caso:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

Aqui, a exceção é tratada pelo receptor, portanto, não há chance de encerramento anormal do programa.

Try-catch é a abordagem recomendada.

IMO,

  • Lança a palavra-chave usada principalmente com exceções verificadas para convencer o compilador, mas não garante o encerramento normal do programa.

  • Lança o delegado de palavra-chave a responsabilidade de tratamento de exceção para o responsável
    pela chamada (JVM ou outro método).

  • A palavra-chave throws é necessária apenas para exceções verificadas; para exceções não verificadas, não há uso da palavra-chave throws.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.