Со всеми блестящими вещами ( лямбда-выражениями , потоками , Optional , новым API Date / Time и т. Д.), Чтобы отвлечь мое внимание, которое пришло с JDK 8 , я не обращал особого внимания на добавление метода Math.toIntExact () , Тем не менее, это небольшое дополнение может быть довольно полезным само по себе.
Документация Javadoc для Math.toIntExact (long) гласит: «Возвращает значение long
аргумента; выбрасывая исключение, если значение переполняет int
. » Это особенно полезно в ситуациях, когда человеку дается или уже есть Long
и ему нужно вызвать API, который ожидает int
. Конечно, было бы лучше, если бы API могли быть изменены для использования одного и того же типа данных, но иногда это не поддается контролю. Когда нужно ввести Long
в int
существует вероятность переполнения целым числом, потому что числовое значение Long
может иметь большую величину, чем может точно представить int
.
Если говорят, что данный Long
никогда не будет больше, чем может хранить int
, статический метод Math.toIntExact(Long)
особенно полезен, потому что он вызовет непроверенную ArithmeticException, если возникнет такая «исключительная» ситуация, и станет очевидным, что произошла «исключительная» ситуация.
Когда Long.intValue () используется для получения целого числа из Long
, исключение не выдается, если происходит целочисленное переполнение. Вместо этого предоставляется целое число, но это значение редко будет полезным из-за переполнения целого числа. Почти в каждом возможном случае лучше встретить исключение времени выполнения, которое предупреждает о целочисленном переполнении, чем если программное обеспечение продолжит неправильно использовать номер переполнения.
В качестве первого шага в иллюстрации различий между Long.intValue()
и Math.toIntExact(Long)
следующий код генерирует диапазон значений Long
от 5 меньше, чем Integer.MAX_VALUE, до 5 больше, чем Integer.MAX_VALUE
.
Диапазон генерирования Long
s, который включает в себя Integer.MAX_VALUE
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
/** * Generate {@code Long}s from range of integers that start * before {@code Integer.MAX_VALUE} and end after that * maximum integer value. * * @return {@code Long}s generated over range includes * {@code Integer.MAX_VALUE}. */ public static List<Long> generateLongInts() { final Long maximumIntegerAsLong = Long.valueOf(Integer.MAX_VALUE); final Long startingLong = maximumIntegerAsLong - 5 ; final Long endingLong = maximumIntegerAsLong + 5 ; return LongStream.range(startingLong, endingLong).boxed().collect(Collectors.toList()); } |
В следующем листинге кода показаны два метода, которые демонстрируют два ранее упомянутых подхода для получения int
из Long
.
Использование Long.intValue()
и Math.toIntExact(Long)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
/** * Provides the {@code int} representation of the provided * {@code Long} based on an invocation of the provided * {@code Long} object's {@code intValue()} method. * * @param longRepresentation {@code Long} for which {@code int} * value extracted with {@code intValue()} will be returned. * @return {@code int} value corresponding to the provided * {@code Long} as provided by invoking the method * {@code intValue()} on that provided {@code Long}. * @throws NullPointerException Thrown if the provided long * representation is {@code null}. */ public static void writeLongIntValue( final Long longRepresentation) { out.print(longRepresentation + " => Long.intValue() = " ); try { out.println(longRepresentation.intValue()); } catch (Exception exception) { out.println( "ERROR - " + exception); } } /** * Provides the {@code int} representation of the provided * {@code Long} based on an invocation of {@code Math.toIntExact(Long)} * on the provided {@code Long}. * * @param longRepresentation {@code Long} for which {@code int} * value extracted with {@code Math.toIntExact(Long)} will be * returned. * @return {@code int} value corresponding to the provided * {@code Long} as provided by invoking the method * {@code Math.toIntExact)Long} on that provided {@code Long}. * @throws NullPointerException Thrown if the provided long * representation is {@code null}. * @throws ArithmeticException Thrown if the provided {@code Long} * cannot be represented as an integer without overflow. */ public static void writeIntExact( final Long longRepresentation) { out.print(longRepresentation + " => Math.toIntExact(Long) = " ); try { out.println(Math.toIntExact(longRepresentation)); } catch (Exception exception) { out.println( "ERROR: " + exception); } } |
Когда приведенный выше код выполняется с диапазоном Long
s, созданным в более раннем листинге кода ( полный код доступен на GitHub ), вывод будет выглядеть следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
2147483642 => Long.intValue() = 2147483642 2147483642 => Math.toIntExact(Long) = 2147483642 2147483643 => Long.intValue() = 2147483643 2147483643 => Math.toIntExact(Long) = 2147483643 2147483644 => Long.intValue() = 2147483644 2147483644 => Math.toIntExact(Long) = 2147483644 2147483645 => Long.intValue() = 2147483645 2147483645 => Math.toIntExact(Long) = 2147483645 2147483646 => Long.intValue() = 2147483646 2147483646 => Math.toIntExact(Long) = 2147483646 2147483647 => Long.intValue() = 2147483647 2147483647 => Math.toIntExact(Long) = 2147483647 2147483648 => Long.intValue() = -2147483648 2147483648 => Math.toIntExact(Long) = ERROR: java.lang.ArithmeticException: integer overflow 2147483649 => Long.intValue() = -2147483647 2147483649 => Math.toIntExact(Long) = ERROR: java.lang.ArithmeticException: integer overflow 2147483650 => Long.intValue() = -2147483646 2147483650 => Math.toIntExact(Long) = ERROR: java.lang.ArithmeticException: integer overflow 2147483651 => Long.intValue() = -2147483645 2147483651 => Math.toIntExact(Long) = ERROR: java.lang.ArithmeticException: integer overflow |
Integer.MAX_VALUE
строки указывают код, обрабатывающий Long
со значением, равным Integer.MAX_VALUE
. После этого отображается Long
представляющий единицу больше, чем Integer.MAX_VALUE
с результатами попытки преобразования этого Long
в int
с использованием Long.intValue()
и Math.toIntExact(Long)
. Long.intValue()
встречает целочисленное переполнение, но не вызывает исключение и вместо этого возвращает отрицательное число -2147483648 . Метод Math.toIntExact(Long)
не возвращает значение при переполнении целого числа, а вместо этого выдает Math.toIntExact(Long)
ArithmeticException
с информативным сообщением «переполнение целого числа».
Метод Math.toIntExact(Long)
не так важен, как многие из функций, представленных в JDK 8, но он может быть полезен во избежание ошибок, связанных с целочисленным переполнением, которые иногда бывает сложно диагностировать.
Опубликовано на Java Code Geeks с разрешения Дастина Маркса, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Точное преобразование Long в Int в Java
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |