Укороченные логические операторы похожи на операторы & и |, но в отличие от них применяются только к выражениям типа boolean и никогда не применяются к интегральным типам. Тем не менее, && и || обладают замечательным свойством: они укорачивают вычисление выражения, если результат может быть дедуцирован из части выражения (чуть позже я поясню это на примерах). Благодаря этому свойству, операторы && и || широко используются для обработки null-выражений. Они также помогают увеличить эффективность всей программы.
Свойство укорачивания вытекает прямым образом из различий между &&/|| и &/|: последняя пара операторов должна получать на вход значения левого и правого операторов, в то время как для первой пары операторов иногда достаточно знать значение только левого операнда, чтобы вернуть значение всего выражения. Такое поведение укороченных логических операторов базируется на двух математических правилах логической таблицы истинности:
- выражение с AND оператором ложно (false), если значение хотя бы одного из его операндов ложно;
- выражение с OR оператором истинно (true), если значение хотя бы одного из его операндов истинно.
- false AND X = false
- true OR X = true
Рассмотрим пример кода, который выводит сообщение 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
2 комментария:
// первый пример
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);
Надо полагать, тут очепятка)
Исправлено. Спасибо за указание ошибки.
Отправить комментарий