Большинство операций в Java аналогичны тем, которые применяются в других си-подобных языках. Есть унарные операции (выполняются над одним операндом), бинарные - над двумя операндами, а также тернарные - выполняются над тремя операндами. Операндом является переменная или значение (например, число), участвующее в операции. Рассмотрим все виды операций.
В арифметических операциях участвуют числа. В Java есть бинарные арифметические операции (производятся над двумя операндами) и унарные (выполняются над одним операндом). К бинарным операциям относят следующие:
+
операция сложения двух чисел:
int a = 10; int b = 7; int c = a + b; // 17 int d = 4 + b; // 11
-
операция вычитания двух чисел:
int a = 10; int b = 7; int c = a - b; // 3 int d = 4 - a; // -6
*
операция умножения двух чисел
int a = 10; int b = 7; int c = a * b; // 70 int d = b * 5; // 35
/
операция деления двух чисел:
int a = 20; int b = 5; int c = a / b; // 4 double d = 22.5 / 4.5; // 5.0
При делении стоит учитывать, что если в операции участвуют два целых числа, то результат деления будет округляться до целого числа, даже если результат присваивается переменной float или double:
double k = 10 / 4; // 2 System.out.println(k);
Чтобы результат представлял число с плавающей точкой, один из операндов также должен представлять число с плавающей точкой:
double k = 10.0 / 4; // 2.5 System.out.println(k);
%
получение остатка от деления двух чисел:
int a = 33; int b = 5; int c = a % b; // 3 int d = 22 % 4; // 2 (22 - 4*5 = 2)
Также есть две унарные арифметические операции, которые производятся над одним числом: ++ (инкремент) и -- (декремент). Каждая из операций имеет две разновидности: префиксная и постфиксная:
++ (префиксный инкремент)
Предполагает увеличение переменной на единицу, например, z=++y
(вначале значение переменной y увеличивается на 1,
а затем ее значение присваивается переменной z)
int a = 8; int b = ++a; System.out.println(a); // 9 System.out.println(b); // 9
++ (постфиксный инкремент)
Также представляет увеличение переменной на единицу, например, z=y++
(вначале значение переменной y присваивается
переменной z, а потом значение переменной y увеличивается на 1)
int a = 8; int b = a++; System.out.println(a); // 9 System.out.println(b); // 8
-- (префиксный декремент)
уменьшение переменной на единицу, например, z=--y
(вначале значение переменной y уменьшается на 1,
а потом ее значение присваивается переменной z)
int a = 8; int b = --a; System.out.println(a); // 7 System.out.println(b); // 7
-- (постфиксный декремент)
z=y--
(сначала значение переменной y присваивается переменной z, а затем значение переменной y уменьшается на 1)
int a = 8; int b = a--; System.out.println(a); // 7 System.out.println(b); // 8
Одни операции имеют больший приоритет, чем другие, и поэтому выполняются вначале. Операции в порядке уменьшения приоритета:
++ (постфиксный инкремент), -- (постфиксный декремент)
++ (префиксный инкремент), -- (префиксный декремент)
* (умножение), / (деление), % (остаток от деления)
+ (сложение), - (вычитание)
Приоритет операций следует учитывать при выполнении набора арифметических выражений:
int a = 8; int b = 7; int c = a + 5 * ++b; System.out.println(c); // 48
Вначале будет выполняться операция инкремента ++b
, которая имеет больший приоритет - она увеличит значение переменной b и возвратит его в
качестве результата. Затем выполняется умножение 5 * ++b
, и только в последнюю очередь выполняется сложение a + 5 * ++b
Скобки позволяют переопределить порядок вычислений:
int a = 8; int b = 7; int c = (a + 5) * ++b; System.out.println(c); // 104
Несмотря на то, что операция сложения имеет меньший приоритет, но вначале будет выполняться именно сложение, а не умножение, так как операция сложения заключена в скобки.
Кроме приоритета операции отличаются таким понятием как ассоциативность. Когда операции имеют один и тот же приоритет, порядок вычисления определяется ассоциативностью операторов. В зависимости от ассоциативности есть два типа операторов:
Левоассоциативные операторы, которые выполняются слева направо
Правоассоциативные операторы, которые выполняются справа налево
Так, некоторые операции, например, операции умножения и деления, имеют один и тот же приоритет. Какой же тогда будет результат в выражении:
int x = 10 / 5 * 2;
Стоит нам трактовать это выражение как (10 / 5) * 2
или как 10 / (5 * 2)
? Ведь в зависимости от трактовки мы получим разные результаты.
Все арифметические операторы (кроме префиксного инкремента и декремента) являются левоассоциативными, то есть выполняются слева направо. Поэтому выражение 10 / 5 * 2
необходимо трактовать как (10 / 5) * 2
,
то есть результатом будет 4.
Следует отметить, что числа с плавающей точкой не подходят для финансовых и других вычислений, где ошибки при округлении могут быть критичными. Например:
double d = 2.0 - 1.1; System.out.println(d);
В данном случае переменная d будет равна не 0.9, как можно было бы изначально предположить, а 0.8999999999999999. Подобные ошибки точности возникают из-за того, что на низком уровне для представления чисел с плавающей точкой применяется двоичная система, однако для числа 0.1 не существует двоичного представления, также как и для других дробных значений. Поэтому в таких случаях обычно применяется класс BigDecimal, который позволяет обойти подобные ситуации.