在Java中将字节转换为int的最优雅方式

时间:2021-11-30 00:19:25

Example code:

int a = 255;
byte b = (byte) a;
int c = b & 0xff; // Here be dragons
System.out.println(a);
System.out.println(b);
System.out.println(c);

So we start with an integer value of 255, convert it to a byte (becoming -1) and then converting it back to an int by using a magic formula. The expected output is:

所以我们从255的整数值开始,将其转换为一个字节(变为-1),然后使用魔术公式将其转换回int。预期的输出是:

255
-1
255

I'm wondering if this a & 0xff is the most elegant way to to this conversion. checkstyle for example complains about using a magic number at this place and it's not a good idea to ignore this value for this check because in other places 255 may really be a magic number which should be avoided. And it's quite annoying to define a constant for stuff like this on my own. So I wonder if there is a standard method in JRE which does this conversion instead? Or maybe an already defined constant with the highest unsigned byte value (similar to Byte.MAX_VALUE which is the highest signed value)

我想知道这个&0xff是否是进行此转换的最优雅方式。 checkstyle例如抱怨在这个地方使用一个幻数,并且忽略这个检查的值不是一个好主意,因为在其他地方255可能真的是一个应该避免的幻数。而且我自己为这样的东西定义常量非常烦人。所以我想知道JRE中是否有标准方法可以进行此转换?或者可能是已定义的具有最高无符号字节值的常量(类似于Byte.MAX_VALUE,这是最高的有符号值)

So to keep the question short: How can I convert a byte to an int without using a magic number?

所以要保持简短的问题:如何在不使用幻数的情况下将字节转换为int?

Ok, so far the following possibilities were mentioned:

好的,到目前为止提到了以下可能性:

  • Keep using & 0xff and ignore the magic number 255 in checkstyle. Disadvantage: Other places which may use this number in some other scope (not bit operations) are not checked then, too. Advantage: Short and easy to read.
  • 继续使用&0xff并忽略checkstyle中的幻数255。缺点:其他可能在某些其他范围(不是位操作)中使用此数字的地方也不会被检查。优点:简单易读。

  • Define my own constant for it and then use code like & SomeConsts.MAX_UNSIGNED_BYTE_VALUE. Disadvantage: If I need it in different classes then I have to define my own constant class just for this darn constant. Advantage: No magic numbers here.
  • 为它定义我自己的常量,然后使用像&SomeConsts.MAX_UNSIGNED_BYTE_VALUE这样的代码。缺点:如果我需要在不同的类中,那么我必须为这个darn常量定义我自己的常量类。优势:这里没有神奇的数字。

  • Do some clever math like b & ((1 << Byte.SIZE) - 1). The compiler output is most likely the same because it gets optimized to a constant value. Disadvantage: Pretty much code, difficult to read. Advantage: As long as 1 is not defined as magic number (checkstyle ignores it by default) we have no magic number here and we don't need to define custom constants. And when bytes are redefined to be 16 bit some day (Just kidding) then it still works because then Byte.SIZE will be 16 and not 8.
  • 做一些聪明的数学,比如b&((1 << Byte.SIZE) - 1)。编译器输出很可能是相同的,因为它被优化为常量值。缺点:代码相当多,难以阅读。优点:只要1未被定义为幻数(checkstyle默认忽略它),我们这里没有幻数,我们不需要定义自定义常量。当字节有一天被重新定义为16位(开玩笑)时它仍然有效,因为Byte.SIZE将是16而不是8。

Are there more ideas? Maybe some other clever bit-wise operation which is shorter then the one above and only uses numbers like 0 and 1?

还有更多想法吗?也许其他一些聪明的逐位操作比上面的那个短,只使用0和1这样的数字?

5 个解决方案

#1


18  

This is the standard way to do that transformation. If you want to get rid of the checkstyle complaints, try defining a constant, it could help:

这是进行转换的标准方法。如果你想摆脱checkstyle投诉,尝试定义一个常量,它可能会有所帮助:

 public final static int MASK = 0xff;

BTW - keep in mind, that it is still a custom conversion. byte is a signed datatype so a byte can never hold the value 255. A byte can store the bit pattern 1111 1111 but this represents the integer value -1.

顺便说一句 - 请记住,它仍然是自定义转换。 byte是一个带符号的数据类型,因此一个字节永远不能保存值255.一个字节可以存储位模式1111 1111,但这表示整数值-1。

So in fact you're doing bit operations - and bit operations always require some magic numbers.

所以实际上你正在进行位操作 - 位操作总是需要一些神奇的数字。


BTW-2 : Yes, there is a Byte.MAX_VALUE constant but this is - because byte is signed - defined as 27-1 (= 127). So it won't help in your case. You need a byte constant for -1.

BTW-2:是的,有一个Byte.MAX_VALUE常量,但这是 - 因为字节是有符号的 - 定义为27-1(= 127)。所以它对你的情况没有帮助。 -1需要一个字节常量。

#2


10  

Ignore checkstyle. 0xFF is not a magic number. If you define a constant for it, the constant is a magic constant, which is much less understandable than 0xFF itself. Every programmer educated in the recent centuries should be more familiar with 0xFF than with his girlfriend, if any.

忽略checkstyle。 0xFF不是幻数。如果为它定义一个常量,则常量是一个魔术常量,这比0xFF本身更难以理解。在最近几个世纪受过教育的每个程序员都应该比他的女朋友更熟悉0xFF,如果有的话。

should we write code like this?

我们应该写这样的代码吗?

for(int i = Math.ZERO; ... )

#3


4  

Guava to the rescue.

番石榴来救援。

com.google.common.primitives.UnsignedBytes.toInt

#4


2  

I wrote a method for this like

我为此写了一个方法

public static int unsigned(byte x) {
    return int (x & 0xFF);
}

which is overloaded for short and int parameters, too (where int gets extended to long).

这也是short和int参数的重载(其中int扩展为long)。

Instead of 0xFF you could use Byte.MAX_VALUE+Byte.MAX_VALUE+1 to keep FindBug shut, but I'd consider it to be an obfuscation. And it's too easy to get it wrong (s. previous versions).

您可以使用Byte.MAX_VALUE + Byte.MAX_VALUE + 1来保持FindBug关闭,而不是0xFF,但我认为它是一个混淆。它很容易弄错(先前的版本)。

#5


1  

Java 8 provides Byte.toUnsignedInt and Byte.toUnsignedLong (probably for really big bytes) methods:

Java 8提供Byte.toUnsignedInt和Byte.toUnsignedLong(可能用于非常大的字节)方法:

byte b = (byte)255;
int c = Byte.toUnsignedInt(b); // 255
long asLong = Byte.toUnsignedLong(b); // 255

#1


18  

This is the standard way to do that transformation. If you want to get rid of the checkstyle complaints, try defining a constant, it could help:

这是进行转换的标准方法。如果你想摆脱checkstyle投诉,尝试定义一个常量,它可能会有所帮助:

 public final static int MASK = 0xff;

BTW - keep in mind, that it is still a custom conversion. byte is a signed datatype so a byte can never hold the value 255. A byte can store the bit pattern 1111 1111 but this represents the integer value -1.

顺便说一句 - 请记住,它仍然是自定义转换。 byte是一个带符号的数据类型,因此一个字节永远不能保存值255.一个字节可以存储位模式1111 1111,但这表示整数值-1。

So in fact you're doing bit operations - and bit operations always require some magic numbers.

所以实际上你正在进行位操作 - 位操作总是需要一些神奇的数字。


BTW-2 : Yes, there is a Byte.MAX_VALUE constant but this is - because byte is signed - defined as 27-1 (= 127). So it won't help in your case. You need a byte constant for -1.

BTW-2:是的,有一个Byte.MAX_VALUE常量,但这是 - 因为字节是有符号的 - 定义为27-1(= 127)。所以它对你的情况没有帮助。 -1需要一个字节常量。

#2


10  

Ignore checkstyle. 0xFF is not a magic number. If you define a constant for it, the constant is a magic constant, which is much less understandable than 0xFF itself. Every programmer educated in the recent centuries should be more familiar with 0xFF than with his girlfriend, if any.

忽略checkstyle。 0xFF不是幻数。如果为它定义一个常量,则常量是一个魔术常量,这比0xFF本身更难以理解。在最近几个世纪受过教育的每个程序员都应该比他的女朋友更熟悉0xFF,如果有的话。

should we write code like this?

我们应该写这样的代码吗?

for(int i = Math.ZERO; ... )

#3


4  

Guava to the rescue.

番石榴来救援。

com.google.common.primitives.UnsignedBytes.toInt

#4


2  

I wrote a method for this like

我为此写了一个方法

public static int unsigned(byte x) {
    return int (x & 0xFF);
}

which is overloaded for short and int parameters, too (where int gets extended to long).

这也是short和int参数的重载(其中int扩展为long)。

Instead of 0xFF you could use Byte.MAX_VALUE+Byte.MAX_VALUE+1 to keep FindBug shut, but I'd consider it to be an obfuscation. And it's too easy to get it wrong (s. previous versions).

您可以使用Byte.MAX_VALUE + Byte.MAX_VALUE + 1来保持FindBug关闭,而不是0xFF,但我认为它是一个混淆。它很容易弄错(先前的版本)。

#5


1  

Java 8 provides Byte.toUnsignedInt and Byte.toUnsignedLong (probably for really big bytes) methods:

Java 8提供Byte.toUnsignedInt和Byte.toUnsignedLong(可能用于非常大的字节)方法:

byte b = (byte)255;
int c = Byte.toUnsignedInt(b); // 255
long asLong = Byte.toUnsignedLong(b); // 255