Арифметические операторы Java
Операторы +, -, *, /, % в Java: целочисленное деление, приоритет операторов и особенности чисел с плавающей точкой.
В Java есть пять арифметических операторов: сложение, вычитание, умножение, деление и остаток от деления. Их синтаксис такой же, как в C, JavaScript или Python, однако статическая типизация Java создаёт несколько неочевидных ситуаций, связанных с делением и переполнением, о которых стоит знать прежде, чем начинать вычисления.
На этой странице рассмотрены все пять операторов, объясняется, почему целочисленное деление усекает результат, как ведёт себя % с отрицательными числами, каков приоритет операторов, что делают сокращения ++/--, что такое «тихое» целочисленное переполнение и почему числа с плавающей точкой могут давать неожиданные результаты. Полный список операторов Java см. в обзоре Java Operators.
Пять операторов
int a = 14;
int b = 4;
System.out.println(a + b); // 18
System.out.println(a - b); // 10
System.out.println(a * b); // 56
System.out.println(a / b); // 3 — integer division
System.out.println(a % b); // 2 — remainderЦелочисленное деление усекает результат
Если оба операнда / являются целыми числами, результат также будет целым — дробная часть отбрасывается (усечение в сторону нуля):
System.out.println(7 / 2); // 3, not 3.5
System.out.println(-7 / 2); // -3
System.out.println(1 / 3); // 0Чтобы получить вещественный результат, хотя бы один из операндов должен иметь тип с плавающей точкой. Можно записать литерал как double (7.0) или привести int к double:
System.out.println(7.0 / 2); // 3.5
System.out.println(7 / 2.0); // 3.5
System.out.println((double) 7 / 2); // 3.5Приведение типа имеет более высокий приоритет, чем /, поэтому (double) 7 / 2 сначала приводит 7 к double, а затем выполняет деление — результат 3.5. Будьте осторожны с (double) (7 / 2): сначала выполняется целочисленное деление, и вы получите 3.0.
Это частая ловушка для начинающих. Если вы видите 0 там, где ожидали ненулевое частное, — скорее всего, виновато целочисленное деление.
Оператор остатка %
% возвращает остаток от целочисленного деления. Он определён так, что (a / b) * b + (a % b) == a:
System.out.println(10 % 3); // 1
System.out.println(-10 % 3); // -1 — sign matches the dividend
System.out.println(10 % -3); // 1Типичные применения:
- Проверка делимости:
if (n % 2 == 0)проверяет чётность. - Циклическая индексация:
arr[(i + 1) % arr.length]возвращается к0после последнего элемента. - Выделение цифр или единиц:
n % 10— последняя цифра числа;seconds % 60— секунды в пределах минуты.
Другие числовые функции — возведение в степень, округление, квадратный корень — доступны через Java Math Class.
% также работает с double, где возвращает остаток по стандарту IEEE 754. Для более точного управления можно использовать метод Math.IEEEremainder.
Приоритет операторов
Действуют стандартные правила:
- Сначала
*,/,% - Затем
+,- - Слева направо при одинаковом уровне приоритета
int result = 2 + 3 * 4; // 14, not 20
int result2 = (2 + 3) * 4; // 20
int result3 = 10 - 2 - 3; // 5 — left-to-rightЕсли есть сомнения — ставьте скобки. Это ничего не стоит.
Инкремент и декремент — ++ и --
Унарные ++ и -- увеличивают или уменьшают значение переменной на 1:
int x = 5;
x++; // x is 6
x--; // x is 5Они существуют в префиксной (++x) и постфиксной (x++) формах. Разница важна только внутри выражения:
int a = 5;
int b = a++; // postfix: b is 5 (old value), a becomes 6
int c = ++a; // prefix: a becomes 7, c is 7Для наглядности рекомендуется использовать ++ и -- отдельной строкой, когда это возможно.
Переполнение происходит незаметно
Целочисленная арифметика для int и long при переполнении перекручивается — исключение не выбрасывается:
int max = Integer.MAX_VALUE; // 2147483647
int wrapped = max + 1; // -2147483648 (Integer.MIN_VALUE)Если нужно обнаружение переполнения, используйте Math.addExact, Math.multiplyExact и другие методы, которые выбрасывают ArithmeticException при переполнении.
Особенности чисел с плавающей точкой
double соответствует стандарту IEEE 754 — быстрый и хорошо поддерживаемый, однако большинство десятичных дробей не может быть представлено им точно:
System.out.println(0.1 + 0.2); // 0.30000000000000004Это не ошибка Java — так работает двоичная арифметика с плавающей точкой. Для денежных расчётов, научной точности или любых вычислений, требующих точной десятичной арифметики, используйте BigDecimal:
import java.math.BigDecimal;
BigDecimal sum = new BigDecimal("0.1").add(new BigDecimal("0.2"));
System.out.println(sum); // 0.3(Всегда передавайте строку в new BigDecimal(...); new BigDecimal(0.1) по-прежнему захватит двоичную неточность.)
Демонстрация
Что дальше
Java Assignment Operators — =, += и семейство операторов составного присваивания.