2010-02-13 57 views
13

Soy un novato de Java, mi pregunta es acerca de los bloques try-catch en una división simple por ejemplo cero. ¿Ves la primera línea de try? Si lanzo cualquiera de esas dos variables al doble, el programa no reconoce el bloque catch. En mi opinión, si lanzo o no solo el bloque catch debe ser ejecutado. ¿Qué hay de malo en este código? Gracias.try-catch para la división por cero

public static void main(String[] args) { 

    int pay=8,payda=0; 

    try { 

     double result=pay/(double)payda; // if I cast any of the two variables, program does not recognize the catch block, why is it so? 
     System.out.println(result); 
     System.out.println("inside-try"); 


    } catch (Exception e) { 

     System.out.println("division by zero exception"); 
     System.out.println("inside-catch"); 

    } 
} 

Respuesta

22

La división por cero es válida para números en coma flotante.

  • 1/0 yields Infinity.
  • (-1)/0 cede -Infinito.
  • 0/0 produce NaN.

Estos "números" están correctamente definidos en el estándar IEEE 754.

La división entera por cero, por el contrario, tiros porque uno no puede representar el infinito como un int.

+0

Si la división de coma flotante no puede lanzar una excepción, entonces la prueba/captura debe ser eliminada y se deben usar códigos de error en su lugar. –

+1

No creo que 'int' arroje porque no puede representar infinito. 1/0 simplemente no tiene sentido, y es por eso que arroja. El punto flotante, por otro lado, hizo un gesto con la mano y dijo "debería ser infinito". – GManNickG

3

La respuesta se encuentra en la salida de su programa - imprime "Infinity" para result. Esto se debe a que Java solo impide la división entera por cero: la división de punto flotante por cero es legal y produce Infinity.

Consulte la documentación de Double y Float para las constantes POSITIVE_INFINITY y NEGATIVE_INFINITY.

14

me gustaría sugerir la verificación:

if (divisor != 0) { 
    // calculate 
} 

en lugar de detectar una excepción

+0

A menos que el divisor sea entero, los divisores distintos de cero pueden producir fácilmente resultados inutilizables, como un divisor de gran denom y pequeño: "Div doble = Double.MAX_VALUE/0.5;" cede infinito Recomiendo verificar Double.isInfinite y Double.isNaN (o los equivalentes de Float) en cualquier cálculo arriesgado sobre la comprobación del divisor! = 0. –

+0

Supongamos que son enteros, como en el ejemplo anterior – Bozho

1

Debido a la división de dos dobles devuelve un infinito, pero no tira. Puede usar isInfinite() para verificar esto. Sin embargo, la solución apropiada (como ya se señaló) es verificar el denominador antes de la división.

+0

dividiendo solo devuelve un NaN si uno de los argumentos es NaN o ambos son infinitos o ambos son cero. Dividir un cero distinto de cero - la pregunta - da como resultado Infinito positivo o negativo. http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.17.2 –

2

Solo la división por cero con enteros generará una ArithmeticException. La división por cero con doble o flotante dará como resultado Infinity.

7

Dado que usted es un "novato" autoproclamado, creo que sería una buena idea señalar algunos problemas más amplios con su código. (Sé que no es el código de producción, pero sólo deja para asumir por el bien del argumento de que se trataba.)

  • Si se espera una excepción, por lo general es más sencillo, más claro y más eficiente si se detecta la condición eso dará lugar a la excepción. En este caso, si espera que divisor ocasionalmente sea cero, es mejor probarlo antes de hacer la división.

  • Por otro lado, si una excepción es totalmente inesperada (es decir, un "error"), la mejor estrategia es permitir que la excepción se propague al nivel más externo. En ese punto, la captura de su aplicación debe capturar todas las excepciones, registrar la pila de excepción y rescatar.

  • Aparte del punto anterior, es una mala idea para atrapar Exception, RuntimeException, Throwable o Error. Hacer esto atrapará una gran cantidad de excepciones que probablemente no pretenda atrapar.En este caso, ya que está esperando un ArithmeticException, debería atrapar justamente eso.

  • Rara vez es correcto usar float o double en aplicaciones financieras. Estos tipos no son exactos, pero las aplicaciones financieras generalmente requieren cantidades de dinero para ser manejadas exactamente.

  • De manera más general, los números en coma flotante son intrínsecamente difíciles de entender para los profanos (y los novatos). Muchas de las "verdades" que la gente espera tener en realidad no son válidas. Por ejemplo, un cálculo de coma flotante de 1.0/3.0 + 1.0/3.0 + 1.0/3.0 no da 1.0. De manera similar (como descubriste) la división por cero se comporta de manera diferente. Si desea utilizar el punto flotante de forma segura, debe comprender las trampas.

EDITAR elaborar el primer punto en respuesta a @ comentario de Jay.

Primero, utilicé deliberadamente la palabra "generalmente". Hay casos en que evitar arrojar la excepción esperada no logra nada.

Dicho esto, a menudo no desea que se produzca una excepción genérica "esperada" , incluso si su aplicación no puede resolver la situación de inmediato. Por ejemplo, si el código del OP forma parte de algo más grande, puede ser mejor tirar explícitamente IllegalArgumentException (si esto es una violación de un contrato API) o algún UserEnteredRubbishException verificado si sabemos que esto es resultado de una mala entrada del usuario (y hay alguna oportunidad para reportarlo/corregirlo).

El hecho de que estamos "esperando" una excepción significa por definición que sabemos más sobre él que (digamos) un genérico ArithmeticException diría. Si permitimos que una excepción genérica se propague, dificulta que muchos bloques de pila actúen de forma adecuada. En este caso, por ejemplo, el bloque catch remoto no pudo diagnosticar la causa de la división por cero con certeza. El ArithmeticExceptionpodría haber venido de una parte diferente de la aplicación, y podría no ser ¡incluso dividirse por cero! La forma de abordar es lanzar explícitamente una excepción más específica.

+0

Discutiré con tu primer punto. Si se espera un caso especial Y hay algo que puede hacer para manejarlo y continuar el procesamiento, entonces sí, debe verificarlo en lugar de lanzar una excepción.Pero si, no importa qué tan esperado sea un caso especial, todo lo que puedes hacer cuando sucede es gritar de pánico y liberar a los perros de la guerra, y luego lanzar una excepción. – Jay

+0

Pero mega dittos en el n. ° 3 y n. ° 4. Capturar una excepción genérica rara vez es productivo. No tienes idea de lo que estás atrapando. Por cierto, podría agregar: Corolario: no arrojes excepciones genéricas. Si su programa detecta una condición de error y desea lanzar una excepción, tómese los diez minutos para crear una nueva clase que amplíe la excepción. No solo arroje una nueva excepción ("Foo faltaba una barra") o lo que sea. – Jay

0

Nadie debe esperar que RuntimeException se arroje desde su código. Estos Exception s pueden (y deben) evitarse fácilmente.

Cuestiones relacionadas