Со всеми блестящими вещами ( лямбда-выражениями , потоками , 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() = 21474836422147483642 => Math.toIntExact(Long) = 21474836422147483643 => Long.intValue() = 21474836432147483643 => Math.toIntExact(Long) = 21474836432147483644 => Long.intValue() = 21474836442147483644 => Math.toIntExact(Long) = 21474836442147483645 => Long.intValue() = 21474836452147483645 => Math.toIntExact(Long) = 21474836452147483646 => Long.intValue() = 21474836462147483646 => Math.toIntExact(Long) = 21474836462147483647 => Long.intValue() = 21474836472147483647 => Math.toIntExact(Long) = 21474836472147483648 => Long.intValue() = -21474836482147483648 => Math.toIntExact(Long) = ERROR: java.lang.ArithmeticException: integer overflow2147483649 => Long.intValue() = -21474836472147483649 => Math.toIntExact(Long) = ERROR: java.lang.ArithmeticException: integer overflow2147483650 => Long.intValue() = -21474836462147483650 => Math.toIntExact(Long) = ERROR: java.lang.ArithmeticException: integer overflow2147483651 => Long.intValue() = -21474836452147483651 => 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, являются их собственными. |