Lossy Conversion in Java – Java中的有损转换

最后修改: 2019年 7月 15日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we’ll discuss the concept of lossy conversion in Java and the reason behind it.

在这个快速教程中,我们将讨论Java中有损转换的概念及其背后的原因。

At the same time, we’ll explore some handy conversion techniques to avoid this error.

同时,我们将探讨一些方便的转换技巧,以避免这种错误。

2. Lossy Conversion

2.有损转换

Lossy conversion is simply the loss of information while handling data.

有损转换只是在处理数据时损失了一些信息。

In Java, it corresponds to the possibility of losing the value or precision of a variable while converting one type to another.

在Java中,它对应于在将一种类型转换为另一种类型时丢失变量的值或精度的可能性。

When we try to assign a variable of large-sized type to a smaller sized type, Java will generate an error, incompatible types: possible lossy conversion, while compiling the code.

当我们试图将一个大尺寸类型的变量赋值给一个小尺寸类型时,Java会产生一个错误,不兼容的类型:可能的有损转换同时编译代码。

For example, let’s try to assign a long to an int:

例如,让我们尝试将一个long分配给一个int

long longNum = 10;
int intNum = longNum;

Java will emit an error while compiling this code:

在编译这段代码时,Java会发出一个错误。

incompatible types: possible lossy conversion from long to int

Here, Java will find long and int incompatible and result in lossy conversion error. Because there can be long values outside the int range -2,147,483,648 to 2,147,483,647.

在这里,Java会发现longint不兼容,导致有损的转换错误。因为在int的范围-2,147,483,648到2,147,483,647之外可能有long值。

Similarly, let’s try to assign a float to a long:

同样地,让我们尝试将一个float分配给一个long

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

As float can have decimal values that don’t have corresponding long value. Therefore, we’ll receive the same error.

由于float可以有十进制的值,但没有相应的long值。因此,我们会收到同样的错误。

Similarly, assigning a double number to an int will cause the same error:

同样地,将一个double数字分配给一个int将导致同样的错误。

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

The double values can be too large or too small for an int and decimal values will get lost in the conversion. Hence, it is a potential lossy conversion.

对于int来说,double值可能过大或过小,小数点值将在转换中丢失。因此,这是一个潜在的有损失的转换。

Also, we can run into this error while performing a simple calculation:

另外,我们在进行简单的计算时也会遇到这个错误。

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

When a double multiply with an int, we get the result in a double. Consequently, it is also a potential lossy conversion.

当一个double与一个int相乘时,我们得到的结果是一个double。因此,这也是一个潜在的有损失的转换。

Therefore, the incompatible types in lossy conversion can either have different sizes or types (integers or decimals).

因此,在亏损转换中,不兼容的类型可以有不同的大小或类型(整数或小数)。

3. Primitive Data Types

3.原始数据类型

In Java, there are many primitive data types available with their corresponding wrapper classes.

在Java中,有许多原始数据类型与它们相应的封装类

Next, let’s compile a handy list of all possible lossy conversions in Java:

接下来,让我们编制一个方便的列表,列出Java中所有可能的有损转换。

  • short to byte or char
  • char to byte or short
  • int to byte, short or char
  • long to byte, short, char or int
  • float to byte, short, char, int or long
  • double to byte, short, char, int, long or float

Note that though short and char have the same size. Still, the conversion from short to char is lossy because char is an unsigned data type.

请注意,虽然shortchar的大小相同。但是,shortchar的转换是有损失的,因为char是一个无符号数据类型

4. Conversion Techniques

4.转换技术

4.1. Converting Between Primitive Types

4.1.原始类型之间的转换

The easy way of converting primitives to avoid lossy conversion is through downcasting; in other words, casting the larger-sized type to a smaller-sized type. Hence, it is also called narrowing primitive conversion.

转换基元以避免有损失的转换的简单方法是通过降级;换句话说,将较大尺寸的类型投到较小尺寸的类型。因此,它也被称为缩小的基元转换。

For instance, let’s convert a long number to a short using downcasting:

例如,让我们用下移法将长数转换为短数:。

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

Similarly, let’s convert a double to an int:

同样地,让我们把一个double转换为int

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

However, we should note that converting large-sized type with values too large or too small to smaller-sized type through downcasting can result in unexpected values.

然而,我们应该注意到,通过下划线将数值过大或过小的大尺寸类型转换为小尺寸类型,可能会导致意外的数值。

Let’s convert long values outside the range of short:

让我们转换long值在short范围之外。

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

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

If we carefully analyze the conversion, we’ll see that these are not the expected values.

如果我们仔细分析转换,就会发现这些不是预期的数值。

In other words, when Java hits the highest value of a small-sized type while converting from large-sized type, the next number is the lowest value of the small-sized type and vice-versa.

换句话说,当Java在从大尺寸类型转换时碰到小尺寸类型的最高值,下一个数字是小尺寸类型的最低值,反之亦然。

Let’s understand this through examples. When largeLongNum with the value of 32768 is converted to short, the value of shortNum1 is -32768. Because the max value of short is 32767, therefore, Java goes for the next min value of the short.

让我们通过例子来理解这一点。当值为32768的largeLongNum被转换为short时,shortNum1的值为-32768因为short的最大值为32767,因此,Java会去找short的下一个最小值。

Similarly, when smallLongNum is converted to short. The value of shortNum2 is 32767 as Java goes for the next max value of the short.

同样地,当smallLongNum被转换为short时。shortNum2的值是32767,因为Java会去找short的下一个最大值。

Also, let’s see what happens when we convert the max and min values of a long to an int:

另外,让我们看看当我们把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. Converting Between Wrapper Objects and Primitive Types

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.

为了直接将包装对象转换为基元,我们可以使用包装类中的各种方法,如intValue()shortValue()longValue()。这被称为unboxing

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

例如,让我们把一个Float对象转换成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:

另外,如果我们看一下longValue或类似方法的实现,我们会发现使用缩小的原始转换。

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.

转换后,longNum的值将是15。然而,doubleNum是15.9999,非常接近于16。

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

相反,我们可以使用Math.round()来转换为最接近的整数。

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

assertEquals(16, longNum);

4.3. Converting Between Wrapper Objects

4.3.在封装对象之间进行转换

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对象转换成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);

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

最后,我们使用Integer.valueOf()来将原始类型int转换成Integer对象。这种类型的转换被称为boxing

5. Conclusion

5.总结

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.

在这篇文章中,我们借助一些例子探讨了Java中有损转换的概念。此外,我们还汇编了一个方便的列表,列出了所有可能的有损转换。

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.

同时,我们还探索了在Java中进行数字转换的其他方便的技术。

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

这篇文章的代码实现可以在GitHub上找到over