Verlustbehaftete Konvertierung in Java

1. Übersicht

In diesem kurzen Tutorial werden wir das Konzept der verlustbehafteten Konvertierung in Java und den Grund dafür diskutieren.

Gleichzeitig werden wir einige praktische Konvertierungstechniken untersuchen, um diesen Fehler zu vermeiden.

2. Verlustbehaftete Konvertierung

Eine verlustbehaftete Konvertierung ist einfach der Verlust von Informationen beim Umgang mit Daten.

In Java entspricht dies der Möglichkeit , den Wert oder die Genauigkeit einer Variablen zu verlieren, während ein Typ in einen anderen konvertiert wird .

Wenn wir versuchen , eine Variable zuweisen großen Typ in einen kleineren Typ , Java wird einen Fehler erzeugen inkompatible Typen: mögliche verlustbehaftete Umwandlung , während Sie den Code zu kompilieren.

Versuchen wir zum Beispiel, einem int ein long zuzuweisen :

long longNum = 10; int intNum = longNum;

Java gibt beim Kompilieren dieses Codes einen Fehler aus:

incompatible types: possible lossy conversion from long to int

Hier findet Java long und int inkompatibel und führt zu verlustbehafteten Konvertierungsfehlern. Weil es lange Werte außerhalb des int- Bereichs von -2.147.483.648 bis 2.147.483.647 geben kann.

Versuchen wir auf ähnliche Weise, einem Long einen Float zuzuweisen :

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

As float kann Dezimalwerte haben, die keinen entsprechenden langen Wert haben. Daher erhalten wir den gleichen Fehler.

In ähnlicher Weise verursacht das Zuweisen einer doppelten Nummer zu einem int den gleichen Fehler:

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

Die Doppelwerte können für ein int zu groß oder zu klein sein, und Dezimalwerte gehen bei der Konvertierung verloren. Daher handelt es sich um eine potenziell verlustbehaftete Umwandlung.

Außerdem können wir bei einer einfachen Berechnung auf diesen Fehler stoßen:

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

Wenn ein Double mit einem int multipliziert wird , erhalten wir das Ergebnis in einem Double . Folglich handelt es sich auch um eine potenziell verlustbehaftete Umwandlung.

Daher können die inkompatiblen Typen bei der verlustbehafteten Konvertierung entweder unterschiedliche Größen oder Typen (Ganzzahlen oder Dezimalstellen) haben.

3. Primitive Datentypen

In Java sind viele primitive Datentypen mit den entsprechenden Wrapper-Klassen verfügbar.

Als nächstes stellen wir eine praktische Liste aller möglichen verlustbehafteten Konvertierungen in Java zusammen:

  • kurz zu byte oder char
  • char zu byte oder kurz
  • int zu Byte , Short oder Char
  • long to byte , short , char oder int
  • float to byte , short , char , int oder long
  • Double to Byte , Short , Char , Int , Long oder Float

Beachten Sie, dass Short und Char die gleiche Größe haben. Dennoch die Umwandlung von kurzen zu char ist verlustbehaftete weil char unsigned Datentyp ist .

4. Konvertierungstechniken

4.1. Konvertieren zwischen primitiven Typen

Die einfache Möglichkeit, Grundelemente zu konvertieren, um eine verlustbehaftete Konvertierung zu vermeiden, besteht im Downcasting. Mit anderen Worten: Umwandeln des größeren Typs in einen kleineren Typ. Daher wird es auch als Verengung der primitiven Umwandlung bezeichnet.

Lassen Sie uns zum Beispiel eine lange Zahl mit Downcasting in eine kurze umwandeln :

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

In ähnlicher Weise konvertieren wir ein Double in ein Int :

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

Wir sollten jedoch beachten, dass das Konvertieren eines großen Typs mit zu großen oder zu kleinen Werten in einen kleineren Typ durch Downcasting zu unerwarteten Werten führen kann.

Lassen Sie uns lange Werte außerhalb des Bereichs von kurzen konvertieren :

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

Wenn wir die Konvertierung sorgfältig analysieren, werden wir feststellen, dass dies nicht die erwarteten Werte sind.

Mit anderen Worten, wenn Java beim Konvertieren von einem großen Typ den höchsten Wert eines kleinen Typs erreicht, ist die nächste Zahl der niedrigste Wert des kleinen Typs und umgekehrt.

Lassen Sie uns dies anhand von Beispielen verstehen. Wenn largeLongNum mit dem Wert 32768 in short konvertiert wird, beträgt der Wert von shortNum1 -32768 . Da der Maximalwert von short 32767 beträgt, wählt Java den nächsten Minimalwert von short.

Ebenso, wenn smallLongNum in short konvertiert wird . Der Wert von shortNum2 ist 32767, da Java den nächsten Maximalwert des Kurzschlusses angibt .

Mal sehen, was passiert, wenn wir die Max- und Min-Werte eines Longs in ein Int konvertieren :

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. Konvertieren zwischen Wrapper-Objekten und primitiven Typen

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.