Перейти к основному содержимому

Преобразование с потерями в Java

· 6 мин. чтения

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 длинному :

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;

Когда double умножается на int , мы получаем результат в виде double . Следовательно, это также потенциальное преобразование с потерями.

Следовательно, несовместимые типы при преобразовании с потерями могут иметь разные размеры или типы (целые или десятичные числа). **

**

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

В Java доступно множество примитивных типов данных с соответствующими классами-оболочками .

Далее составим удобный список всех возможных преобразований с потерями в Java:

  • короткий до байта или символа
  • char в байт или короткий
  • int в byte , short или char
  • long to byte , short , char или int
  • плавать в byte , short , char , int или long
  • удвоить в byte , short , char , int , long или float

Обратите внимание, что короткие и char имеют одинаковый размер. Тем не менее, преобразование из типа short в char происходит с потерями, поскольку char является беззнаковым типом данных .

4. Методы преобразования

4.1. Преобразование между примитивными типами

Самый простой способ преобразования примитивов , чтобы избежать преобразования с потерями, — это преобразование вниз; другими словами, преобразование шрифта большего размера в шрифт меньшего размера. Следовательно, это также называется сужающим примитивным преобразованием.

Например, давайте преобразуем длинное число в короткое , используя понижающее приведение :

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

Точно так же давайте преобразуем double в int :

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

Однако следует отметить, что преобразование шрифта большого размера со слишком большими или слишком маленькими значениями в тип меньшего размера посредством понижения может привести к неожиданным значениям.

Преобразуем длинные значения вне диапазона коротких :

long largeLongNum = 32768; 
short minShortNum = (short) largeLongNum;
assertEquals(-32768, minShortNum);

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

Если мы внимательно проанализируем конверсию, то увидим, что это не ожидаемые значения.

Другими словами, когда Java достигает максимального значения мелкого типа при преобразовании из крупноразмерного типа, следующее число является наименьшим значением мелкоразмерного типа, и наоборот.

Давайте разберемся в этом на примерах. Когда largeLongNum со значением 32768 преобразуется в short , значение shortNum1 равно -32768 . Поскольку максимальное значение short равно 32767, поэтому Java выбирает следующее минимальное значение short.

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

Кроме того, давайте посмотрим, что произойдет, когда мы преобразуем максимальное и минимальное значения 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. Преобразование между объектами-оболочками и примитивными типами

Чтобы напрямую преобразовать объект-оболочку в примитив, мы можем использовать различные методы в классах-оболочках, такие как intValue() , shortValue() и longValue() . Это называется распаковкой .

Например, давайте преобразуем объект Float в long :

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

Кроме того, если мы посмотрим на реализацию longValue или подобных методов, мы обнаружим использование сужающего примитивного преобразования:

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

Однако иногда следует избегать сужения примитивного преобразования, чтобы сохранить ценную информацию:

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

После преобразования значение longNum будет равно 15. Однако значение doubleNum равно 15,9999, что очень близко к 16.

Вместо этого мы можем использовать Math.round() для преобразования в ближайшее целое число:

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

assertEquals(16, longNum);

4.3. Преобразование между объектами-оболочками

Для этого воспользуемся уже рассмотренными методами конвертации.

Сначала мы преобразуем объект-оболочку в примитивное значение, приведем его к понижению и преобразуем в другой объект-оболочку . Другими словами, мы будем выполнять методы распаковки, преобразования вниз и упаковки.

Например, давайте преобразуем объект Double в объект Integer :

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

Наконец, мы используем Integer . valueOf() для преобразования примитивного типа int в объект Integer . Этот тип преобразования называется боксом .

5. Вывод

В этой статье мы рассмотрели концепцию преобразования с потерями в Java с помощью ряда примеров. Кроме того, мы составили удобный список всех возможных преобразований с потерями.

Попутно мы определили сужающее примитивное преобразование как простой метод преобразования примитивных чисел и избежания ошибки преобразования с потерями.

В то же время мы также изучили дополнительные удобные методы числового преобразования в Java.

Реализации кода для этой статьи можно найти на GitHub .