Операторы в Java

Операторы — это символы, выполняющие операции над операндами: +, -, ==, &&, <<, ?: и др. Java унаследовала большинство операторов от C/C++, но добавила свою специфику: например, + работает для конкатенации строк, а сдвиги имеют два варианта — арифметический >> и логический >>>.

Все операторы можно разделить на группы:

  • Арифметические: + - * / % ++ --

  • Присваивания: = += -= *= /= %= &= |= ^= <<= >>= >>>=

  • Сравнения: == != < > <= >=

  • Логические: && || ! ^

  • Побитовые: & | ^ ~ << >> >>>

  • Тернарный: ? :

  • Особые: instanceof, new, ., [], () (приведение)

Важный момент — приоритет: a + b * c интерпретируется как a + (b * c). Сомневаетесь — ставьте скобки, они никогда не лишние.

Зачем это нужно

  • Производить вычисления и преобразования значений.

  • Сравнивать данные и принимать решения в if / while.

  • Работать с битами регистров (особенно актуально для микроконтроллеров и протоколов).

  • Писать компактный код через составные присваивания и тернарный оператор.

Пример 1. Арифметические операторы

public class Arithmetic {
    public static void main(String[] args) {
        int a = 17, b = 5;
        System.out.println("a + b = " + (a + b));
        System.out.println("a - b = " + (a - b));
        System.out.println("a * b = " + (a * b));
        System.out.println("a / b = " + (a / b));   // целочисленное деление
        System.out.println("a % b = " + (a % b));   // остаток

        double x = 17.0, y = 5.0;
        System.out.println("x / y = " + (x / y));   // деление с дробной частью
    }
}

Вывод:

a + b = 22
a - b = 12
a * b = 85
a / b = 3
a % b = 2
x / y = 3.4

/ между двумя int отбрасывает дробную часть. Чтобы получить дробь, хотя бы один операнд должен быть double или float.

Пример 2. Инкремент и декремент

public class IncDec {
    public static void main(String[] args) {
        int i = 5;
        System.out.println(i++);   // постфикс: вернёт 5, потом сделает 6
        System.out.println(i);     // 6
        System.out.println(++i);   // префикс: сначала 7, потом вернёт 7
        System.out.println(i);     // 7
        i--;
        System.out.println(i);     // 6
    }
}

Вывод:

5
6
7
7
6

Постфикс (i++) возвращает старое значение, потом увеличивает. Префикс (++i) сначала увеличивает, потом возвращает новое.

Пример 3. Операторы сравнения и логические

public class CompareLogic {
    public static void main(String[] args) {
        int distance = 18;
        boolean obstacle = distance < 20;
        boolean farEnough = distance > 5;

        System.out.println("obstacle  = " + obstacle);
        System.out.println("farEnough = " + farEnough);
        System.out.println("AND  = " + (obstacle && farEnough));
        System.out.println("OR   = " + (obstacle || farEnough));
        System.out.println("NOT  = " + (!obstacle));
        System.out.println("XOR  = " + (obstacle ^ farEnough));
        System.out.println("eq   = " + (distance == 18));
        System.out.println("neq  = " + (distance != 0));
    }
}

Вывод:

obstacle  = true
farEnough = true
AND  = true
OR   = true
NOT  = false
XOR  = false
eq   = true
neq  = true

&& и || — с коротким замыканием: если левый операнд уже определяет результат, правый не вычисляется.

Пример 4. Составные операторы присваивания

public class CompoundAssign {
    public static void main(String[] args) {
        int speed = 50;
        speed += 30;   // speed = speed + 30 -> 80
        speed -= 10;   // 70
        speed *= 2;    // 140
        speed /= 4;    // 35
        speed %= 10;   // 5
        System.out.println("speed = " + speed);

        String s = "Robot";
        s += " Phobo";   // конкатенация
        System.out.println(s);
    }
}

Вывод:

speed = 5
Robot Phobo

Составные операторы делают код короче и попутно неявно приводят правый операнд к типу левого.

Пример 5. Тернарный оператор

public class Ternary {
    public static void main(String[] args) {
        int distance = 12;
        String status = (distance < 15) ? "STOP" : "GO";
        System.out.println(status);

        int a = 30, b = 17;
        int max = (a > b) ? a : b;
        System.out.println("max = " + max);

        // Вложенный (читать аккуратно!)
        int score = 73;
        String grade = (score >= 90) ? "A"
                     : (score >= 75) ? "B"
                     : (score >= 60) ? "C"
                     : "F";
        System.out.println("grade = " + grade);
    }
}

Вывод:

STOP
max = 30
grade = C

condition ? a : b — возвращает a, если условие истинно, иначе b.

Пример 6. Побитовые операторы

public class Bitwise {
    public static void main(String[] args) {
        int a = 0b1100; // 12
        int b = 0b1010; // 10
        System.out.println("a & b = " + (a & b));   // 0b1000 = 8
        System.out.println("a | b = " + (a | b));   // 0b1110 = 14
        System.out.println("a ^ b = " + (a ^ b));   // 0b0110 = 6
        System.out.println("~a    = " + (~a));      // -13 (инверсия всех битов)

        // Установка/сброс/проверка бита (например, в регистре PORTB Arduino)
        int port = 0;
        port |= (1 << 3);    // включить бит 3
        System.out.println("set bit 3:   " + Integer.toBinaryString(port));
        boolean bit3 = (port & (1 << 3)) != 0;
        System.out.println("bit 3 is on: " + bit3);
        port &= ~(1 << 3);   // сбросить бит 3
        System.out.println("clear bit 3: " + Integer.toBinaryString(port));
    }
}

Вывод:

a & b = 8
a | b = 14
a ^ b = 6
~a    = -13
set bit 3:   1000
bit 3 is on: true
clear bit 3: 0

Типичный приём для микроконтроллеров: port |= (1 << N) — установить N-й бит, port &= ~(1 << N) — сбросить.

Пример 7. Сдвиги

public class Shifts {
    public static void main(String[] args) {
        int x = 16;          // 0b10000
        System.out.println(x << 2);   // 64,  умножение на 4
        System.out.println(x >> 1);   // 8,   деление на 2

        int neg = -8;
        System.out.println(neg >> 1);  // -4, арифметический сдвиг сохраняет знак
        System.out.println(neg >>> 1); // 2147483644, логический сдвиг заполняет нулями
    }
}

Вывод:

64
8
-4
2147483644

>> — арифметический (сохраняет знак), >>> — логический (заполняет нулями слева).

Пример 8. instanceof и приоритеты

public class InstanceofAndPrecedence {
    public static void main(String[] args) {
        Object obj = "AlashEd";
        if (obj instanceof String s) {   // pattern matching, Java 16+
            System.out.println("Длина строки: " + s.length());
        }

        // Приоритеты: * и / выше + и -
        int r1 = 2 + 3 * 4;     // 14
        int r2 = (2 + 3) * 4;   // 20
        System.out.println(r1 + " " + r2);

        // && выше ||
        boolean t = true, f = false;
        boolean r3 = t || f && f;   // t || (f && f) -> true
        System.out.println(r3);
    }
}

Вывод:

Длина строки: 7
14 20
true

instanceof проверяет тип объекта. С Java 16 можно сразу объявить переменную нужного типа.

Подводные камни

Предупреждение

  • Целочисленное деление: 5 / 2 == 2, а не 2.5. Чтобы получить дробь, приведите хотя бы один операнд: 5.0 / 2 или (double) a / b.

  • Деление на ноль: для целых выбрасывается ArithmeticException, для double получится Infinity или NaN.

  • == для объектов сравнивает ссылки: для строк, Integer и др. используйте .equals.

  • & vs &&: & всегда вычисляет оба операнда (нет короткого замыкания), && — только пока нужно. Для boolean обычно нужен &&.

  • Сдвиг отрицательного числа: -1 >> 1 == -1, -1 >>> 1 даст огромное положительное. Не путайте операторы.

  • Приоритет ?: ниже почти всех: int x = a > 0 ? a : -a + 1; интерпретируется как a > 0 ? a : (-a + 1). Скобки — ваши друзья.

  • Переполнение в ``*``: int big = 100_000 * 100_000; даст странное число. Приведите хотя бы один операнд к long.

См. также

Примечание

Лицензия и источники

Техническое описание адаптировано из официальной документации Oracle Java Tutorials (https://docs.oracle.com/javase/tutorial/), Oracle Free Documentation License. Перевод на русский, примеры и пояснения — © AlashEd Wiki.