try / catch versus throws Excepción

117

¿Son equivalentes estas declaraciones de código? ¿Hay alguna diferencia entre ellos?

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

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}
carlos
fuente
3
No es realmente una respuesta, pero puede que le interese el artículo de Ned Batchelder Excepciones en la selva tropical , que ayuda a explicar los casos generales en los que se prefiere un estilo u otro.
Daniel Pryden
1
en lugar de tener "showException (e)" en la captura, ¿estaba preguntando si tenía "throws e" en la captura (o no tenía el try / catch en absoluto)?
MacGyver

Respuestas:

146

Sí, hay una gran diferencia: el último se traga la excepción (mostrándola, es cierto), mientras que el primero permitirá que se propague. (Supongo que eso showExceptionno lo vuelve a tirar).

Entonces, 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 en absoluto ... lo cual generalmente es algo malo, a menos que showExceptionhaya manejado realmente la excepción, solucionado lo que estaba mal y, en general, se haya asegurado que calculateAreaha logrado su propósito.

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

Jon Skeet
fuente
12
Cuando mencionas que "A menos que realmente manejara la excepción", ese es un gran punto. Solo pensé en agregar que la captura de "Excepción" en sí misma rara vez conduce a un "manejo" inteligente de la excepción real, que es la razón por la que la gente recomienda que detecte la excepción más específica posible.
Bill K
17
+1. Porque Jon Skeet necesita más reputación. Ah, y la respuesta también fue buena.
Jonathan Spiller
20

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

samitgaur
fuente
Entonces, en pocas palabras, siempre debería 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 habiendo hecho eso, ahora me doy cuenta de que T estaba cometiendo un gran error ..
carlos
9
No, se necesitan ambos patrones. Si su método puede manejar la excepción, use el segundo patrón, si no, use el primero para notificar a la persona que llama.
Andreas Dolk
La versión que utilice depende de sus requisitos; básicamente, a qué nivel necesita manejar esa excepción. La persona que llama debe estar codificada en consecuencia. Si una persona que llama estaba llamando a la primera versión y usted reemplaza la definición del método con la segunda versión, su código de llamada se verá obligado a manejar la excepción, ya que esta es una excepción marcada.
samitgaur
16

Si. La versión que declara throws Exceptionrequerirá el código de llamada para manejar la excepción, mientras que la versión que la maneja explícitamente no lo hará.

es decir, simplemente:

performCalculation();

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

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

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

En términos generales, también, no desea detectar una excepción genérica. En su lugar, querrá captar solo algunos específicos, como FileNotFoundExceptiono IOExceptionporque pueden significar cosas diferentes.

Chris Thompson
fuente
3

Hay un escenario particular en el que no podemos usar lanzamientos, tenemos que usar try-catch. Hay una regla "Un método anulado no puede lanzar ninguna excepción adicional que no sea 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 clase base simple

package trycatchvsthrows;

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

y su clase 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
    }
}

Cuando tenemos que llamar a thread.sleep () nos vemos obligados a usar try-catch, aquí no podemos usar:

 public void show() throws InterruptedException

porque el método anulado no puede generar excepciones adicionales.

Arjun Thakur
fuente
Creo que no todo el mundo es consciente de esta salvedad. Bien puntiagudo.
ivanleoncz
1

Supongo que por "idéntico" te refieres al comportamiento.

El comportamiento de una función se puede determinar mediante:

1) Valor devuelto

2) Excepciones lanzadas

3) Efectos secundarios (es decir, cambios en el montón, sistema de archivos, etc.)

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

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

--editar--

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

Eyal Schneider
fuente
1

Si lanzó una excepción, el método secundario (que anula esto) debería 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
}
Sherif Eldeeb
fuente
0

Muchas veces desea que la persona que llama maneje la excepción. Digamos que la persona que llama llama a 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, usted puede manejarla en la persona que llama. A menos que desee hacer algo en uno de los métodos cuando ese método falle.

isaace
fuente
0

La persona que llama a este método deberá detectar esta excepción o declarar que se vuelva a lanzar en la firma del método.

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

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

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

    } catch (Exception e) {
        showException(e);
    }
}
JSON C11
fuente
0
private void calculateArea() throws Exception {
    ....do something
}

Esto arroja la excepción, por lo que la persona que llama es responsable de manejar esa excepción, pero si la persona que llama no maneja la excepción, es posible que se le dé a jvm, lo que puede resultar en la terminación anormal del programa.

Mientras que en el segundo caso:

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

En este caso, la excepción la maneja el destinatario, por lo que no hay posibilidad de una finalización anormal del programa.

Try-catch es el enfoque recomendado.

OMI,

  • Lanza la palabra clave que se usa principalmente con las excepciones marcadas para convencer al compilador, pero no garantiza la terminación normal del programa.

  • Lanza la palabra clave delega la responsabilidad del manejo de excepciones al
    llamador (JVM u otro método).

  • La palabra clave Throws es necesaria solo para las excepciones marcadas, para las excepciones no marcadas no se utiliza la palabra clave throws.

Nitin Pawar
fuente