Lanzar y atrapar excepciones en la misma función / método

10

He escrito una función que le pide al usuario que ingrese hasta que el usuario ingrese un número entero positivo (un número natural). Alguien dijo que no debería lanzar y capturar excepciones en mi función y debería dejar que la persona que llama de mi función las maneje.

Me pregunto qué piensan otros desarrolladores sobre esto. Probablemente también estoy haciendo mal uso de excepciones en la función. Aquí está el código en Java:

private static int sideInput()
{
    int side = 0;
    String input;
    Scanner scanner = new Scanner(System.in);

    do {
        System.out.print("Side length: ");
        input = scanner.nextLine();
        try {
            side = Integer.parseInt(input);
            if (side <= 0) {
                // probably a misuse of exceptions
                throw new NumberFormatException();
            }
        }
        catch (NumberFormatException numFormExc) {
            System.out.println("Invalid input. Enter a natural number.");
        }
    } while (side <= 0);

    return side;
}

Me interesan dos cosas:

  1. ¿Debo dejar que la persona que llama se preocupe por las excepciones? El punto de la función es que molesta al usuario hasta que el usuario ingrese un número natural. ¿Es malo el punto de la función? No estoy hablando de la interfaz de usuario (el usuario no puede salir del bucle sin la entrada adecuada), sino de la entrada en bucle con excepciones manejadas.
  2. ¿Diría que la declaración de lanzamiento (en este caso) es un mal uso de excepciones? Podría crear fácilmente una bandera para verificar la validez del número y enviar el mensaje de advertencia basado en esa bandera. Pero eso agregaría más líneas al código y creo que es perfectamente legible como es.

La cuestión es que a menudo escribo una función de entrada separada. Si el usuario tiene que ingresar un número varias veces, creo una función separada para la entrada que maneja todas las excepciones y limitaciones de formato.

usr
fuente
Depende mucho del idioma. Algunos idiomas usan excepciones más libremente que otros.
Martin York

Respuestas:

11

El punto de una excepción es que permite que un método le diga a la persona que llama que ingresó un estado en el que no puede continuar normalmente, sin obligarlo a incrustar un código de error en el valor de retorno.

En su caso, su método sabe exactamente qué hacer cuando la entrada no es mayor que 0. La única razón por la que está guardando líneas aquí es porque está lanzando la misma excepción que obtendría si la entrada no fuera un número. Sin embargo, la excepción que está lanzando no representa adecuadamente por qué su código no le gusta la entrada. Si alguien más apareciera y viera este código, tendrían que pasar más tiempo tratando de ver exactamente cómo funcionan las cosas.

muestreador
fuente
Sí, por eso pensé que era un mal uso. Entonces, ignorando esa declaración de lanzamiento, ¿está de acuerdo en que está bien manejar excepciones en dicho ciclo dentro de una función en lugar de permitir que la persona que llama las atrape? La declaración catch está ahí debido a Integer.parseInt (nuevamente, ignorando el lanzamiento).
usr
1
@ usr: Esa respuesta depende mucho más de cómo el resto del sistema debe funcionar en conjunto. Las excepciones deben manejarse en algún momento. Hay algunas formas diferentes de organizarlo y esta es una de ellas. Lo que es mejor depende de otra información que no tenemos aquí.
Unholysampler
4

Este es un mal uso de excepciones. Para empezar, un número no positivo no es una excepción de formato.

¿Por qué usar excepciones en absoluto? Si sabe qué entrada no está permitida, simplemente no salga del ciclo hasta que obtenga una entrada válida del usuario, algo como lo siguiente:

while (true)
{
   // Get user input.
   String input = scanner.nextLine();

   try
   {
      side = Integer.parseInt(input);

      break;
   }
   catch (NumberFormatException ex)
   {
      // Inform user of invalid input.
      System.out.println("Invalid input. Enter a natural number.");
   }
}
Bernardo
fuente
Integer.intParse arroja un formato de excepciones, por lo que usar la instrucción catch es perfectamente válido. Principalmente quiero saber si está bien usar la instrucción catch en un bucle en una función o si debo dejar que el llamador de la función maneje la excepción de formato.
Usr
Integer.parseInt()arroja un NumberFormatExceptionsi no puede analizar el argumento de cadena proporcionado. No es necesario que usted (y no podrá) lanzar la excepción usted mismo.
Bernard
He editado el código de ejemplo para que sea más explícito.
Bernard
"y no podrás) lanzar la excepción tú mismo", ¿qué quieres decir allí?
Michael Borgwardt
@Michael Borgwardt: quiero decir que dado que el Integer.parseInt()método arrojará la excepción para ti si ocurre, no podrás lanzarlo tú mismo después ya que ya se ha lanzado.
Bernard
1

Solo capture excepciones si tiene la intención de hacer algo que sea relevante para la llamada al método actual; es decir, limpieza, lógica de falla, etc. En este caso, la captura simplemente está enviando un mensaje a la consola, no es relevante para el método sideInput, por lo que puede manejarse más arriba en la cadena / pila de llamadas.

Uno puede deshacerse del try / catch aquí y simplemente documentar la llamada al método:

//Throws NumberFormatException if read input is less than 0
private static int sideInput()

¡Todavía hay que manejar esa excepción más arriba en la cadena / pila de llamadas!

Jon Raynor
fuente
1
El mensaje está ahí solo para una mejor interfaz de usuario. El punto de la función es que molesta al usuario para que ingrese hasta que ingrese una entrada válida. Esto no se puede hacer sin bloques try-catch. Mi pregunta era si el punto en sí es válido. Creo que sí, pero alguien me dijo que debería eliminar los bloques try-catch y dejar que la persona que llama maneje esta excepción en particular. Pero entonces la función no funcionará según lo previsto.
Usr
1

No debe lanzar y atrapar la misma excepción en un método, incluso creo que el bloque de captura capturará la misma excepción que está lanzando, por lo que realmente no lo está lanzando.

Si parseInttuvo éxito, entonces no es un NumberFormatException.

si el lado es menor que cero, debe lanzar un NegativeSideLengthException;

Cree una excepción personalizada / comercial denominada NegativeSideLengthException

public class NegativeSideLengthException extends Exception
{


    public NegativeSideLengthException(Integer i)
    {
        super("Invalid negative side length "+i);        
    }

}

Luego sideInputlanza NegativeSideLengthException

private static int sideInput() throws NegativeSideLengthException
{
    int side = 0;
    String input;
    Scanner scanner = new Scanner(System.in);

    do {
        System.out.print("Side length: ");
        input = scanner.nextLine();
        try {
            side = Integer.parseInt(input);
            if (side <= 0) {
                throw new NegativeSideLengthException(side);
            }
        }
        catch (NumberFormatException numFormExc) {
            System.out.println("Invalid input. Enter a natural number.");
        }
    } while (side <= 0);

    return side;
}

Incluso puede (si lo desea) agregar otro bloque catch para atrapar NegativeSideLengthExceptiony no hacer que el método lo lance.

do {
    System.out.print("Side length: ");
    input = scanner.nextLine();
    try {
        side = Integer.parseInt(input);
        if (side <= 0) {
            throw new NegativeSideLengthException(side);
        }
    }
    catch (NumberFormatException numFormExc) {
        System.out.println("Invalid input. Enter a natural number.");
    } catch (NegativeSideLengthException e){
        System.out.println("Invalid input. Enter a non-negative number.");
    }
} while (side <= 0);

Las banderas no son una buena forma de manejar las excepciones.

Tulains Córdova
fuente
-1

Las excepciones son cosas bastante pesadillas, traen más complejidades de las que resuelven.

En primer lugar, si no detecta sus excepciones, la persona que llama solo puede hacer on error resume next, es decir, después de una semana, incluso usted no sabrá qué puede arrojar su función y qué hacer con ella:

{
    ...
}
catch(OutOfMemory, CorruptedMemory, BadData, DanglingPointers, UnfinishedCommit)
{
    Console.WriteLine("Nothing to see here, move on.");
    Console.WriteLine("The app is very stable, see, no crashing!");
}

Básicamente, si los atrapa, debe comprender muy bien los contratos y las garantías de excepción. Eso rara vez sucede en un mundo real. Y también su código será difícil de leer.

Además, lo curioso es que si realmente tiene alguna posibilidad de manejar excepciones, necesita un lenguaje RAII real, que es algo gracioso, ya que Java y .NET se trata de excepciones ...

Repitiendo esto una vez más, pero ...:

http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx

http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx

http://www.joelonsoftware.com/items/2003/10/13.html

Descifrador
fuente
44
-1 para publicar una diatriba limítrofe, llena de declaraciones no del todo correctas, o al menos dependientes del contexto / lenguaje, en lugar de responder la pregunta real del OP.
Péter Török
@ PéterTörök: "Dale un pescado a un hombre y lo alimentarás por un día. Enseña a un hombre a pescar y lo alimentarás toda la vida". Hay problemas muy serios detrás de las excepciones, y la gente debería conocerlos -1000 / + 1, realmente no me importa.
Codificador
1
Siéntase libre de creer que puede escribir el código correcto más fácilmente sin excepciones. Simplemente no declare sus puntos de vista y creencias como hechos (incluso si Joel es de la misma opinión, sigue siendo una opinión, no un hecho), y no publique respuestas irrelevantes en SE.
Péter Török
@ PéterTörök: No es una opinión, es un hecho, cada vez que utiliza un componente que genera una excepción internamente, tiene que rastrear toda la jerarquía y verificar cada línea de código para saber qué atrapar, y si los componentes ofrecen un fuerte garantía, y todo se revierte, o si esa captura es solo una falsa sensación de seguridad. Diablos, ni siquiera sabes todas las excepciones std :: string throws, puedes buscar las especificaciones, pero nunca las encontrarás. Cosas como : throw(thisexception, thatexception)están francamente mal y nunca deben usarse, porque de lo contrario obtendrás una excepción inesperada.
Codificador
2
Bien, ¿qué tal si el código no usa excepciones? Gee, debe rastrear el código para verificar cada línea para ver si los valores de retorno se manejan correctamente o se ignoran. Y cuando se ignora un valor de retorno, nadie se da cuenta hasta que tal vez su aplicación se bloquee un par de miles de líneas más tarde. Las excepciones al menos lo obligan a tomar nota. Sí, puede tragárselos, pero solo con un explícito catch. Si bien un valor de retorno ignorado no se puede buscar, solo se puede identificar a través de la revisión de código línea por línea. Por último, pero no menos importante, los constructores no tienen valores de retorno, esta es la razón principal para usar excepciones.
Péter Török