Бинарные операторы java. Логические операторы

Большинство операций над примитивными типами выполняется не с помощью методов, а с помощью специальных символов, называемых знаком операции .

Операция присваивания

Присвоение переменной значения константы, другой переменной или выражения (переменных и/или констант, разделенных знаками операций), называется операцией присваивания и обозначается знаком "= ", например: x = 3 ; y = x; z = x; В Java допустимо многократное использование операции присваивания в одном выражении, например: x1 = x2 = x3 = 0 ; Эта операция выполняется справа налево, т.е. сначала переменной x3 присваивается значение 0 , затем переменной x2 присваивается значение переменной x3 (0), и, наконец, переменной x1 присваивается значение переменной x2 (0). Знаки операций, аргументами которых являются числа, разделяются на две категории: унарные (unary) знаки операций с одним аргументом и бинарные (binary) с двумя аргументами.

Унарные операции

В Java определены следующие унарные операции:
  • унарный минус " - " – меняет знак числа или выражения на противоположный;
  • унарный плюс " + " – не выполняет никаких действий над числом или выражением;
  • побитовое дополнение " ~ " (только для целых) – инвертирует все биты поля числа (меняет 0 на 1 и 1 на 0);
  • инкремент " ++ " (только для целых) – увеличивает значение переменной на 1;
  • декремент " -- " (только для целых) – уменьшает значение переменной на 1.
Примеры унарных операций " + " и " - ": int i = 3 , j, k; j= - i; // j = -3 k = + i; // k = 3 Пример операции побитового дополнения: int a = 15 ; int b; b = ~ a; // b = -16 Числа a и b являются числами типа int , т.е. представляются внутри компьютера как двоичные целые числа со знаком длиной 32 бита, поэтому двоичное представление чисел a и b будет выглядеть следующим образом: a = 00000000 00000000 00000000 00001111 b = 11111111 11111111 11111111 11110000 Как видно из этого представления, все нулевые биты в числе a изменены на единичные биты в числе b , а единичные биты в a изменены на нулевые биты. Десятичным представлением числа b будет –16 . Знаки операции инкремента и декремента могут размещаться как до, так и после переменной. Эти варианты называются соответственно префиксной и постфиксной записью этих операции. Знак операции в префиксной записи возвращает значение своего операнда после вычисления выражения. При постфиксной записи знак операции сначала воз­вращает значение своего операнда и только после этого вычисляет инкремент или декремент, например: int x = 1 , y, z; y = ++ x; z= x++ ; Переменная y будет присвоено значение 2 , поскольку сначала значение x будет увеличено на 1 , а затем результат будет присвоен переменной y . Переменной z будет присвоено значение 1 , поскольку сначала переменной z будет присвоено значение, а затем значение x будет увеличено на 1 . В обоих случаях новое значение переменной x будет равно 2 . Следует отметить, что в Java, в отличие от языка C, операции декремента и инкремента могут применяться и к вещественным переменным (типа float и double). Бинарные знаки операций подразделяются на операции с числовым результатом и операции сравнения, результатом которых является булевское значение.

Арифметические бинарные операции

В Java определены следующие арифметические бинарные операции :
  • сложение " + ";
  • вычитание " - ";
  • умножение " * ";
  • деление " / ";
  • вычисление остатка от деления целых чисел " % " (возвращает остаток от деления первого числа на второе, причем результат будет иметь тот же знак, что и делимое), например, результат операции 5%3 будет равен 2 , а результат операции (-7)%(-4) будет равен -3 . В Java операция может использоваться и для вещественных переменных (типа float или double).
Примеры бинарных арифметических операций: int x = 7 , x1, x2, x3, x4, x5; x1 = x + 10 ; // x1 = 17 x2 = x – 8 ; // x2 = -1 x3 = x2 * x; // x3 = -7 x4 = x/ 4 ; // x4 = 1 (при делении целых чисел // дробная часть отбрасывается) x5 = x% 4 // x5 = 3 (остаток от деления // 7 на 4)

Побитовые операции

  • Побитовые операции рассматривают исходные числовые значения как поля битов и выполняют над ними следующие действия:
  • установка бита в i -ой позиции поля результата в 1 , если оба бита в i -ых позициях операндов равны 1 , или в 0 в противном случае – побитовое И (" & ");
  • установка бита в i -ой позиции поля результата в 1 , если хотя бы один бит в i -ых позициях операндов равен 1 , или в 0 в противном случае – побитовое ИЛИ (" | ");
  • установка бита в i -ой позиции поля результата в 1 , если биты в i -ых позициях операндов не равны друг другу, или в 0 в противном случае – побитовое исключающее ИЛИ (" ^ ");
  • сдвиг влево битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – побитовый сдвиг влево с учетом знака " << ";
  • сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – побитовый сдвиг вправо с учетом знака " >> ";
  • сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом также сдвигается) – побитовый сдвиг вправо без учета знака " >>> ".
Примеры побитовых операций:
  1. Побитовое И

    int x = 112 ; int y = 94 ; int z; z = x & y; // z=80: 00000000 00000000 00000000 01010000
  2. Побитовое ИЛИ

    int x = 112 ; // x: 00000000 00000000 00000000 01110000 int y = 94 ; // y: 00000000 00000000 00000000 01011110 int z; z = x | y; // z = 126: 00000000 00000000 00000000 01111110
  3. Побитовое исключающее ИЛИ

    int x = 112 ; // x: 00000000 00000000 00000000 01110000 int y = 94 ; // y: 00000000 00000000 00000000 01011110 int z; z = x ^ y; // z = 46: 00000000 00000000 00000000 00101110
  4. Сдвиг влево с учетом знака

    int x = 31 , z; // x: 00000000 00000000 00000000 00011111 z = x << 2 ; // z = 124: 00000000 00000000 00000000 01111100
  5. Сдвиг вправо с учетом знака

    int x = - 17 , z; z = x >> 2 ; // z = -5: 11111111 11111111 11111111 11111011
  6. Сдвиг вправо без учета знака

    int x = - 17 , z; // x: 11111111 11111111 11111111 11101111 z = x >>> 2 ; // z = 1073741819 // z: 00111111 11111111 11111111 11111011

Комбинированные операции

В Java для бинарных арифметических операций можно использовать комбинированные (составные) знаки операций: идентификатор операция = выражение Это эквивалентно следующей операции: идентификатор = идентификатор операция выражение Примеры:
  1. Выражение x += b означает x = x + b .
  2. Выражение x -= b означает x = x - b .
  3. Выражение x *= b означает x = x * b .
  4. Выражение x /= b означает x = x / b .
  5. Выражение x %= b означает x = x % b .
  6. Выражение x &= b означает x = x & b .
  7. Выражение x |= b означает x = x | b .
  8. Выражение x ^= b означает x = x ^ b .
  9. Выражение x <<= b означает x = x << b .
  10. Выражение x >>= b означает x = x >> b .
  11. Выражение x >>>= b означает x = x >>> b .

Операции сравнения

В Java определены следующие операции сравнения:
  • " == " (равно), " != " (не равно),
  • " > " (больше), " >= " (больше или равно),
  • " < " (меньше) " <= " (меньше или равно)
имеют два операнда и возвращают булевское значение, соответствующее результату сравнения (false или true ). Следует обратить внимание, что при сравнении двух величин на равенство в Java, как и в C и в C++, используются символы "== " (два идущих без пробела друг за другом знака равенства), в отличие от оператора присваивания, в котором используется символ "= ". Использование символа " = " при сравнении двух величин либо вызывает ошибку при компиляции, либо приводит к неверному результату. Примеры операций сравнения: boolean isEqual, isNonEqual, isGreater, isGreaterOrEqual, isLess, isLessOrEqual; int x1 = 5 , x2 = 5 , x3 = 3 , x4 = 7 ; isEqual = x1 == x2; // isEqual = true isNonEqual = x1 != x2; // isNonEqual = false isGreater = x1 > x3; // isGreater = true // isGreaterOrEqual = true isGreaterOrEqual = x2 >= x3; isLess = x3 < x1; // isLess = true isLessOrEqual = x1 <= x3; // isLessOrEqual = false

Булевские операции

Булевские операции выполняются над булевскими переменными и их результатом также является значение типа boolean . В Java определены следующие булевские операции:
  • отрицание "!" – замена false на true , или наоборот;
  • операция И "&" – результат равен true , только, если оба операнда равны true , иначе результат – false ;
  • операция ИЛИ " | " – результат равен true , только, если хотя бы один из операндов равен true , иначе результат – false .
  • операция исключающее ИЛИ " ^ " – результат равен true , только, если операнды не равны друг другу, иначе результат – false .
Операции " & ", " | " и " ^ " можно, также как и соответствующие побитовые операции использовать в составных операциях присваивания: " &= ", " |= " и " ^= " Кроме того, к булевским операндам применимы операции " == " (равно) и " != " (не равно). Как видно из определения операций ИЛИ и И, операция ИЛИ приводит к результату true , когда первый операнд равен true , незави­симо от значения второго операнда, а операция И приводит к результату false , когда первый операнд равен false , независимо от значения второго операнда. В Java определены еще две булевские операции: вторые версии булевских операций И и ИЛИ, известные как укороченные (short-circuit) логические операции: укороченное И " && " и укороченное ИЛИ " || ". При использовании этих операций второй операнд вообще не будет вычисляться, что полезно в тех случаях, когда правильное функционирование правого операнда зависит от того, имеет ли левый операнд значение true или false . Примеры булевских операций: boolean isInRange, isValid, isNotValid, isEqual, isNotEqual; int x = 8 ; isInRange = x > 0 && x < 5 ; // isInRange = false isValid = x > 0 || x > 5 ; // isValid = true isNotValid = ! isValid; // isNotValid = false isEqual = isInRange == isValid; // isEqual = false // isNotEqual = true isNotEqual = isInRange != isValid

Условная операция

Условная операция записывается в форме выражение-1?выражение-2:выражение-3 . При этом сначала вычисляется выражение выражение-1 , которое должно дать булевское значение, а затем, если выражение-1 имеет значение true , вычисляется и возвращается выражение-2 как результат выполнения операции, либо (если выражение-1 имеет значение false), вычисляется и, как результат выполнения операции, возвращается выражение-3 . Пример условной операции: x= n> 1 ? 0 : 1 ; Переменной x будет присвоено значение 0 , если n>1 (выражение n>1 имеет значение true) или 1 , если n≤1 (выражение n>1 имеет значение false).

Старшинство операций

Операции в выражениях выполняются слева направо, однако, в соответствии со своим приоритетом. Так операции умножения в выражении y = x + z* 5 ; будет выполнена раньше, чем операция сложения, поскольку приоритет операции умножения выше, чем приоритет операции сложения. Приоритеты операций (в порядке уменьшения приоритета) в Java приведены в табл. 1.
Круглые скобки повышают старшинство операций, которые находятся внутри них. Так, если в приведенное выше выражение вставить скобки: y = (x + z) * 5 ; то сначала будет выполнена операция сложения, а затем операция умножения. Иногда скобки используют просто для того, чтобы сделать выражение более читаемым, например: (x > 1 ) && (x <= 5 ) ;

Преобразование и приведение типов при выполнении операций

В операции присваивания и арифметических выражениях могут использоваться литералы, переменные и выражения разных типов, например: double y; byte x; y = x + 5 ; В этом примере выполняется операция сложения переменной x типа byte и литерала 5 (типа int) и результат присваивается переменной y типа double . В Java, как и в языке C, преобразования типов при вычислении выражений могут выполняться автоматически, либо с помощью оператора приведения типа. Однако правила приведения типов несколько отличаются от правил языка C, и в целом являются более строгими, чем в языке C. При выполнении операции присваивания преобразование типов происходит автоматически, если происходит расширяющее преобразование (widening conversion) и два типа совместимы . Расширяющими преобразованиями являются преобразования byte ®short ®int ®long ®float ®double . Для расширяющих преобразований числовые типы, включая целый и с пла­вающей точкой, являются совместимыми друг с другом. Однако числовые типы не совместимы с типами char и boolean . Типы char и boolean не совмес­тимы также и друг с другом. В языке Java выполняется автоматическое преобразование типов также и при сохранении литеральной целочисленной константы (которая имеет по умолчанию тип int) в перемен­ных типа byte , short или long (однако если литерал имеет значение вне диапазона допустимых значений для данного типа, выдается сообщение об ошибке: возможная потеря точности). Если преобразование является сужающим (narrowing conversion), т. е. выполняется преобразование byte ¬ short ¬ char ¬ int ¬ long ¬ float ¬ double , то такое преобразование может привести к потере точности числа или к его искажению. Поэтому при сужающих преобразованиях при компиляции программы выводится диагностическое сообщение о несовместимости типов и файлы классов не создаются. Такое сообщение будет выдано и при попытке преобразование выражений типа byte или short в переменную типа char . Если все же необходимо выполнить такие преобразования, используется операция приведения (cast) типа, которая имеет следующий формат: (тип-преобразования ) значение , где тип-преобразования определяет тип, в который необходимо преобразовать заданное значение , например, в результате выполнения операторов: byte x = 71 ; char symbol = (char ) x; переменная symbol получит значение " G ". Если значение с плавающей точкой присваивается целому типу, то (если значение с плавающей точкой имеет дробную часть) при явном преобразовании типа происходит также усечение (truncation) числа. Так, в результате выполнения оператора int x = (int ) 77.85 ; переменная x получит значение 77 . Если же присваиваемое значение лежит вне диапазона типа-преобразования , то результатом преобразования будет остаток от деления значения на модуль диапазона присваиваемого типа (для чисел типа byte модуль диапазона будет равен 256 , для short – 65536 , для int – 4294967296 и для long – 18446744073709551616). Например, в результате выполнения оператора byte x = (byte ) 514 ; переменная x получит значение 2 . При преобразовании целых или вещественных чисел в данные типа char , преобразование в символ происходит, если исходное число лежит в диапазоне от 0 до 127, иначе символ получает значение " ? ". При выполнении арифметических и побитовых преобразований все значения byte и short , а также char расширяются до int , (при этом в вычислениях для char используется числовое значение кода символа) затем, если хотя бы один операнд имеет тип long , тип целого выражения расширяется до long . Если один из операндов имеет тип float , то тип полного вы­ражения расширяется до float , а если один из операндов имеет тип double , то тип результата будет double . Так, если объявлены переменные byte a, c; short b; то в выражении a + b* c – 15 L + 1.5F + 1.08 - 10 ; сначала, перед вычислением a + b*c значения переменных будут расширены до int , затем, поскольку константа 15 имеет тип long , перед вычитанием результат вычисления будет увеличен до long . После этого, поскольку литерал 1.5 имеет тип float перед сложением с этим литералом результат вычисления a + b*c – 15L будет расширен до float . Перед выполнением сложения с числом 1.08 результат предыдущих вычислений будет расширен до double (поскольку вещественные константы по умолчанию имеют тип double) и, наконец, перед выполнением последнего сложения литерал 10 (по умолчанию int) будет расширен до double . Таким образом, результат вычисления выражения будет иметь тип double . Автоматические расширения типов (особенно расширения short и byte до int) могут вызывать плохо распознаваемые ошибки во время компиляции. Например, в операторах: byte x = 30 , y = 5 ; x = x + y; перед выполнением сложения значение переменных x и y будет расширено до int , а затем при выполнении попытки присвоения результата вычисления типа int переменной типа byte будет выдано сообщение об ошибке. Чтобы этого избежать надо использовать во втором операторе явное преобразование типов: x = (byte ) (x + y) ; Выражение x + y необходимо заключит в скобки потому, что приоритет операции приведения типа, заключенной в скобки, выше, чем приоритет операции сложения. Кстати, если записать второй оператор в виде: x += y; то сообщения об ошибке не будет. Ссылка на перво

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

Из к/ф «Забытая мелодия для флейты»

Все операторы Java можно разделить на четыре группы: арифметические, логиче- ские, побитовые и сравнения. Рассмотрим последовательно каждую группу опе- раторов. Начнем с арифметических. Эти операторы перечислены в табл. 1.2.


Таблица 1.2. Арифметические операторы Java

Оператор Название Пояснение
+ Сложение Бинарный оператор. Результатом команды a+b являет- ся сумма значений переменных a и b
- Вычитание Бинарный оператор. Результатом команды a-b являет- ся разность значений переменных a и b
* Умножение Бинарный оператор. Результатом команды a*b являет- ся произведение значений переменных a и b
/ Деление Бинарный оператор. Результатом команды a/b являет- ся частное от деления значений переменных a и b. Для целочисленных операндов по умолчанию выполняется деление нацело
% Остаток Бинарный оператор. Результатом команды a%b яв- ляется остаток от целочисленного деления значений переменных a и b
+= Сложение (упро- щенная форма с присваиванием) Упрощенная форма оператора сложения с присваива- нием. Команда a+=b является эквивалентом команды a=a+b
-= Вычитание (упро- щенная форма с присваиванием) Упрощенная форма оператора вычитания с присваива- нием. Команда a-=b является эквивалентом команды a=a-b
*= Умножение (упро- щенная форма с присваиванием) Упрощенная форма оператора умножения с присваи- ванием. Команда a*=b является эквивалентом команды a=a*b
/= Деление (упро- щенная форма с присваиванием) Упрощенная форма оператора деления с присваива- нием. Команда a/=b является эквивалентом команды a=a/b
%= Остаток (упро- щенная форма) Упрощенная форма оператора вычисления остатка с присваиванием. Команда a%=b является эквивален- том команды a=a%b
++ Инкремент Унарный оператор. Команда a++ (или ++a) является эквивалентом команды a=a+1
-- Декремент Унарный оператор. Команда a-- (или --a) является эквивалентом команды a=a-1

Эти операторы имеют некоторые особенности. В первую очередь обращаем вни- мание на оператор деления /. Если операндами являются целые числа, в ка- честве значения возвращается результат целочисленного деления. Рассмотрим последовательность команд:

int a=5,b=2; double x=a/b;

В данном примере переменная x получает значение 2.0, а не 2.5, как можно было бы ожидать. Дело в том, что сначала вычисляется выражение a/b. Поскольку


операнды целочисленные, выполняется целочисленное деление. И только по- сле этого полученное значение преобразуется к формату double и присваивается переменной x.

Для того чтобы при целочисленных операндах выполнялось обычное деление, перед выражением с оператором деления указывается в круглых скобках иден- тификатор типа double (или float). Например, так:

double x=(double)a/b;

Теперь значение переменной x равно 2.5.

В Java, как и в С++, есть группа упрощенных арифметических операторов с присваиванием. Если op - один из операторов сложения, умножения, деления и вычисления остатка, то упрощенная форма этого оператора с присваиванием имеет вид op=. Это тоже бинарный оператор, как и оператор op, а команда вида x op=y является эквивалентом команды x=x op y.

Еще два исключительно полезных унарных оператора - операторы инкремента (++) и декремента (--). Действие оператора декремента сводится к увеличению на единицу значения операнда, а оператор декремента на единицу уменьшает операнд. Другими словами, команда x++ эквивалентна команде x=x+1, а команда x-- эквивалентна команде x=x-1. У операторов инкремента и декремента есть не только представленная здесь постфиксная форма (оператор следует после опе- ранда: x++ или x--), но и префиксная (оператор располагается перед операндом:

X или --x). С точки зрения действия на операнд нет разницы в том, префикс- ная или постфиксная формы оператора использованы. Однако если выражение с оператором инкремента или декремента является частью более сложного вы- ражения, различие в префиксной и постфиксной формах операторов инкремента и декремента существует. Если использована префиксная форма оператора, сна- чала изменяется значение операнда, а уже после этого вычисляется выражение. Если использована постфиксная форма оператора, сначала вычисляется выраже- ние, а затем изменяется значение операнда. Рассмотрим небольшой пример:

В этом случае после выполнения команд переменная n будет иметь значение 11, а переменная m - значение 10. На момент выполнения команды m=n++ значение переменной n равно 10. Поскольку в команде m=n++ использована постфиксная форма оператора инкремента, то сначала выполняется присваивание значения переменной m, а после этого значение переменной n увеличивается на единицу.

Иной результат выполнения следующих команд:


Обе переменные (n и m) в этом случае имеют значение 11. Поскольку в команде m=++n использована префиксная форма инкремента, сначала на единицу увели- чивается значение переменной n, а после этого значение переменной n присваи- вается переменной m.

Следующую группу образуют логические операторы. Операндами логических операторов являются переменные и литералы типа boolean. Логические опера- торы Java перечислены в табл. 1.3.

Таблица 1.3. Логические операторы Java

Оператор Название Пояснение
& Логическое И Бинарный оператор. Результатом операции A&B явля- ется true, если значения обоих операндов равны true. В противном случае возвращается значение false
&& Сокращенное логическое И Бинарный оператор. Особенность оператора, по срав- нению с оператором &, состоит в том, что если значе- ние первого операнда равно false, то значение второго операнда не проверяется
| Логическое ИЛИ Бинарный оператор. Результатом операции A|B являет- ся true, если значение хотя бы одного операнда равно true. В противном случае возвращается значение false
|| Сокращенное логическое ИЛИ Бинарный оператор. Особенность оператора, по срав- нению с оператором |, состоит в том, что если значе- ние первого операнда равно true, то значение второго операнда не проверяется
^ Исключающее ИЛИ Бинарный оператор. Результатом операции A^B являет- ся true, если значение одного и только одного опе- ранда равно true. В противном случае возвращается значение false
! Логическое отрицание Унарный оператор. Результатом команды!A является true, если значение операнда A равно false. Если зна- чение операнда A равно true, результатом команды!A является значение false

Логические операторы обычно используются в качестве условий в условных операторах и операторах цикла.

В табл. 1.4 перечислены операторы сравнения, используемые в Java.

Таблица 1.4. Операторы сравнения Java


Оператор Название Пояснение
< Меньше Результатом операции A
<= Меньше или равно Результатом операции A<=B является значения true, если значение операнда A не больше значения операн- да B. В противном случае значением является false
> Больше Результатом операции A>B является значения true, если значение операнда A больше значения операнда B. В противном случае значением является false
>= Больше или равно Результатом операции A>=B является значения true, если значение операнда A не меньше значения опе- ранда B. В противном случае значением является false
!= Не равно Результатом операции A!=B является значения true, если операнды A и B имеют разные значения. В про- тивном случае значением является false

Операторы сравнения обычно используются совместно с логическими операто- рами.

Для понимания принципов работы поразрядных операторов необходимо иметь хотя бы элементарные познания о двоичном представлении чисел. Напомним читателю некоторые основные моменты.

‰ В двоичном представлении позиционная запись числа содержит нули и еди- ницы.

‰ Старший бит (самый первый слева) определяет знак числа. Для положитель- ных чисел старший бит равен нулю, для отрицательных - единице.

‰ Перевод из двоичной системы счисления положительного числа с позицион-


ной записью


bnbn -1...b 2b 1b 0


(bi могут принимать значения 0 или 1, старший


бит для положительных чисел bn = 0) в десятичную выполняется так:



n -1 n





+ ... + bn -12



‰ Для перевода отрицательного двоичного числа в десятичное представление производится побитовое инвертирование кода (об операции побитового ин- вертирования - см. далее), полученное двоичное число переводится в деся- тичную систему, к нему прибавляется единица (и добавляется знак минус).

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

‰ Умножение числа на два эквивалентно сдвигу влево на один бит позиционной записи числа (с заполнением первого бита нулем).

Побитовые операторы Java описаны в табл. 1.5.


Таблица 1.5. Побитовые операторы Java

Оператор Название Пояснение
& Побитовое И Бинарный оператор. Логическая операция И приме- няется к каждой паре битов операндов. Результатом является 1, если каждый из двух сравниваемых битов равен 1. В противном случае результат равен 0
| Побитовое ИЛИ Бинарный оператор. Логическая операция ИЛИ при- меняется к каждой паре битов операндов. Результатом является 1, если хотя бы один из двух сравниваемых битов равен 1. В противном случае результат равен 0
^ Побитовое ИСКЛЮЧА- ЮЩЕЕ ИЛИ Бинарный оператор. Логическая операция ИСКЛЮЧАЮЩЕЕ ИЛИ применяется к каждой паре битов операндов. Результатом является 1, если один и только один из двух сравниваемых битов равен 1. В противном случае результат равен 0
~ Побитовое отрицание Унарный оператор. Выполняется инверсия двоичного кода: 0 меняется на 1, а 1 меняется на 0
>> Сдвиг вправо Бинарный оператор. Результатом является число, получаемое сдвигом вправо в позиционном пред- ставлении первого операнда (слева от оператора) на количество битов, определяемых вторым операндом (справа от оператора). Исходное значение перво- го операнда при этом не меняется. Младшие биты теряются, а старшие заполняются дублированием знакового бита
<< Сдвиг влево Бинарный оператор. Результатом является число, получаемое сдвигом влево в позиционном представле- нии первого операнда (слева от оператора) на количе- ство битов, определяемых вторым операндом (справа от оператора). Исходное значение первого операнда при этом не меняется. Младшие биты заполняются нулями, а старшие теряются
>>> Беззнаковый сдвиг вправо Бинарный оператор. Результатом является число, по- лучаемое сдвигом вправо в позиционном представле- нии первого операнда (слева от оператора) на количе- ство битов, определяемых вторым операндом (справа от оператора). Исходное значение первого операнда при этом не меняется. Младшие биты теряются, а старшие заполняются нулями
&= Упрощенная форма побито- вого оператора & с присваиванием Команда вида A& A=A&B
|= Упрощенная форма побито- вого оператора | с присваиванием Команда вида A|=B является эквивалентом команды A=A|B

Оператор Название Пояснение
^= Упрощенная Команда вида A^=B является эквивалентом команды
форма побито-
вого оператора ^ A=A^B
с присваиванием
>>= Упрощенная Команда вида A>>=B является эквивалентом команды
форма побитово-
го оператора >> A=A>>B
с присваиванием
<<= Упрощенная Команда вида A<<=B является эквивалентом команды
форма побитово-
го оператора << A=A<
с присваиванием
>>>= Упрощенная Команда вида A>>>=B является эквивалентом команды
форма побитово-
го оператора >>> A=A>>>B
с присваиванием

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

Помимо перечисленных операторов, в Java есть единственный тернарный опе- ратор (у оператора три операнда). Формально оператор обозначается как?:. Синтаксис вызова этого оператора следующий:

условие?значение_1:значение_2

Первым операндом указывается условие - выражение, возвращающее в качестве значения логическое значение. Если значение выражения-условия равно true, в качестве значения тернарным оператором возвращается значение_1. Если зна- чением выражения-условия является false, тернарным оператором в качестве значения возвращается значение_2.

Несколько замечаний по поводу оператора присваивания (оператор =). В Java оператор присваивания возвращает значение. Команда вида x=y выполняется следующим образом. Сначала вычисляется выражение y, после чего это выра- жение приводится к типу переменной x и затем записывается в эту переменную. Благодаря тому, что, в отличие от других операторов с равными приоритетами, присваивание выполняется справа налево, в Java допустимыми являются ко- манды вида x=y=z. В этом случае значение переменной z присваивается сначала переменной y, а затем значение переменной y присваивается переменной x.

Еще одно замечание касается упрощенных форм операторов с присваиванием, то есть операторов вида op=. Хотя утверждалось, что команда вида A op=B эк- вивалента команде A=A op B, это не совсем так. При выполнении команды вида A op=B сначала вычисляется выражение A op B, затем полученное значение при- водится к типу переменной A и только после этого присваивается переменной A. Поскольку приведение к типу переменной A выполняется, фактически, явно, а в команде A=A op B приведение типов неявное, может проявиться разница


в использовании полной и упрощенной форм команд присваивания. Рассмо- трим простой пример:

// Правильно: a+=20;

// Неправильно: a=a+b;

В данном случае команда a+=20 является корректной, а команда a=a+b - нет. В первом случае литерал 20 типа int «насильственно» приводится к типу byte в силу особенностей оператора +=. Во втором случае результат вычисления вы- ражения a+b автоматически расширяется до типа int, а автоматическое приведе- ние типа int к типу byte запрещено.

Напоследок приведем в табл. 1.6 данные о приоритете различных операторов в Java.

Таблица 1.6. Приоритеты операторов в Java

Приоритет Операторы
Круглые скобки (), квадратные скобки и оператор «точка»
Инкремент ++, декремент --, отрицания ~ и!
Умножение *, деление / и вычисление остатка %
Сложение + и вычитание -
Побитовые сдвиги >>, << и >>>
Больше >, больше или равно >=, меньше или равно <= и меньше <
Равно == и неравно!=
Побитовое И &
Побитовое исключающее ИЛИ ^
Побитовое ИЛИ |
Логическое И &&
Логические ИЛИ ||
Тернарный оператор?:
Присваивание = и сокращенные формы операторов вида op=

Операторы равных приоритетов (за исключением присваивания) выполняются слева направо. В случаях когда возникают сомнения в приоритете операторов и последовательности вычисления выражений, рекомендуется использовать круглые скобки.

Последнее обновление: 30.10.2018

Большинство операций в 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, который позволяет обойти подобные сиуации.

Большинство операций над примитивными типами выполняется не с помощью методов, а с помощью специальных символов, называемых знаком операции .

Операция присваивания

Присвоение переменной значения константы, другой переменной или выражения (переменных и/или констант, разделенных знаками операций), называется операцией присваивания и обозначается знаком "= ", например: x = 3 ; y = x; z = x; В Java допустимо многократное использование операции присваивания в одном выражении, например: x1 = x2 = x3 = 0 ; Эта операция выполняется справа налево, т.е. сначала переменной x3 присваивается значение 0 , затем переменной x2 присваивается значение переменной x3 (0), и, наконец, переменной x1 присваивается значение переменной x2 (0). Знаки операций, аргументами которых являются числа, разделяются на две категории: унарные (unary) знаки операций с одним аргументом и бинарные (binary) с двумя аргументами.

Унарные операции

В Java определены следующие унарные операции:
  • унарный минус " - " – меняет знак числа или выражения на противоположный;
  • унарный плюс " + " – не выполняет никаких действий над числом или выражением;
  • побитовое дополнение " ~ " (только для целых) – инвертирует все биты поля числа (меняет 0 на 1 и 1 на 0);
  • инкремент " ++ " (только для целых) – увеличивает значение переменной на 1;
  • декремент " -- " (только для целых) – уменьшает значение переменной на 1.
Примеры унарных операций " + " и " - ": int i = 3 , j, k; j= - i; // j = -3 k = + i; // k = 3 Пример операции побитового дополнения: int a = 15 ; int b; b = ~ a; // b = -16 Числа a и b являются числами типа int , т.е. представляются внутри компьютера как двоичные целые числа со знаком длиной 32 бита, поэтому двоичное представление чисел a и b будет выглядеть следующим образом: a = 00000000 00000000 00000000 00001111 b = 11111111 11111111 11111111 11110000 Как видно из этого представления, все нулевые биты в числе a изменены на единичные биты в числе b , а единичные биты в a изменены на нулевые биты. Десятичным представлением числа b будет –16 . Знаки операции инкремента и декремента могут размещаться как до, так и после переменной. Эти варианты называются соответственно префиксной и постфиксной записью этих операции. Знак операции в префиксной записи возвращает значение своего операнда после вычисления выражения. При постфиксной записи знак операции сначала воз­вращает значение своего операнда и только после этого вычисляет инкремент или декремент, например: int x = 1 , y, z; y = ++ x; z= x++ ; Переменная y будет присвоено значение 2 , поскольку сначала значение x будет увеличено на 1 , а затем результат будет присвоен переменной y . Переменной z будет присвоено значение 1 , поскольку сначала переменной z будет присвоено значение, а затем значение x будет увеличено на 1 . В обоих случаях новое значение переменной x будет равно 2 . Следует отметить, что в Java, в отличие от языка C, операции декремента и инкремента могут применяться и к вещественным переменным (типа float и double). Бинарные знаки операций подразделяются на операции с числовым результатом и операции сравнения, результатом которых является булевское значение.

Арифметические бинарные операции

В Java определены следующие арифметические бинарные операции :
  • сложение " + ";
  • вычитание " - ";
  • умножение " * ";
  • деление " / ";
  • вычисление остатка от деления целых чисел " % " (возвращает остаток от деления первого числа на второе, причем результат будет иметь тот же знак, что и делимое), например, результат операции 5%3 будет равен 2 , а результат операции (-7)%(-4) будет равен -3 . В Java операция может использоваться и для вещественных переменных (типа float или double).
Примеры бинарных арифметических операций: int x = 7 , x1, x2, x3, x4, x5; x1 = x + 10 ; // x1 = 17 x2 = x – 8 ; // x2 = -1 x3 = x2 * x; // x3 = -7 x4 = x/ 4 ; // x4 = 1 (при делении целых чисел // дробная часть отбрасывается) x5 = x% 4 // x5 = 3 (остаток от деления // 7 на 4)

Побитовые операции

  • Побитовые операции рассматривают исходные числовые значения как поля битов и выполняют над ними следующие действия:
  • установка бита в i -ой позиции поля результата в 1 , если оба бита в i -ых позициях операндов равны 1 , или в 0 в противном случае – побитовое И (" & ");
  • установка бита в i -ой позиции поля результата в 1 , если хотя бы один бит в i -ых позициях операндов равен 1 , или в 0 в противном случае – побитовое ИЛИ (" | ");
  • установка бита в i -ой позиции поля результата в 1 , если биты в i -ых позициях операндов не равны друг другу, или в 0 в противном случае – побитовое исключающее ИЛИ (" ^ ");
  • сдвиг влево битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – побитовый сдвиг влево с учетом знака " << ";
  • сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – побитовый сдвиг вправо с учетом знака " >> ";
  • сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом также сдвигается) – побитовый сдвиг вправо без учета знака " >>> ".
Примеры побитовых операций:
  1. Побитовое И

    int x = 112 ; int y = 94 ; int z; z = x & y; // z=80: 00000000 00000000 00000000 01010000
  2. Побитовое ИЛИ

    int x = 112 ; // x: 00000000 00000000 00000000 01110000 int y = 94 ; // y: 00000000 00000000 00000000 01011110 int z; z = x | y; // z = 126: 00000000 00000000 00000000 01111110
  3. Побитовое исключающее ИЛИ

    int x = 112 ; // x: 00000000 00000000 00000000 01110000 int y = 94 ; // y: 00000000 00000000 00000000 01011110 int z; z = x ^ y; // z = 46: 00000000 00000000 00000000 00101110
  4. Сдвиг влево с учетом знака

    int x = 31 , z; // x: 00000000 00000000 00000000 00011111 z = x << 2 ; // z = 124: 00000000 00000000 00000000 01111100
  5. Сдвиг вправо с учетом знака

    int x = - 17 , z; z = x >> 2 ; // z = -5: 11111111 11111111 11111111 11111011
  6. Сдвиг вправо без учета знака

    int x = - 17 , z; // x: 11111111 11111111 11111111 11101111 z = x >>> 2 ; // z = 1073741819 // z: 00111111 11111111 11111111 11111011

Комбинированные операции

В Java для бинарных арифметических операций можно использовать комбинированные (составные) знаки операций: идентификатор операция = выражение Это эквивалентно следующей операции: идентификатор = идентификатор операция выражение Примеры:
  1. Выражение x += b означает x = x + b .
  2. Выражение x -= b означает x = x - b .
  3. Выражение x *= b означает x = x * b .
  4. Выражение x /= b означает x = x / b .
  5. Выражение x %= b означает x = x % b .
  6. Выражение x &= b означает x = x & b .
  7. Выражение x |= b означает x = x | b .
  8. Выражение x ^= b означает x = x ^ b .
  9. Выражение x <<= b означает x = x << b .
  10. Выражение x >>= b означает x = x >> b .
  11. Выражение x >>>= b означает x = x >>> b .

Операции сравнения

В Java определены следующие операции сравнения:
  • " == " (равно), " != " (не равно),
  • " > " (больше), " >= " (больше или равно),
  • " < " (меньше) " <= " (меньше или равно)
имеют два операнда и возвращают булевское значение, соответствующее результату сравнения (false или true ). Следует обратить внимание, что при сравнении двух величин на равенство в Java, как и в C и в C++, используются символы "== " (два идущих без пробела друг за другом знака равенства), в отличие от оператора присваивания, в котором используется символ "= ". Использование символа " = " при сравнении двух величин либо вызывает ошибку при компиляции, либо приводит к неверному результату. Примеры операций сравнения: boolean isEqual, isNonEqual, isGreater, isGreaterOrEqual, isLess, isLessOrEqual; int x1 = 5 , x2 = 5 , x3 = 3 , x4 = 7 ; isEqual = x1 == x2; // isEqual = true isNonEqual = x1 != x2; // isNonEqual = false isGreater = x1 > x3; // isGreater = true // isGreaterOrEqual = true isGreaterOrEqual = x2 >= x3; isLess = x3 < x1; // isLess = true isLessOrEqual = x1 <= x3; // isLessOrEqual = false

Булевские операции

Булевские операции выполняются над булевскими переменными и их результатом также является значение типа boolean . В Java определены следующие булевские операции:
  • отрицание "!" – замена false на true , или наоборот;
  • операция И "&" – результат равен true , только, если оба операнда равны true , иначе результат – false ;
  • операция ИЛИ " | " – результат равен true , только, если хотя бы один из операндов равен true , иначе результат – false .
  • операция исключающее ИЛИ " ^ " – результат равен true , только, если операнды не равны друг другу, иначе результат – false .
Операции " & ", " | " и " ^ " можно, также как и соответствующие побитовые операции использовать в составных операциях присваивания: " &= ", " |= " и " ^= " Кроме того, к булевским операндам применимы операции " == " (равно) и " != " (не равно). Как видно из определения операций ИЛИ и И, операция ИЛИ приводит к результату true , когда первый операнд равен true , незави­симо от значения второго операнда, а операция И приводит к результату false , когда первый операнд равен false , независимо от значения второго операнда. В Java определены еще две булевские операции: вторые версии булевских операций И и ИЛИ, известные как укороченные (short-circuit) логические операции: укороченное И " && " и укороченное ИЛИ " || ". При использовании этих операций второй операнд вообще не будет вычисляться, что полезно в тех случаях, когда правильное функционирование правого операнда зависит от того, имеет ли левый операнд значение true или false . Примеры булевских операций: boolean isInRange, isValid, isNotValid, isEqual, isNotEqual; int x = 8 ; isInRange = x > 0 && x < 5 ; // isInRange = false isValid = x > 0 || x > 5 ; // isValid = true isNotValid = ! isValid; // isNotValid = false isEqual = isInRange == isValid; // isEqual = false // isNotEqual = true isNotEqual = isInRange != isValid

Условная операция

Условная операция записывается в форме выражение-1?выражение-2:выражение-3 . При этом сначала вычисляется выражение выражение-1 , которое должно дать булевское значение, а затем, если выражение-1 имеет значение true , вычисляется и возвращается выражение-2 как результат выполнения операции, либо (если выражение-1 имеет значение false), вычисляется и, как результат выполнения операции, возвращается выражение-3 . Пример условной операции: x= n> 1 ? 0 : 1 ; Переменной x будет присвоено значение 0 , если n>1 (выражение n>1 имеет значение true) или 1 , если n≤1 (выражение n>1 имеет значение false).

Старшинство операций

Операции в выражениях выполняются слева направо, однако, в соответствии со своим приоритетом. Так операции умножения в выражении y = x + z* 5 ; будет выполнена раньше, чем операция сложения, поскольку приоритет операции умножения выше, чем приоритет операции сложения. Приоритеты операций (в порядке уменьшения приоритета) в Java приведены в табл. 1.
Круглые скобки повышают старшинство операций, которые находятся внутри них. Так, если в приведенное выше выражение вставить скобки: y = (x + z) * 5 ; то сначала будет выполнена операция сложения, а затем операция умножения. Иногда скобки используют просто для того, чтобы сделать выражение более читаемым, например: (x > 1 ) && (x <= 5 ) ;

Преобразование и приведение типов при выполнении операций

В операции присваивания и арифметических выражениях могут использоваться литералы, переменные и выражения разных типов, например: double y; byte x; y = x + 5 ; В этом примере выполняется операция сложения переменной x типа byte и литерала 5 (типа int) и результат присваивается переменной y типа double . В Java, как и в языке C, преобразования типов при вычислении выражений могут выполняться автоматически, либо с помощью оператора приведения типа. Однако правила приведения типов несколько отличаются от правил языка C, и в целом являются более строгими, чем в языке C. При выполнении операции присваивания преобразование типов происходит автоматически, если происходит расширяющее преобразование (widening conversion) и два типа совместимы . Расширяющими преобразованиями являются преобразования byte ®short ®int ®long ®float ®double . Для расширяющих преобразований числовые типы, включая целый и с пла­вающей точкой, являются совместимыми друг с другом. Однако числовые типы не совместимы с типами char и boolean . Типы char и boolean не совмес­тимы также и друг с другом. В языке Java выполняется автоматическое преобразование типов также и при сохранении литеральной целочисленной константы (которая имеет по умолчанию тип int) в перемен­ных типа byte , short или long (однако если литерал имеет значение вне диапазона допустимых значений для данного типа, выдается сообщение об ошибке: возможная потеря точности). Если преобразование является сужающим (narrowing conversion), т. е. выполняется преобразование byte ¬ short ¬ char ¬ int ¬ long ¬ float ¬ double , то такое преобразование может привести к потере точности числа или к его искажению. Поэтому при сужающих преобразованиях при компиляции программы выводится диагностическое сообщение о несовместимости типов и файлы классов не создаются. Такое сообщение будет выдано и при попытке преобразование выражений типа byte или short в переменную типа char . Если все же необходимо выполнить такие преобразования, используется операция приведения (cast) типа, которая имеет следующий формат: (тип-преобразования ) значение , где тип-преобразования определяет тип, в который необходимо преобразовать заданное значение , например, в результате выполнения операторов: byte x = 71 ; char symbol = (char ) x; переменная symbol получит значение " G ". Если значение с плавающей точкой присваивается целому типу, то (если значение с плавающей точкой имеет дробную часть) при явном преобразовании типа происходит также усечение (truncation) числа. Так, в результате выполнения оператора int x = (int ) 77.85 ; переменная x получит значение 77 . Если же присваиваемое значение лежит вне диапазона типа-преобразования , то результатом преобразования будет остаток от деления значения на модуль диапазона присваиваемого типа (для чисел типа byte модуль диапазона будет равен 256 , для short – 65536 , для int – 4294967296 и для long – 18446744073709551616). Например, в результате выполнения оператора byte x = (byte ) 514 ; переменная x получит значение 2 . При преобразовании целых или вещественных чисел в данные типа char , преобразование в символ происходит, если исходное число лежит в диапазоне от 0 до 127, иначе символ получает значение " ? ". При выполнении арифметических и побитовых преобразований все значения byte и short , а также char расширяются до int , (при этом в вычислениях для char используется числовое значение кода символа) затем, если хотя бы один операнд имеет тип long , тип целого выражения расширяется до long . Если один из операндов имеет тип float , то тип полного вы­ражения расширяется до float , а если один из операндов имеет тип double , то тип результата будет double . Так, если объявлены переменные byte a, c; short b; то в выражении a + b* c – 15 L + 1.5F + 1.08 - 10 ; сначала, перед вычислением a + b*c значения переменных будут расширены до int , затем, поскольку константа 15 имеет тип long , перед вычитанием результат вычисления будет увеличен до long . После этого, поскольку литерал 1.5 имеет тип float перед сложением с этим литералом результат вычисления a + b*c – 15L будет расширен до float . Перед выполнением сложения с числом 1.08 результат предыдущих вычислений будет расширен до double (поскольку вещественные константы по умолчанию имеют тип double) и, наконец, перед выполнением последнего сложения литерал 10 (по умолчанию int) будет расширен до double . Таким образом, результат вычисления выражения будет иметь тип double . Автоматические расширения типов (особенно расширения short и byte до int) могут вызывать плохо распознаваемые ошибки во время компиляции. Например, в операторах: byte x = 30 , y = 5 ; x = x + y; перед выполнением сложения значение переменных x и y будет расширено до int , а затем при выполнении попытки присвоения результата вычисления типа int переменной типа byte будет выдано сообщение об ошибке. Чтобы этого избежать надо использовать во втором операторе явное преобразование типов: x = (byte ) (x + y) ; Выражение x + y необходимо заключит в скобки потому, что приоритет операции приведения типа, заключенной в скобки, выше, чем приоритет операции сложения. Кстати, если записать второй оператор в виде: x += y; то сообщения об ошибке не будет. Ссылка на перво

Укороченные (short-circuit) логические операторы && и || предназначаются для логических AND (И) и OR (ИЛИ) операций над выражениями типа boolean . Заметьте, что для XOR (исключающее ИЛИ) операции не существует укороченного логического оператора.

Укороченные логические операторы похожи на операторы & и |, но в отличие от них применяются только к выражениям типа boolean и никогда не применяются к интегральным типам. Тем не менее, && и || обладают замечательным свойством: они укорачивают вычисление выражения, если результат может быть дедуцирован из части выражения (чуть позже я поясню это на примерах). Благодаря этому свойству, операторы && и || широко используются для обработки null-выражений. Они также помогают увеличить эффективность всей программы.

Свойство укорачивания вытекает прямым образом из различий между &&/|| и &/|: последняя пара операторов должна получать на вход значения левого и правого операторов, в то время как для первой пары операторов иногда достаточно знать значение только левого операнда, чтобы вернуть значение всего выражения. Такое поведение укороченных логических операторов базируется на двух математических правилах логической таблицы истинности :

  • выражение с AND оператором ложно (false ), если значение хотя бы одного из его операндов ложно;
  • выражение с OR оператором истинно (true ), если значение хотя бы одного из его операндов истинно.
Иными словами:
  • false AND X = false
  • true OR X = true
То есть, если левый операнд AND выражения ложен, то и всё выражение ложно, вне зависимости от значения правого операнда. То есть при ложном левом операнде нет нужны вычислять значение правого операнда. Аналогичным образом, если левый операнд OR выражения истиннен, то истинно и всё выражения, вне зависимости от значения правого операнда, которое, следовательно, нам не нужно вычислять.

Рассмотрим пример кода, который выводит сообщение String , если строка не нулевая и более 20 символов длиной:

1. if ((s != null) && (s.length() > 20)) {
2. System.out.println(s);
3. }

Эта же задача может быть закодиравана по-другому:

1. if (s != null) {
2. if (s.length() > 20) {
3. System.out.println(s);
4. }
5. }

Если бы строка s была null , то при вызове метода s.length() мы бы получили NullPointerException . Ни в одном из двух примеров кода, однако, такая ситауция не возникнет. В частности, во втором примере, s.length() не вызывается при s = null , благодаря использованию укороченного оператора &&. Если бы тест (s!=null) возвращал ложь (false ), то есть s - несуществующая строка, то и всё выражение гарантированно ложно. Значит, отпадает необхеодимость вычислять значение второго операнда, то есть выражения (s.length()>20) .

Однако данные операторы имеют побочные эффекты. Например, если правый операнд является выражением, выполняющим некую операцию, то при применении укороченных операторов, эта операция может оазаться невыполненной в случае ложного левого операнда.

Рассмотрим пример:
// первый пример 1. int val = (int)(2 * Math.random()); 2. boolean test = (val == 0) || (++val == 2); 3. System.out.println(“test = “ + test + “\nval = “ + val); // второй пример 1. int val = (int)(2 * Math.random()); 2. boolean test = (val == 0)|(++val == 2); 3. System.out.println(“test = “ + test + “\nval = “ + val);
Первый пример иногда будет выводить на печать вот это:
test = true
val = 0

А иногда вот это:
test = true
val = 2

Второй пример иногда будет выводить на печать вот это:
test = true
val = 1

А иногда вот это:
test = true
val = 2

А дело вот в чём. Если val равно 0, то второй операнд (++val) никогда не будет вычислен, то есть val останется равным нулю. Если же изначально val равен единице, то в результате эта переменная будет инкрементирована и мы увидим val = 2 . Во втором примере, при использовании не укороченных операторов, инкремент выполняется всегда и результат будет всегда или 1 или 2 в зависимости от случайного значения выбранного на первом шаге. В обоих примерах переменная test принимает значение true , потому что либо val = 0 , либо val = 1 и инкрементируется до значения 2.

Резюмируем информацию об укороченных операторах && и ||:

  • Они применяются к операндам типа boolean ;
  • Они вычисляют значение правого операнда только если результат не может быть вычислен на основании значения левого операнда:
    • false AND X = false
    • true OR X = true