Conversione con perdita in Java

1. Panoramica

In questo rapido tutorial, discuteremo il concetto di conversione con perdita in Java e il motivo alla base di esso.

Allo stesso tempo, esploreremo alcune pratiche tecniche di conversione per evitare questo errore.

2. Conversione lossy

La conversione lossy è semplicemente la perdita di informazioni durante la gestione dei dati.

In Java, corrisponde alla possibilità di perdere il valore o la precisione di una variabile durante la conversione di un tipo in un altro.

Quando proviamo ad assegnare una variabile di tipo grande a un tipo di dimensione inferiore , Java genererà un errore, tipi incompatibili: possibile conversione con perdita , durante la compilazione del codice.

Ad esempio, proviamo ad assegnare un long a un int :

long longNum = 10; int intNum = longNum;

Java emetterà un errore durante la compilazione di questo codice:

incompatible types: possible lossy conversion from long to int

Qui, Java troverà incompatibili long e int e genererà un errore di conversione con perdita. Perché possono esserci valori lunghi al di fuori dell'intervallo int da -2.147.483.648 a 2.147.483.647.

Allo stesso modo, proviamo ad assegnare un float a un long :

float floatNum = 10.12f; long longNum = floatNum;
incompatible types: possible lossy conversion from float to long

As float può avere valori decimali che non hanno un valore lungo corrispondente . Pertanto, riceveremo lo stesso errore.

Allo stesso modo, l'assegnazione di un numero doppio a un int causerà lo stesso errore:

double doubleNum = 1.2; int intNum = doubleNum;
incompatible types: possible lossy conversion from double to int

I valori double possono essere troppo grandi o troppo piccoli per un int ei valori decimali andranno persi nella conversione. Quindi, è una potenziale conversione con perdita.

Inoltre, possiamo incorrere in questo errore durante l'esecuzione di un semplice calcolo:

int fahrenheit = 100; int celcius = (fahrenheit - 32) * 5.0 / 9.0;

Quando un doppio si moltiplica con un int , otteniamo il risultato in un doppio . Di conseguenza, è anche una potenziale conversione con perdite.

Pertanto, i tipi incompatibili nella conversione con perdita possono avere dimensioni o tipi diversi (numeri interi o decimali).

3. Tipi di dati primitivi

In Java, sono disponibili molti tipi di dati primitivi con le classi wrapper corrispondenti.

Successivamente, compiliamo un pratico elenco di tutte le possibili conversioni con perdite in Java:

  • corto a byte o char
  • char di byte o corto
  • int a byte , short o char
  • da lungo a byte , corto , carattere o int
  • float a byte , short , char , int o long
  • double in byte , short , char , int , long o float

Nota che anche se short e char hanno la stessa dimensione. Tuttavia, la conversione da short a char è con perdite perché char è un tipo di dati senza segno .

4. Tecniche di conversione

4.1. Conversione tra tipi primitivi

Il modo più semplice per convertire le primitive per evitare la conversione con perdite è attraverso il downcasting; in altre parole, lanciare il tipo di dimensioni maggiori a un tipo di dimensioni inferiori. Quindi, è anche chiamato restringimento della conversione primitiva.

Ad esempio, convertiamo un numero lungo in uno corto utilizzando il downcasting :

long longNum = 24; short shortNum = (short) longNum; assertEquals(24, shortNum);

Allo stesso modo, convertiamo un double in un int :

double doubleNum = 15.6; int integerNum = (int) doubleNum; assertEquals(15, integerNum);

Tuttavia, è opportuno notare che la conversione di caratteri di grandi dimensioni con valori troppo grandi o troppo piccoli in caratteri di dimensioni inferiori tramite il downcast può generare valori imprevisti.

Convertiamo valori lunghi al di fuori dell'intervallo di brevi :

long largeLongNum = 32768; short minShortNum = (short) largeLongNum; assertEquals(-32768, minShortNum); long smallLongNum = -32769; short maxShortNum = (short) smallLongNum; assertEquals(32767, maxShortNum);

Se analizziamo attentamente la conversione, vedremo che questi non sono i valori attesi.

In altre parole, quando Java raggiunge il valore più alto di un tipo di piccole dimensioni durante la conversione da un tipo di grandi dimensioni, il numero successivo è il valore più basso del tipo di piccole dimensioni e viceversa.

Comprendiamolo attraverso esempi. Quando largeLongNum con il valore di 32768 viene convertito in short , il valore di shortNum1 è -32768 . Poiché il valore massimo di short è 32767, Java utilizza il valore minimo successivo di short.

Allo stesso modo, quando smallLongNum viene convertito in short . Il valore di shortNum2 è 32767 poiché Java utilizza il valore massimo successivo dello short .

Inoltre, vediamo cosa succede quando convertiamo i valori massimo e minimo di un long in un int :

long maxLong = Long.MAX_VALUE; int minInt = (int) maxLong; assertEquals(-1, minInt); long minLong = Long.MIN_VALUE; int maxInt = (int) minLong; assertEquals(0, maxInt);

4.2. Conversione tra oggetti wrapper e tipi primitivi

To directly convert a wrapper object to a primitive, we can use various methods in wrapper classes such as intValue(), shortValue() and longValue(). This is called unboxing.

For instance, let's convert a Float object to a long:

Float floatNum = 17.564f; long longNum = floatNum.longValue(); assertEquals(17, longNum);

Also, if we look at the implementation of longValue or similar methods, we'll find the use of narrowing primitive conversion:

public long longValue() { return (long) value; }

However, at times, narrowing primitive conversion should be avoided to save valuable information:

Double doubleNum = 15.9999; long longNum = doubleNum.longValue(); assertEquals(15, longNum); 

After conversion, the value of longNum will be 15. However, the doubleNum is 15.9999, which is very close to 16.

Instead, we can use Math.round() for conversion to the closest integer:

Double doubleNum = 15.9999; long longNum = Math.round(doubleNum); assertEquals(16, longNum);

4.3. Converting Between Wrapper Objects

For this, let's use the already discussed conversion techniques.

First, we'll convert wrapper object to a primitive value, downcast it and convert it to another wrapper object. In other words, we'll perform unboxing, downcasting, and boxing techniques.

For example, let's convert a Double object to an Integer object:

Double doubleNum = 10.3; double dbl = doubleNum.doubleValue(); // unboxing int intgr = (int) dbl; // downcasting Integer intNum = Integer.valueOf(intgr); assertEquals(Integer.valueOf(10), intNum); 

Lastly, we're using Integer.valueOf() to convert the primitive type int to an Integer object. This type of conversion is called boxing.

5. Conclusion

In this article, we've explored the concept of lossy conversion in Java with the help of a number of examples. In addition, we've compiled a handy list of all possible lossy conversions as well.

Along the way, we've identified narrowing primitive conversion as an easy technique to convert primitive numbers and avoid the lossy conversion error.

At the same time, we've also explored additional handy techniques for numeric conversions in Java.

The code implementations for this article can be found over on GitHub.