Conversion avec perte en Java

1. Vue d'ensemble

Dans ce rapide didacticiel, nous discuterons du concept de conversion avec perte en Java et de la raison qui la sous-tend.

Dans le même temps, nous explorerons quelques techniques de conversion pratiques pour éviter cette erreur.

2. Conversion avec perte

La conversion avec perte est simplement la perte d'informations lors du traitement des données.

En Java, cela correspond à la possibilité de perdre la valeur ou la précision d'une variable lors de la conversion d' un type en un autre.

Lorsque nous essayons d'assigner une variable de type de grande taille à un type de plus petite taille , Java générera une erreur, types incompatibles: conversion avec perte possible , lors de la compilation du code.

Par exemple, essayons d'assigner un long à un int :

long longNum = 10; int intNum = longNum;

Java émettra une erreur lors de la compilation de ce code:

incompatible types: possible lossy conversion from long to int

Ici, Java trouvera long et int incompatibles et entraînera une erreur de conversion avec perte. Parce qu'il peut y avoir des valeurs longues en dehors de la plage int de -2 147 483 648 à 2 147 483 647.

De même, essayons d'assigner un flottant à un long :

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

As float peut avoir des valeurs décimales qui n'ont pas de valeur longue correspondante . Par conséquent, nous recevrons la même erreur.

De même, attribuer un double nombre à un int provoquera la même erreur:

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

Les valeurs doubles peuvent être trop grandes ou trop petites pour un entier et les valeurs décimales seront perdues dans la conversion. Par conséquent, il s'agit d'une conversion potentielle avec perte.

De plus, nous pouvons rencontrer cette erreur en effectuant un calcul simple:

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

Lorsqu'un double se multiplie avec un int , on obtient le résultat dans un double . Par conséquent, il s'agit également d'une conversion potentielle avec perte.

Par conséquent, les types incompatibles dans la conversion avec perte peuvent avoir des tailles ou des types différents (entiers ou décimales).

3. Types de données primitifs

En Java, il existe de nombreux types de données primitifs disponibles avec leurs classes wrapper correspondantes.

Ensuite, compilons une liste pratique de toutes les conversions avec perte possibles en Java:

  • court à octet ou carbonisation
  • char en octet ou court
  • int pour octet , court ou carbonisation
  • long en octet , court , char ou int
  • float to byte , short , char , int ou long
  • double en byte , short , char , int , long ou float

Notez que bien que short et char aient la même taille. Néanmoins, la conversion de short en char est avec perte car char est un type de données non signé .

4. Techniques de conversion

4.1. Conversion entre types primitifs

La méthode la plus simple pour convertir les primitives pour éviter une conversion avec perte est la conversion descendante; en d'autres termes, le moulage du type de plus grande taille en un type de plus petite taille. Par conséquent, il est également appelé rétrécissement de la conversion primitive.

Par exemple, convertissons un long nombre en un court en utilisant le downcasting :

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

De même, convertissons un double en un entier :

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

Cependant, nous devons noter que la conversion de caractères de grande taille avec des valeurs trop grandes ou trop petites en caractères de plus petite taille par le biais du downcasting peut entraîner des valeurs inattendues.

Convertissons les valeurs longues en dehors de la plage de short :

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

Si nous analysons attentivement la conversion, nous verrons que ce ne sont pas les valeurs attendues.

En d'autres termes, lorsque Java atteint la valeur la plus élevée d'un type de petite taille lors de la conversion à partir d'un type de grande taille, le nombre suivant est la valeur la plus basse du type de petite taille et vice-versa.

Comprenons cela à travers des exemples. Lorsque largeLongNum avec la valeur 32768 est converti en short , la valeur de shortNum1 est -32768 . Parce que la valeur maximale de short est 32767, par conséquent, Java choisit la valeur minimale suivante du short.

De même, lorsque smallLongNum est converti en short . La valeur de shortNum2 est 32767 car Java utilise la valeur maximale suivante du short .

Voyons également ce qui se passe lorsque nous convertissons les valeurs max et min d'un long en 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. Conversion entre objets wrapper et types primitifs

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.