Тихие переполнения чисел в Java
- Переполнение Java
- AddExact и обычное сложение в Java
- Целочисленное переполнение в Java
- Безопасные арифметические операции в Java
Рассмотрим этот пример:
int result = Integer.MAX_VALUE + 1;
// Приводит к Integer.MIN_VALUE из-за переполнения
В обычных арифметических операциях при переполнении Java выполняет так называемый “циклический переход”, то есть при значении > Integer.MAX_VALUE, “дальнейший счет” пойдет с Integer.MIN_VALUE.
Методы Java Math.exact
Безопасное сложение
Math.addExact() выполняет сложение и кидает ArithmeticException, если результат приведет к переполнению. Есть как int, так и long версии:
try {
int result = Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
System.out.println("Переполнение");
}
Безопасное умножение
Аналогично addExact, multiplyExact безопасно делает умножение:
try {
int result = Math.multiplyExact(100000, 100000);
} catch (ArithmeticException e) {
System.out.println("Переполнение");
}
Также есть версия для long.
Безопасное вычитание
subtractExact делает безопасное вычитание:
try {
int result = Math.subtractExact(Integer.MIN_VALUE, 1);
} catch (ArithmeticException e) {
System.out.println("Переполнение");
}
Другие арифметические методы Math.exact
Java также предоставляет несколько других точных арифметических методов:
incrementExact – увеличивает на единицу, кидает ArithmeticException:
int result = Math.incrementExact(Integer.MAX_VALUE);
decrementExact – уменьшает на единицу, кидает ArithmeticException:
int result = Math.decrementExact(Integer.MIN_VALUE);
negateExact – возвращает отрицание аргумента, кидает ArithmeticException:
int result = Math.negateExact(Integer.MIN_VALUE);
toIntExact – возвращает значение аргумента long, кидает ArithmeticException:
int result = Math.toIntExact(Long.MAX_VALUE);
Применение
Эти методы особенно полезны в:
- Финансовых расчетах, где точность критически важна
- Научных вычислениях, которые не могут допускать переполнение
- Критически важных для безопасности приложениях
Не забудем BigInteger или BigDecimal для больших чисел.
Пример
Вот практический пример, объединяющий несколько exact методов:
public class SafeCalculator {
public static int calculateTotal(int quantity, int price) {
try {
// Сначала умножаем количество на цену
int subtotal = Math.multiplyExact(quantity, price);
// Добавляем налог (предположим 10%)
int tax = Math.multiplyExact(subtotal, 10);
tax = Math.divideExact(tax, 100);
// Возвращаем итог с налогом
return Math.addExact(subtotal, tax);
} catch (ArithmeticException e) {
throw new IllegalArgumentException("Переполнение", e);
}
}
}