Безопасное внесение long в int в Java

Какой самый идиоматический способ в 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;
}

Ответ 1

Новый метод был добавлен с Java 8, чтобы сделать именно это.

import static java.lang.Math.toIntExact;

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

Выкинет исключение ArithmeticException в случае переполнения.

Смотрите: Math.toIntExact(long)

В Java 8 добавлено несколько других методов переполнения. Они заканчиваются точными.

Примеры:

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

Ответ 2

Я думаю, что сделаю это как просто:

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

Я думаю, что это выражает намерение более четко, чем повторное кастинг... но это несколько субъективно.

Обратите внимание на потенциальный интерес - в С# это будет просто:

return checked ((int) l);

Ответ 3

С Google Guava Ints ваш метод можно изменить на:

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

Из связанных документов:

checkedCast

public static int checkedCast(long value)

Возвращает значение int, равное value, если возможно.

Параметры: value - любое значение в диапазоне типа int

Возврат:значение int, равное value

Броски: IllegalArgumentException - если value больше, чем Integer.MAX_VALUE или меньше Integer.MIN_VALUE

Кстати, вам не нужна оболочка safeLongToInt, если вы не хотите оставить ее на месте для изменения функциональности без тщательного рефакторинга, конечно.

Ответ 4

С BigDecimal:

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

Ответ 5

вот решение, в случае, если вы не заботитесь о ценности в случае, если оно больше, чем необходимо;)

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

Ответ 6

Я утверждаю, что очевидный способ увидеть, изменило ли значение значения значение, было бы бросить и проверить результат. Тем не менее я бы удалил ненужный при сравнении. Я также не слишком увлечен именами переменных одной буквы (исключение 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 почти наверняка является ошибочным исключением, которое бросает в отношении кода клиента.

Ответ 7

DONT: Это не решение!

Мой первый подход:

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

Но это просто просто отдает длинный int, потенциально создавая новые экземпляры Long или извлекая их из Long pool.


Недостатки

  • Long.valueOf создает новый экземпляр Long, если число не находится в пределах диапазона пула Long [-128, 127].

  • Реализация intValue не делает ничего:

    return (int)value;
    

Таким образом, это можно считать еще хуже, чем просто отбрасывание Long до int.

Ответ 8

Целочисленные типы Java представлены как подписанные. При вводе между 2 31 и 2 32 (или -2 31 и -2 32) актеры будут но ваш тест потерпит неудачу.

Что нужно проверить, все ли все старшие бит 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("...");
    }
}

Ответ 9

(int) (longType + 0)

но Long не может превышать максимум:)

Ответ 10

Еще одно решение может быть:

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

Я пробовал это для случаев, когда клиент делает POST, а серверная БД понимает только целые числа, в то время как у клиента есть Long.