¿Qué significa “posible conversión con pérdida” y cómo lo soluciono?

Los nuevos progtwigdores de Java a menudo se confunden con mensajes de error de comstackción como:

“tipos incompatibles: posible conversión con pérdida de doble a int”

para esta línea de código:

int squareRoot = Math.sqrt(i); 

¿Qué significa este error y cómo lo solucionas?

En primer lugar, este es un error de comstackción. Si alguna vez lo ve en un mensaje de excepción en el tiempo de ejecución, es porque ha ejecutado un progtwig con errores de comstackción 1 .

La forma general del mensaje es esta:

“tipos incompatibles: posible conversión con pérdida de a

donde y son ambos tipos numéricos primitivos; es decir, de byte , char , short , int , long , float o double .

Este error ocurre cuando su código intenta hacer una conversión implícita de a pero la conversión puede ser con pérdida .

En el ejemplo en la pregunta:

  int squareRoot = Math.sqrt(i); 

el método sqrt produce un double , pero una conversión de double a int es potencialmente con pérdida.

¿Qué significa “potencialmente con pérdidas”?

Bueno, veamos un par de ejemplos.

  1. Una conversión de long a int es una conversión potencialmente con pérdidas porque hay valores long que no tienen un valor int correspondiente. Por ejemplo, cualquier valor long que sea mayor que 2 ^ 31 – 1 es demasiado grande para representarse como un int . Del mismo modo, cualquier número menor que -2 ^ 31 es demasiado pequeño.

  2. Una conversión de int a long no es conversión con pérdida porque cada valor int tiene un valor long correspondiente.

  3. Una conversión de un float a long es una conversión potencialmente con pérdidas porque float valores que son demasiado grandes o demasiado pequeños para representarlos como valores long .

  4. Una conversión de un long a un float NO es una conversión con pérdida porque cada valor long tiene un valor float correspondiente. (El valor convertido puede ser menos preciso, pero “pérdida” no significa que … en este contexto).

Estas son todas las conversiones que son potencialmente con pérdidas:

  • short a byte o char
  • char a byte o short
  • int to byte , short o char
  • long to byte , short , char o int
  • float a byte , short , char , int o long
  • double a byte , short , char , int , long o float .

¿Cómo arreglas el error?

La forma de hacer desaparecer el error de comstackción es agregar un tipocast. Por ejemplo;

  int i = 47; int squareRoot = Math.sqrt(i); // comstacktion error! 

se convierte

  int i = 47; int squareRoot = (int) Math.sqrt(i); // no comstacktion error 

¿Pero es realmente una solución? Considere que la raíz cuadrada de 47 es 6.8556546004 … pero squareRoot obtendrá el valor 6 . (La conversión se truncará, no será redonda).

¿Y qué hay de esto?

  byte b = (int) 512; 

Eso resulta en b obtener el valor 0 . La conversión de un tipo int más grande a un tipo int más pequeño se realiza enmascarando los bits de orden superior, y los 8 bits de bajo orden de 512 son todos cero.

En resumen, no debería simplemente agregar un tipo de transmisión, ya que podría no hacer lo correcto para su aplicación .

En su lugar, debe comprender por qué su código necesita hacer una conversión:

  • ¿Esto sucede porque has cometido algún otro error en tu código?
  • ¿Debería el ser un tipo diferente, de modo que no se necesita una conversión con pérdida aquí?
  • Si es necesaria una conversión, ¿la conversión con pérdida silenciosa es que el encasillado realizará el comportamiento correcto?
  • ¿O debería su código hacer algunas comprobaciones de rango y tratar con valores incorrectos / inesperados arrojando una excepción?

Algunos casos específicos:

“Conversión con pérdida posible” al suscribirse.

Primer ejemplo:

 for (double d = 0; d < 10.0; d += 1.0) { System.out.println(array[d]); // <<-- possible lossy conversion } 

El problema aquí es que el valor del índice de matriz debe ser int . Entonces d tiene que convertirse de double a int . En general, usar un valor de coma flotante como índice no tiene sentido. O alguien tiene la impresión de que las matrices de Java funcionan como (digamos) los diccionarios de Python, o han pasado por alto el hecho de que la aritmética de punto flotante a menudo es inexacta.

La solución es reescribir el código para evitar el uso de un valor de coma flotante como un índice de matriz. (Agregar un molde de tipo probablemente sea una solución incorrecta).

Segundo ejemplo:

 for (long l = 0; l < 10; l++) { System.out.println(array[l]); // <<-- possible lossy conversion } 

Esta es una variación del problema anterior, y la solución es la misma. La diferencia es que la causa raíz es que las matrices de Java están limitadas a índices de 32 bits. Si desea una estructura de datos "tipo array" que tenga más de 2 31 - 1 elementos, necesita definir o encontrar una clase para hacerlo.


1 - Por ejemplo, el Eclipse IDE tiene una opción que le permite ignorar los errores de comstackción y ejecutar el código de todos modos. Si selecciona esto, el comstackdor del IDE creará un archivo .class donde el método con el error arrojará una excepción no verificada si se llama. El mensaje de excepción mencionará el mensaje de error de comstackción.