Перетворення втрат в Java

1. Огляд

У цьому короткому посібнику ми обговоримо концепцію перетворення збитків у Java та причину цього.

Одночасно ми вивчимо кілька зручних методів перетворення, щоб уникнути цієї помилки.

2. Перетворення втрат

Перетворення збитків - це просто втрата інформації під час обробки даних.

У Java це відповідає можливості втрати значення або точності змінної при перетворенні одного типу в інший.

Коли ми намагаємося привласнити змінну великогабаритного типу до типу меншого розміру , Java буде генерувати помилку, несумісні типи: можливо перетворення з втратами , при компіляції коду.

Наприклад, спробуємо призначити long для int :

long longNum = 10; int intNum = longNum;

Java видасть помилку під час компіляції цього коду:

incompatible types: possible lossy conversion from long to int

Тут Java знайде long і int несумісним і призведе до помилки перетворення з втратами. Оскільки можуть бути довгі значення за межами діапазону int від -2,147,483,648 до 2,147,483,647.

Подібним чином спробуємо призначити float для long :

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

Як float може мати десяткові значення, які не мають відповідного довгого значення. Тому ми отримаємо ту ж помилку.

Аналогічним чином, присвоєння подвійного числа int спричиняє ту ж помилку:

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

Ці подвійні значення можуть бути занадто великим або занадто маленьким для Int значень і десяткових загубиться в перетворенні. Отже, це потенційна конверсія збитків.

Крім того, ми можемо зіткнутися з цією помилкою, виконуючи простий розрахунок:

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

Коли подвійне множення на int , ми отримуємо результат у подвійному . Отже, це також потенційна конверсія збитків.

Отже, несумісні типи при перетворенні з втратами можуть мати різні розміри або типи (цілі чи десяткові числа).

3. Примітивні типи даних

У Java існує багато примітивних типів даних із відповідними класами обгортки.

Далі складемо зручний список усіх можливих перетворень з втратами в Java:

  • короткий до байта або символу
  • char в байт або короткий
  • int в байт , короткий або символ
  • довгий до байта , короткий , символ або int
  • float до байта , короткий , char , int або long
  • подвійний до байту , короткий , char , int , long або float

Зверніть увагу, що хоча короткий і символи мають однаковий розмір. Тим не менше, перетворення з короткого на char є втратним, оскільки char є непідписаним типом даних .

4. Техніка перетворення

4.1. Перетворення між примітивними типами

Найпростіший спосіб перетворення примітивів, щоб уникнути перетворення з втратами, - це зниження; іншими словами, відливання великого типу до меншого типу. Отже, це також називається звуження примітивного перетворення.

Наприклад, перетворимо довге число на коротке, використовуючи даундайтинг :

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

Аналогічним чином, давайте перетворимо подвійне в int :

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

Однак ми повинні зауважити, що перетворення великого типу із занадто великим або занадто малим значенням у менший за допомогою пониження може призвести до несподіваних значень.

Перетворимо довгі значення за межі діапазону short :

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

Якщо ми ретельно проаналізуємо конверсію, то побачимо, що це не очікувані значення.

Іншими словами, коли Java досягає найвищого значення для малогабаритного типу під час перетворення з великого типу, наступне число є найменшим значенням для малогабаритного типу і навпаки.

Давайте розберемося в цьому на прикладах. Коли largeLongNum зі значенням 32768 перетворюється на короткий , значення shortNum1 становить -32768 . Оскільки максимальне значення короткого - 32767, отже, Java переходить до наступного мінімального значення короткого.

Подібним чином, коли smallLongNum перетворюється на short . Значення shortNum2 дорівнює 32767, оскільки Java переходить до наступного максимального значення короткого .

Крім того, давайте подивимося, що відбувається, коли ми перетворюємо значення max і min long у 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. Перетворення між об'єктами-обгортками та примітивними типами

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.