Перейти к основному содержимому

Составные операторы Java

· 5 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Обзор

В этом руководстве мы рассмотрим составные операторы Java, их типы и то, как Java их оценивает.

Мы также объясним, как работает неявное приведение типов.

2. Составные операторы присваивания

Оператор присваивания — это бинарный оператор, который присваивает результат правой части переменной в левой части. Самым простым является оператор присваивания «=» :

int x = 5;

Этот оператор объявляет новую переменную x , присваивает x значение 5 и возвращает 5 .

Составные операторы присваивания — это более короткий способ применить арифметическую или побитовую операцию и присвоить значение операции переменной в левой части.

Например, следующие два оператора умножения эквивалентны, то есть a и b будут иметь одно и то же значение:

int a = 3, b = 3, c = -2;
a = a * c; // Simple assignment operator
b *= c; // Compound assignment operator

Важно отметить, что переменная слева от составного оператора присваивания должна быть уже объявлена. Другими словами, составные операторы нельзя использовать для объявления новой переменной.

Подобно оператору присваивания «=», составные операторы возвращают присвоенный результат выражения:

long x = 1;
long y = (x+=2);

И x , и y будут содержать значение 3 .

Присваивание (x+=2) делает две вещи: во-первых, оно добавляет 2 к значению переменной x , которое становится равным 3; во-вторых, он возвращает значение присваивания, которое также равно 3 .

3. Типы составных операторов присваивания

Java поддерживает 11 составных операторов присваивания. Мы можем сгруппировать их в арифметические и побитовые операторы.

Давайте пройдемся по арифметическим операторам и операциям, которые они выполняют:

  • Приращение: +=
  • Декрементация: -=
  • Умножение: *=
  • Раздел: /=
  • Модуль: %=

Затем у нас также есть побитовые операторы:

  • И, двоичный: &=
  • Исключающее ИЛИ, двоичное: ^=
  • Включающее ИЛИ, двоичное: |=
  • Сдвиг влево, двоичный: <<=
  • Сдвиг вправо, двоичный: >=
  • Сдвиг вправо нулевой заливки: >>>=

Рассмотрим несколько примеров таких операций:

// Simple assignment
int x = 5; // x is 5

// Incrementation
x += 5; // x is 10

// Decrementation
x -= 2; // x is 8

// Multiplication
x *= 2; // x is 16

// Modulus
x %= 3; // x is 1

// Binary AND
x &= 4; // x is 0

// Binary exclusive OR
x ^= 4; // x is 4

// Binary inclusive OR
x |= 8; // x is 12

Как мы видим здесь, синтаксис для использования этих операторов согласован.

4. Оценка сложных операций присваивания

Есть два способа, которыми Java оценивает составные операции.

Во- первых, когда левый операнд не является массивом, Java будет по порядку:

  1. Убедитесь, что операнд является объявленной переменной
  2. Сохраните значение левого операнда
  3. Оценить правый операнд
  4. Выполните бинарную операцию, как указано составным оператором
  5. Преобразование результата бинарной операции в тип левой переменной (неявное приведение)
  6. Назначьте преобразованный результат левой переменной

Далее, когда левый операнд является массивом, шаги немного отличаются:

  1. Проверьте выражение массива в левой части и сгенерируйте исключение NullPointerException или ArrayIndexOutOfBoundsException , если оно неверно.
  2. Сохраните элемент массива в индексе
  3. Оценить правый операнд
  4. Проверьте, является ли выбранный компонент массива примитивным или ссылочным типом, а затем выполните те же действия, что и в первом списке, как если бы левый операнд был переменной.

Если какой-либо шаг оценки завершается неудачно, Java не продолжает выполнять следующие шаги.

Приведем несколько примеров, связанных с вычислением этих операций над элементом массива:

int[] numbers = null;

// Trying Incrementation
numbers[2] += 5;

Как и следовало ожидать, это вызовет исключение NullPointerException .

Однако, если мы присвоим начальное значение массиву:

int[] numbers = {0, 1};

// Trying Incrementation
numbers[2] += 5;

Мы бы избавились от исключения NullPointerException, но все равно получили бы исключение ArrayIndexOutOfBoundsException , так как используемый индекс неверен.

Если мы это исправим, операция завершится успешно:

int[] numbers = {0, 1};

// Incrementation
numbers[1] += 5; // x is now 6

Наконец, переменная x будет равна 6 в конце присваивания.

5. Неявное приведение

Одна из причин, по которой составные операторы полезны, заключается в том, что они не только обеспечивают более короткий путь для операций, но и неявно приводят переменные.

Формально составное выражение присваивания вида:

Е1 оп= Е2

эквивалентно:

E1 - (T) (E1 или E2)

где T — тип E1 .

Рассмотрим следующий пример:

long number = 10;
int i = number;
i = i * number; // Does not compile

Давайте рассмотрим, почему последняя строка не компилируется.

Java автоматически продвигает меньшие типы данных к большим, когда они находятся вместе в операции, но выдает ошибку при попытке преобразования из больших типов в меньшие .

Итак, сначала меня повысят до длинной , а затем умножение даст результат 10L. Длинный результат будет присвоен i , который является int , и это вызовет ошибку.

Это можно исправить с помощью явного приведения:

i = (int) i * number;

Составные операторы присваивания Java идеально подходят в этом случае, потому что они выполняют неявное приведение типов:

i *= number;

Этот оператор прекрасно работает, приводя результат умножения к типу int и присваивая значение левой переменной i .

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

В этой статье мы рассмотрели составные операторы в Java, приведя несколько примеров и их различные типы. Мы объяснили, как Java оценивает эти операции.

Наконец, мы также рассмотрели неявное приведение типов — одну из причин, по которой эти сокращенные операторы полезны.

Как всегда, все фрагменты кода, упомянутые в этой статье, можно найти в нашем репозитории GitHub .