Java Math.divideExact(): избегание ошибок переполнения диапазона

В Java мы можем разделить два числа, используя оператор деления('/') как часть простой математики. Начиная с Java 18, мы можем использовать метод Math.divideExact(), который выдает ArithmeticException, если результат переполняется.

1. Проблема переполнения

Давайте начнем с простого примера деления в Java. Мы делим 100 на -1. Результат -100. Это простой пример использования, который работает так, как и ожидалось.

 результат int = 100 / -1;System.out.println(результат); // -100

Давайте усложним задачу и применим деление больших чисел. Мы делим значение Integer.MIN_VALUE на -1, что дает -2 147 483 648. Это неверный результат.

 int maxInteger = Integer.MAX_VALUE; // 2,147,483,647int minInteger = Integer.MIN_VALUE; // -2,147,483,648int частное = minInteger/-1; // -2 147 483 648

Приведенный выше результат неверен, поскольку он должен быть равен +2 147 483 648, что не вписывается в область int. Область int была переполнена и в результате получилось |Integer.MIN_VALUE| > |Integer.MAX_VALUE|(сравнение абсолютных значений ).

Та же проблема возникнет и для типа данных long, когда мы используем Long.MIN_VALUE. Следующее деление также неверно и должно было дать положительное число.

long y = Long.MIN_VALUE; // -9,223,372,036,854,775,808long quotient = y / -1; // -9,223,372,036,854,775,808

2. Решение: Math.divideExact()

Начиная с JDK 18, класс Math имеет два дополнительных метода divideExact() — один для типа данных int и второй для long.

 публичный статический int divideExact(int x, int y)публичный статический длинный делительExact(длинный x, длинный y)

Эти методы возвращают частное аргументов, как и ожидалось. Кроме того, эти методы выдают ArithmeticException:

  • если результат переполняется
  • если y(делитель) равен нулю

Если быть точным, переполнение происходит в этом методе ТОЛЬКО ЕСЛИ x равен Integer.MIN_VALUE, а y равен -1. В таких случаях эти методы выдают ArithmeticException вместо того, чтобы возвращать вводящий в заблуждение результат.

 int quotientExactFine = Math.divideExact(4, -1);System.out.println(quotientExactFine);int quotientExactEx = Math.divideExact(x, -1);System.out.println(quotientExactEx);

Вывод программы:

-4Exception in thread "main" java.lang.ArithmeticException: integer overflowat java.base/java.lang.Math.divideExact(Math.java:1065)at com.howtodoinjava.core.basic.math.MathDivideExact.main(MathDivideExact.java:25)

3. Заключение

Как обсуждалось в этом руководстве, метод Math.divideExact() очень полезен, если результат деления склонен к переполнению int или long(поскольку Integer.MIN_VALUE/Long.MIN_VALUE выходит за пределы положительного диапазона).

Стоит помнить об использовании классов BigInteger и BigDecimal при работе с большими числами, которые поддерживают значения в диапазоне от -2Integer.MAX_VALUE(исключая) до +2Integer.MAX_VALUE(исключая), и практически невозможно пересечь этот предел в реальном приложении.

Исходный код на Github

Прокрутить вверх