2010-07-13 19 views
94

¿Estas declaraciones de código son equivalentes? ¿Hay alguna diferencia entre ellos?try/catch versus throws Excepción

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

private void calculateArea() { 
     try { 
      ....do something 

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

realmente una respuesta, pero que podría estar interesado en el artículo [Excepciones de Ned Batchelder en la selva] (http://nedbatchelder.com/text/exceptions-in-the-rainforest.html), que ayuda a explicar los casos generales en los que se prefiere un estilo u otro. –

+1

en lugar de tener "showException (e)" en la captura, ¿preguntaba si tenía "throws e" en la captura en su lugar (o no tiene el try/catch en absoluto)? – MacGyver

Respuesta

116

Sí, hay una gran diferencia - este último se traga la excepción (mostrando que, sin duda), mientras que el primero será dejar que se propague. (Supongo que showException no lo vuelve a lanzar.)

Si llama al primer método y "hacer algo" falla, la persona que llama tendrá que manejar la excepción. Si llama al segundo método y "hacer algo" falla, entonces la persona que llama no verá una excepción ... lo cual es generalmente algo malo, a menos que showException haya genuinamente haya manejado la excepción, solucionado lo que estaba mal y en general, se aseguró de que calculateArea haya logrado su propósito.

Usted será capaz de decir esto, porque no se puede llamar el primer método, sin ya sea la captura de Exception mismo o declarar que su método podría tirar también.

+10

Cuando mencionas que "A menos que haya manejado genuinamente la excepción", ese es un buen punto. Solo pensé que agregaría que atrapar "Excepción" en sí raramente conduce a un "manejo" inteligente de la excepción real, que es la razón por la que la gente recomienda que detectes la excepción más específica posible. –

+16

+1.Porque Jon Skeet necesita más reputación. Ah, y la respuesta también fue buena. –

13

Sí. La versión que declara throws Exception requerirá que el código de llamada maneje la excepción, mientras que la versión que maneja explícitamente no lo hará.

es decir, simplemente:

performCalculation(); 

frente a mover la carga de manejar la excepción a la persona que llama:

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

Primero uno throws Exception, por lo que la persona que llama tiene que manejar el Exception. El segundo captura y maneja Exception internamente, por lo que la persona que llama no tiene que hacer ningún manejo de excepción.

+0

Entonces, en pocas palabras, siempre debo usar el segundo. ¿Estoy en lo cierto? El primero es en realidad un método que se utiliza en diferentes puntos del programa. Es por eso que decidí agrupar las instrucciones para un uso posterior, pero una vez hecho esto, me doy cuenta de que T estaba cometiendo un gran error. – carlos

+7

No, se necesitan ambos patrones. Si su método puede manejar la excepción, use el segundo patrón, de lo contrario, use el primero para notificar a la persona que llama. –

+0

La versión que usa depende de sus requisitos, básicamente a qué nivel necesita manejar esa excepción. La persona que llama debe codificarse en consecuencia. Si la persona que llamaba llamaba a la primera versión y reemplazaba la definición del método con la segunda versión, su código llamante se vería obligado a manejar la excepción ya que esta es una excepción marcada. – samitgaur

4

Sí, hay una gran diferencia entre ellos. En el primer bloque de código, pasa la excepción al código de llamada. En el segundo bloque de código lo manejas tú mismo. El método correcto depende completamente de lo que esté haciendo. En algunos casos, desea que su código maneje la excepción (si no se encuentra un archivo y desea crearlo, por ejemplo) pero en otros, desea que el código de llamada maneje la excepción (no se encuentra un archivo). y necesitan especificar uno nuevo o crearlo).

Hablando en general también, no desea detectar una excepción genérica. En su lugar, querrá capturar solo los específicos, como FileNotFoundException o IOException porque pueden significar cosas diferentes.

1

Supongo que por "idéntico" se refiere al comportamiento.

Un comportamiento de una función se puede determinar por:

1) Valor devuelto

2) excepciones lanzadas

3) efectos secundarios (i.e cambios en el montón, sistema de archivos, etc.)

En este caso, el primer método propaga cualquier excepción, mientras que el segundo arroja ninguna excepción marcada, y se traga también la mayoría de las excepciones no verificadas, por lo que el comportamiento ES diferente.

Sin embargo, si usted garantiza que "hacer algo" nunca se produce una excepción, entonces el comportamiento sería idéntico (aunque el compilador requerirá la persona que llama para manejar la excepción, en la primera versión)

--edit -

Desde el punto de vista del diseño de la API, los métodos son completamente diferentes en su contrato. Además, throwing class Exception no es recomendable. Intente arrojar algo más específico para permitir que la persona que llama maneje mejor la excepción.

3

Hay un caso particular en el que no podemos usar throws, tenemos que usar try-catch. Existe una regla "Un método anulado no puede arrojar ninguna excepción adicional a la que está lanzando su clase principal". Si hay alguna excepción adicional que deba manejarse con try-catch. Considere este fragmento de código. Hay una sencilla clase base

package trycatchvsthrows; 

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

y se deriva de clase:

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

Cuando tenemos que llamar Thread.Sleep() nos vemos obligados a utilizar try-catch, aquí no podemos utilizar :

public void show() throws InterruptedException 

porque el método reemplazado no puede arrojar excepciones adicionales.

+0

Creo que no todos conocen esta advertencia. Bien apuntado. – ivanleoncz

0

El llamante de este método deberá detectar esta excepción o declarar que se vuelve a lanzar en su firma de método.

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

En el ejemplo del bloque try-catch a continuación. La persona que llama de este método no tiene que preocuparse por manejar la excepción, ya que ya se ha solucionado.

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

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

Muchas veces desea que la persona que llama maneje la excepción. Supongamos que hace que la persona que llama invoque un método que llama a otro método que llama a otro método, en lugar de que cada método maneje la excepción, puede manejarlo en la persona que llama. A menos que desee hacer algo en uno de los métodos cuando ese método falla.

1

Si inició una excepción, el método niño (que anula este) debe manejar la excepción

ejemplo:

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

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