¿Cuándo usar throws en una declaración de método Java?

82

Así que pensé que tenía una buena comprensión básica del manejo de excepciones en Java, pero recientemente leí un código que me dio algo de confusión y dudas. Mi principal duda que quiero abordar aquí es cuándo una persona debe usar arroja una declaración de método Java como la siguiente:

    public void method() throws SomeException
    {
         // method body here
    }

Al leer algunas publicaciones similares, deduzco que throws se usa como una especie de declaración de que SomeException podría lanzarse durante la ejecución del método.

Mi confusión proviene de un código que se ve así:

     public void method() throws IOException
     {
          try
          {
               BufferedReader br = new BufferedReader(new FileReader("file.txt"));
          }
          catch(IOException e)
          {
               System.out.println(e.getMessage());
          }
     }

¿Hay alguna razón por la que le gustaría usar lanzamientos en este ejemplo? Parece que si solo está haciendo un manejo básico de excepciones de algo como una IOException, simplemente necesitaría el bloque try / catch y eso es todo.

jbranchaud
fuente

Respuestas:

79

Si está detectando un tipo de excepción, no necesita lanzarlo, a menos que lo vuelva a lanzar. En el ejemplo que publicas, el desarrollador debería haber hecho uno u otro, no ambos.

Normalmente, si no va a hacer nada con la excepción, no debería detectarlo.

Lo más peligroso que puede hacer es detectar una excepción y no hacer nada con ella.

Una buena discusión sobre cuándo es apropiado lanzar excepciones está aquí.

¿Cuándo lanzar una excepción?

hvgotcodes
fuente
2
¿Deberían declararse también las excepciones no comprobadas en la firma del método con un 'throws', o es una práctica usar solo 'throws' para las excepciones marcadas?
Cody
Esta respuesta no aborda directamente el aspecto central de la pregunta: el uso de la throwspalabra clave.
Brent Bradburn
@hvgotcodes ¿Qué sucede si detecto una excepción y no hago nada?
Manoj
@manoj te arriesgas a que las cosas se rompan y no puedas resolverlo porque se pierde información crucial. Hay ocasiones (no necesariamente Java) en las que está bien detectar una excepción y no hacer nada, pero deben documentarse. Por ejemplo, en javascript puede intentar invocar una funcionalidad que podría no existir dependiendo de un navegador. Eso no es necesariamente un error que necesite atención.
hvgotcodes
22

Solo necesita incluir una cláusula throws en un método si el método arroja una excepción marcada. Si el método genera una excepción de tiempo de ejecución, no es necesario hacerlo.

Consulte aquí algunos antecedentes sobre las excepciones marcadas frente a las no comprobadas: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Si el método detecta la excepción y la trata internamente (como en el segundo ejemplo), entonces no es necesario incluir una cláusula throws.

Shane Bell
fuente
9

El código que miraste no es el ideal. Deberías:

  1. Capture la excepción y manéjela; en cuyo caso throwses innecesario.

  2. Retire el try/catch; en cuyo caso la excepción será manejada por un método de llamada.

  3. Capture la excepción, posiblemente realice alguna acción y luego vuelva a lanzar la excepción (no solo el mensaje)

Damo
fuente
2

Tienes razón, en ese ejemplo throwses superfluo. Es posible que se haya dejado allí por alguna implementación anterior; quizás la excepción se lanzó originalmente en lugar de quedar atrapada en el bloque de captura.

RevBingo
fuente
2

El código que publicó es incorrecto, debería lanzar una excepción si detecta una excepción específica para manejar IOException pero arroja excepciones no detectadas.

Algo como:

public void method() throws Exception{
   try{
           BufferedReader br = new BufferedReader(new FileReader("file.txt"));
   }catch(IOException e){
           System.out.println(e.getMessage());
   }
}

o

public void method(){
   try{
           BufferedReader br = new BufferedReader(new FileReader("file.txt"));
   }catch(IOException e){
           System.out.println("Catching IOException");
           System.out.println(e.getMessage());
   }catch(Exception e){
           System.out.println("Catching any other Exceptions like NullPontException, FileNotFoundExceptioon, etc.");
           System.out.println(e.getMessage());
   }

}

Ignacio lucatero
fuente
1

En el ejemplo que dio, el método nunca arrojará una IOException, por lo tanto, la declaración es incorrecta (pero válida). Supongo que el método original arrojó la IOException, pero luego se actualizó para manejar la excepción dentro, pero la declaración no se modificó.

DaveJohnston
fuente
1

Esto no es una respuesta, sino un comentario, pero no pude escribir un comentario con un código formateado, así que aquí está el comentario.

Digamos que hay

public static void main(String[] args) {
  try {
    // do nothing or throw a RuntimeException
    throw new RuntimeException("test");
  } catch (Exception e) {
    System.out.println(e.getMessage());
    throw e;
  }
}

La salida es

test
Exception in thread "main" java.lang.RuntimeException: test
    at MyClass.main(MyClass.java:10)

Ese método no declara ninguna excepción "arroja", ¡pero las arroja! El truco es que las excepciones lanzadas son RuntimeExceptions (sin marcar) que no es necesario declarar en el método. Es un poco engañoso para el lector del método, ya que todo lo que ve es un "lanzamiento"; declaración pero no declaración de la excepción de lanzamiento

Ahora, si tenemos

public static void main(String[] args) throws Exception {
  try {
    throw new Exception("test");
  } catch (Exception e) {
    System.out.println(e.getMessage());
    throw e;
  }
}

DEBEMOS declarar las excepciones "throws" en el método, de lo contrario obtendremos un error del compilador.

Αλέκος
fuente
El compilador realiza un análisis estático sorprendentemente sofisticado para decidir si throwsse requiere o no .
Brent Bradburn