在Java中安全地将long转换为int

Bri*_*ham 467 java casting

Java中最常用的方法是验证转换longint不会丢失任何信息?

这是我目前的实施:

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;
}
Run Code Online (Sandbox Code Playgroud)

Pie*_*ine 557

Java 8添加了一种新方法来实现这一目标.

import static java.lang.Math.toIntExact;

long foo = 10L;
int bar = toIntExact(foo);
Run Code Online (Sandbox Code Playgroud)

ArithmeticException如果发生溢出,将抛出.

看到: Math.toIntExact(long)

Java 8中添加了其他几种溢出安全方法.它们以精确结尾.

例子:

  • Math.incrementExact(long)
  • Math.subtractExact(long, long)
  • Math.decrementExact(long)
  • Math.negateExact(long),
  • Math.subtractExact(int, int)

  • 我们还有`addExact`和`multiplyExact`.值得注意的是,除法(`MIN_VALUE/-1`)和绝对值(`abs(MIN_VALUE)`)没有安全的便利方法. (5认同)
  • @YamashiroRion实际上toIntExact的实现首先检查强制转换是否会导致溢出,在这种情况下它会抛出ArithmeticException。仅当强制转换是安全的时,它才会执行从 long 到 int 的强制转换并返回。换句话说,如果您尝试转换一个不能表示为 int 的长数字(例如任何严格高于 2 147 483 647 的数字),它将抛出 ArithmeticException。如果您对简单的强制转换执行相同的操作,则生成的 int 值将是错误的。 (3认同)

Jon*_*eet 304

我想我会这样做:

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;
}
Run Code Online (Sandbox Code Playgroud)

我认为比重复铸造更清楚地表达了意图......但它有点主观.

注意潜在的兴趣 - 在C#中它只是:

return checked ((int) l);
Run Code Online (Sandbox Code Playgroud)

  • 我总是将范围检查作为`(!(Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE))`.我发现很难理解其他方法.可惜Java没有`除非'. (7认同)
  • @Tom:个人偏好,我猜 - 我更喜欢尽可能少的负片.如果我正在查看一个带有异常的主体的"if",我希望看到使它看起来很特殊的条件 - 就像`int`的"低于底端"的值. (7认同)
  • @Tom:在这种情况下,我会删除负片,将演员/片段放在"if"体内,然后如果你明白我的意思就抛出异常. (6认同)
  • +1.这完全属于"例外应该用于*例外*条件"规则. (5认同)
  • (在一种现代通用语言中,它将是:"呃?但是整数有任意大小?") (4认同)

pra*_*pes 129

使用Google Guava的Ints类,您的方法可以更改为:

public static int safeLongToInt(long l) {
    return Ints.checkedCast(l);
}
Run Code Online (Sandbox Code Playgroud)

来自链接的文档:

checkedCast时

public static int checkedCast(long value)

value如果可能,返回等于的int值.

参数: value - int类型范围内的任何值

返回:int等于 的值value

抛出: IllegalArgumentException - 如果value大于Integer.MAX_VALUE或小于Integer.MIN_VALUE

顺便说一下,你不需要safeLongToInt包装器,除非你想将它留在原地以便更改功能而不需要进行大量的重构.

  • 对于Guava解决方案+1,虽然不需要将它包装在另一个方法中,但只需直接调用`Ints.checkedCast(l)`. (14认同)
  • Guava还有`Ints.saturatedCast`,它将返回最近的值而不是抛出异常. (8认同)
  • 顺便提一下,番石榴的`Ints.checkedCast'正是OP所做的 (3认同)

Jai*_*aiz 29

使用BigDecimal:

long aLong = ...;
int anInt = new BigDecimal(aLong).intValueExact(); // throws ArithmeticException
                                                   // if outside bounds
Run Code Online (Sandbox Code Playgroud)

  • 好吧,它正在分配并丢弃一个BigDecimal,只是为了得到应该是一个实用方法,所以是的,那不是最好的过程. (10认同)

小智 17

这是一个解决方案,如果你不关心价值,以防它需要更大;)

public static int safeLongToInt(long l) {
    return (int) Math.max(Math.min(Integer.MAX_VALUE, l), Integer.MIN_VALUE);
}
Run Code Online (Sandbox Code Playgroud)


And*_*eas 12

不要:这不是解决方案!

我的第一个方法是:

public int longToInt(long theLongOne) {
  return Long.valueOf(theLongOne).intValue();
}
Run Code Online (Sandbox Code Playgroud)

但这只是将long转换为int,可能会创建新Long实例或从Long池中检索它们.


缺点

  1. Long.valueOfLong如果数字不在Long池范围内,则创建一个新实例[-128,127].

  2. intValue实施确实不外乎:

    return (int)value;
    
    Run Code Online (Sandbox Code Playgroud)

因此,这可以被认为不仅仅是铸造更糟糕longint.

  • 我们非常感谢您尝试提供帮助,但举例说明一些不起作用的例子与提供可行的解决方案并不完全相同.如果你想编辑添加一个正确的方法,这可能是相当不错的; 否则,它不适合作为答案发布. (4认同)
  • 好吧,为什么不同时使用DO和DONT?Tbh,有时我希望我有一个如何不做事情的列表(DONTs)来检查我是否使用了这样的模式/代码.无论如何,我可以删除这个"答案". (4认同)
  • @PeterWippermann:我添加了更多信息.你认为他们可以理解吗?足够解释? (2认同)

Tom*_*ine 7

我声称看到是否更改值的显而易见的方法是转换并检查结果.但是,我会在比较时删除不必要的演员表.我也没有一个字母的变量名过于激烈(异常xy,而不是在他们的意思,有时分别行和列()).

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;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果可能的话,我真的想避免这种转换.显然,有时它是不可能的,但在这些情况下IllegalArgumentException,就客户端代码而言,几乎肯定是错误的例外.