1. Булевы операции

Операторы | и & можно применять не только к числам, но и к выражениям типа boolean.

Однако, как вы уже знаете, для логических выражений есть операторы && и ||. Что же нам даст использование | вместо || и использование & вместо &&? Есть ли вообще в этом смысл? Оказывается, есть. Иногда.

Логические операторы || и && выполняются слева направо по так называемому ленивому принципу.

(выражение1) || (выражение2) || (выражение3)

Если выражение1 равно true, нет смысла вычислять выражение2 и выражение3: результат все равно будет true.

Поэтому при вычислении выражений (а они вычисляются по порядку слева направо), как только мы получили true, вычисление остальных выражений пропускается. И если в выражениях выражение2 и выражение3 были вызовы каких-нибудь функций, то эти функции не вызываются!

То же самое и для логического оператора &&:

(выражение1) && (выражение2) && (выражение3)

Если выражение1 равно false, нет смысла вычислять выражение2 и выражение3: результат все равно будет false.

Это важный момент, который позволяет писать вещи вида:

String s = null;
if (s != null && s.length() > 0) {

В примере выше мы никогда не получим NullPointerException, т.к. выражение s.length() будет выполняться только если первая часть s != null равна true.

Если s окажется равно null, слева от оператора && будет значение false, и результат всего логического выражения будет false, поэтому вычисления второй части (s.length() > 0) не происходит.

Вот это все к чему:

Если в логическом выражении использовать оператор | или оператор &, то ленивого вычисления не происходит — в любом случае будут вычислены все выражения.



2. Приоритет операций в Java

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

Операторы в Java тоже имеют приоритет. Только: а) их несколько больше, б) у некоторых операторов действия выполняются слева направо, а у других — справа налево.

Вот как выглядит таблица со всеми операторами Java:

Категория Оператор Ассоциативность
Постфикс () [] . Слева направо
Унарный ++ -- ! ~ Справа налево
Мультипликативный * / % Слева направо
Аддитивный + - Слева направо
Сдвиг >> >>> << Слева направо
Реляционный > >= < <= Слева направо
Равенство == != Слева направо
Побитовое И (AND) & Слева направо
Исключающее ИЛИ (XOR) ^ Слева направо
Побитовое ИЛИ (OR) | Слева направо
Логическое И (AND) && Слева направо
Логическое ИЛИ (OR) || Слева направо
Условный ?: Справа налево
Присваивание = += -= *= /= %= >>= <<= &= ^= |= Справа налево
Запятая , Слева направо

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

Чем ниже операторы расположены в таблице, тем ниже их приоритет.

Если вы используете несколько операторов в вашем выражении, не ленитесь: ставьте скобки.

Да, в Java можно написать что-то типа if (a & 1<<b > ~c), но так делать не стоит. Вы пишете код не только для компилятора, но и для других программистов. Чем код читабельнее, тем лучше.



3. Префиксный и постфиксный инкремент

Как вы уже знаете, в Java есть оператор инкремента (++) и оператор декремента (--), которые увеличивают (и уменьшают) значение переменной на 1.

Чего вы скорее всего не знаете, так это того, что есть два вида этих операций: префиксные – оператор ставится до переменной, и постфиксные — оператор ставится после переменной. И работают эти операторы немного по-разному.

В Java можно написать такое выражение:

int a = 5;
int b = a++;

Если оператор ++ стоит после переменной и переменная участвует в каком-то выражении (как в примере выше), то в выражении будет использовано текущее значение переменной, а только потом она будет увеличена на 1.

Другими словами, произойдет примерно это:

int a = 5;
int b = a;
a = a + 1;

Т.е. b будет иметь значение 5, а не 6, как это могло показаться вначале.

Если же оператор ++ стоит до переменной и переменная участвует в каком-то выражении, она сначала будет увеличена на 1, а только затем ее значение будет участвовать в выражении.

int a = 5;
int b = ++a;

Пример выше эквивалентен следующему примеру:

int a = 5;
a = a + 1;
int b = a;

Вот тут уже значение b будет равно 6.

Есть даже один пример, который используется Java-программистами, чтобы определить, что их собеседник тоже Java-программист:

int a = 5;
int b = ++a++a;

Да, так тоже можно писать.

Этот пример отлично скомпилируется и превратится примерно в это:

int a = 5;

a = a + 1;
int v1 = a;

a = a + 1;
int v2 = a;

int b = v1 + v2;

Для оператора -- все точно то же самое.