在 Java 中验证从 long
到 int
的转换不会丢失任何信息的最惯用方法是什么?
这是我目前的实现:
public static int safeLongToInt(long l) {
int i = (int)l;
if ((long)i != l) {
throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
}
return i;
}
Java 8 添加了一个新方法来做到这一点。
import static java.lang.Math.toIntExact;
long foo = 10L;
int bar = toIntExact(foo);
如果溢出,将抛出 ArithmeticException
。
Java 8 中添加了其他几种溢出安全方法。它们以exact 结尾。
例子:
Math.incrementExact(long)
Math.subtractExact(long, long)
Math.decrementExact(long)
Math.negateExact(long),
Math.subtractExact(int, int)
我想我会这样做:
public static int safeLongToInt(long l) {
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
throw new IllegalArgumentException
(l + " cannot be cast to int without changing its value.");
}
return (int) l;
}
我认为这比重复演员更清楚地表达了意图……但这有点主观。
注意潜在的兴趣 - 在 C# 中它只是:
return checked ((int) l);
(!(Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE))
。我发现很难理解其他方法。可惜 Java 没有 unless
。
int
的底端”。
使用 Google Guava 的 Ints 类,您的方法可以更改为:
public static int safeLongToInt(long l) {
return Ints.checkedCast(l);
}
从链接的文档:
checkedCast public static int checkedCast(long value) 如果可能,返回等于 value 的 int 值。参数: value - int 类型范围内的任何值 返回:等于 value 的 int 值 抛出:IllegalArgumentException - 如果 value 大于 Integer.MAX_VALUE 或小于 Integer.MIN_VALUE
顺便说一句,您不需要 safeLongToInt
包装器,除非您想保留它以更改功能而无需进行大量重构。
Ints.checkedCast
与 OP 完全一样
Ints.checkedCast(l)
即可。
Ints.saturatedCast
它将返回最接近的值而不是抛出异常。
使用 BigDecimal:
long aLong = ...;
int anInt = new BigDecimal(aLong).intValueExact(); // throws ArithmeticException
// if outside bounds
BigDecimal.valueOf(aLong)
而不是 new BigDecimal(aLong)
来表示不需要新实例。执行环境是否对该方法进行缓存,是特定于实现的,就像可能存在的逃逸分析一样。在大多数现实生活中,这对性能没有影响。
这是一个解决方案,以防您不关心价值,以防它比需要的更大;)
public static int safeLongToInt(long l) {
return (int) Math.max(Math.min(Integer.MAX_VALUE, l), Integer.MIN_VALUE);
}
too low
是什么意思?请提供用例。
不要:这不是解决方案!
我的第一种方法是:
public int longToInt(long theLongOne) {
return Long.valueOf(theLongOne).intValue();
}
但这只是将 long 转换为 int,可能会创建新的 Long
实例或从 Long 池中检索它们。
缺点
Long.valueOf 如果数字不在 Long 的池范围 [-128, 127] 内,则创建一个新的 Long 实例。 intValue 实现无非就是: return (int)value;
因此,这可以被认为比仅将 long
转换为 int
更糟糕。
我声称查看转换值是否改变值的明显方法是转换并检查结果。但是,我会在比较时删除不必要的演员表。我也不太喜欢单字母变量名(例外 x
和 y
,但不是当它们表示行和列时(有时分别))。
public static int intValue(long value) {
int valueInt = (int)value;
if (valueInt != value) {
throw new IllegalArgumentException(
"The long value "+value+" is not within range of the int type"
);
}
return valueInt;
}
但是,如果可能的话,我真的想避免这种转换。显然有时这是不可能的,但在那些情况下,几乎可以肯定 IllegalArgumentException
是就客户端代码而言抛出的错误异常。
Java 整数类型表示为有符号。如果输入介于 231 和 232(或 -231 和 -232)之间,则强制转换会成功,但您的测试会失败。
要检查的是 long
的所有高位是否都相同:
public static final long LONG_HIGH_BITS = 0xFFFFFFFF80000000L;
public static int safeLongToInt(long l) {
if ((l & LONG_HIGH_BITS) == 0 || (l & LONG_HIGH_BITS) == LONG_HIGH_BITS) {
return (int) l;
} else {
throw new IllegalArgumentException("...");
}
}
(int) 0xFFFFFFFF
和 (long) 0xFFFFFFFFL
具有不同的值,但它们都包含相同的“信息”,从 int 中提取原始 long 值几乎是微不足道的。
(int) (longType + 0)
但 Long 不能超过最大值:)
+ 0
不会向此转换添加任何内容,如果 Java 以与字符串类似的方式处理数字类型连接,它可能会起作用,但因为它不会无缘无故地执行添加操作。
另一种解决方案可以是:
public int longToInt(Long longVariable)
{
try {
return Integer.valueOf(longVariable.toString());
} catch(IllegalArgumentException e) {
Log.e(e.printstackstrace());
}
}
对于客户端正在执行 POST 并且服务器 DB 仅了解整数而客户端具有 Long 的情况,我已经尝试过此方法。
Integer.valueOf(Long.MAX_VALUE.toString());
导致 java.lang.NumberFormatException: For input string: "9223372036854775807"
几乎混淆了 Out-Of-Range-Exception,因为现在它的处理方式与处理包含字母的字符串相同。
addExact
和multiplyExact
。值得注意的是除法 (MIN_VALUE/-1
) 和绝对值 (abs(MIN_VALUE)
) 没有安全的便捷方法。Math.toIntExact()
而不是通常转换为int
的区别是什么?Math.toIntExact()
的实现只是将long
转换为int
。