简体   繁体   English

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

[英]Safely casting long to int in Java

What's the most idiomatic way in Java to verify that a cast from long to int does not lose any information? 在Java中验证从longint强制转换不丢失任何信息的最惯用的方法是什么?

This is my current implementation: 这是我目前的实施:

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;
}

A new method has been added with Java 8 to do just that. Java 8添加了一种新方法来实现这一目标。

import static java.lang.Math.toIntExact;

long foo = 10L;
int bar = toIntExact(foo);

Will throw an ArithmeticException in case of overflow. 如果发生溢出,将抛出ArithmeticException

See: Math.toIntExact(long) 请参阅: Math.toIntExact(long)

Several other overflow safe methods have been added to Java 8. They end with exact . Java 8中添加了其他几种溢出安全方法。它们以精确结尾。

Examples: 例子:

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

I think I'd do it as simply as: 我想我会这样做:

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;
}

I think that expresses the intent more clearly than the repeated casting... but it's somewhat subjective. 我认为比重复铸造更清楚地表达了意图......但它有点主观。

Note of potential interest - in C# it would just be: 注意潜在的兴趣 - 在C#中它只是:

return checked ((int) l);

With Google Guava's Ints class, your method can be changed to: 使用Google Guava的Ints类,您的方法可以更改为:

public static int safeLongToInt(long l) {
    return Ints.checkedCast(l);
}

From the linked docs: 来自链接的文档:

checkedCast checkedCast时

public static int checkedCast(long value)

Returns the int value that is equal to value , if possible. 如果可能,返回等于value的int值。

Parameters: value - any value in the range of the int type 参数: value - int类型范围内的任何值

Returns: the int value that equals value 返回:等于valueint value

Throws: IllegalArgumentException - if value is greater than Integer.MAX_VALUE or less than Integer.MIN_VALUE 抛出: IllegalArgumentException - 如果value大于Integer.MAX_VALUE或小于Integer.MIN_VALUE

Incidentally, you don't need the safeLongToInt wrapper, unless you want to leave it in place for changing out the functionality without extensive refactoring of course. 顺便说一下,你不需要safeLongToInt包装器,除非你想让它更改功能而不需要进行大量的重构。

With BigDecimal: 使用BigDecimal:

long aLong = ...;
int anInt = new BigDecimal(aLong).intValueExact(); // throws ArithmeticException
                                                   // if outside bounds

here is a solution, in case you don't care about value in case it is bigger then needed ;) 这是一个解决方案,如果你不关心价值,以防它需要更大;)

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

DONT: This is not a solution! 不要:这不是解决方案!

My first approach was: 我的第一个方法是:

public int longToInt(long theLongOne) {
  return Long.valueOf(theLongOne).intValue();
}

But that merely just casts the long to an int, potentially creating new Long instances or retrieving them from the Long pool. 但这只是将long转换为int,可能会创建新的Long实例或从Long池中检索它们。


The drawbacks 缺点

  1. Long.valueOf creates a new Long instance if the number is not within Long 's pool range [-128, 127]. 如果数字不在Long的池范围内,则Long.valueOf会创建一个新的Long实例[-128,127]。

  2. The intValue implementation does nothing more than: intValue实现intValue事情:

     return (int)value; 

So this can be considered even worse than just casting the long to int . 所以这可以被认为比仅仅将longint更糟糕。

I claim that the obvious way to see whether casting a value changed the value would be to cast and check the result. 我声称看到是否更改值的显而易见的方法是转换并检查结果。 I would, however, remove the unnecessary cast when comparing. 但是,我会在比较时删除不必要的演员表。 I'm also not too keen on one letter variable names (exception x and y , but not when they mean row and column (sometimes respectively)). 我也不太热衷于一个字母的变量名称(异常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;
}

However, really I would want to avoid this conversion if at all possible. 但是,如果可能的话,我真的想避免这种转换。 Obviously sometimes it's not possible, but in those cases IllegalArgumentException is almost certainly the wrong exception to be throwing as far as client code is concerned. 显然有时它是不可能的,但在那些情况下,就客户端代码而言, IllegalArgumentException几乎肯定是抛出的错误异常。

Java integer types are represented as signed. Java整数类型表示为signed。 With an input between 2 31 and 2 32 (or -2 31 and -2 32 ) the cast would succeed but your test would fail. 如果输入介于2 31和2 32之间 (或-2 31和-2 32 ),则演员会成功,但您的测试将失败。

What to check for is whether all of the high bits of the long are all the same: 什么检查是所有的高位是否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) (longType + 0)

但龙不能超过最大值:)

One other solution can be: 另一个解决方案可以是:

public int longToInt(Long longVariable)
{
    try { 
            return Integer.valueOf(longVariable.toString()); 
        } catch(IllegalArgumentException e) { 
               Log.e(e.printstackstrace()); 
        }
}

I have tried this for cases where the client is doing a POST and the server DB understands only Integers while the client has a Long. 我已经尝试过这种情况,客户端正在进行POST,而服务器数据库只能理解Integers,而客户端只有Long。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM