&& и || и их братья & и | в разных ситуациях. Какие у них различия?

144
25 февраля 2019, 06:10

друзья! Хотелось бы спросить про && и ||. Если используется двойной амперсанд и первое выражение ложно (false), то второе выражение даже не будет проверяться, т.к. вне зависимости от него,всё выражение будет ложным. При одном амперсанде будут вычислены оба условия.

Всё понятно, но есть ли смысл иметь в ЯП двойной амперсанд? Посмотрел, поиспользовал,честно не понял зачем их 2 придумали. Все мои результаты как только не делал вышли одинаковыми.

 public static void main(String[] args) {
        int a = 2;
        int b = 3;
        int c = 4;
        if (a == 2 && b == 3){
            System.out.println("Hello");
        }else{
            System.err.println("Error");
        }
}

Да я понимаю, что с && он проверяет первое значение и если оно false, то дальше даже не проверяет, тогда вопрос: Нужен ли в таком случае &(одинарный амперсанд)? Распишите примеры пожалуйста, где идут отличия & от && и где они могут по разному работать, потому что я увидел только одинаковую работу.

Answer 1

Смотрите: допустим, у вас такая проверка: checkFirst() && checkSecond().

boolean метод checkSecond():

...
System.out.println("Метод checkSecond был вызван т.к. метод checkFirst вернул true");
...

И эта надпись может выводиться в консоль, а может и не выводиться. А если бы вы указали &, то она бы выводилась всегда, даже если бы checkFirst возвращал false. Т.е. иногда надо, чтобы проверялись оба условия, независимо от того, повлияет ли это на что-нибудь. А && было придумано для улучшения производительности, мало ли какие громоздкие проверки у вас стоят - чтобы они не выполнялись лишний раз.

P.S. Andrey NOP написал в комментариях к вопросу про побочные эффекты, println выше - это как раз побочный эффект. Вместо println может быть присваивание какого-то значения важному полю, и т.п.

UPD:

public static void main(String[] args) {
    //тут вызовутся оба метода, т.к. checkFirst возвр. true, потом вызовется checkSecond, он тоже true, условие выполнится
    if (checkFirst(0) && checkSecond(0))
        System.out.println("Первое условие выполнено\n");
    //тут вызовется только checkFirst, т.к. checkFirst возвр. false, и уже не надо проверять checkSecond, т.к. условие ложное, оно не выполнится
    if (checkFirst(1) && checkSecond(0))
        System.out.println("Второе условие выполнено\n");
    //здесь вызовутся оба метода, т.к. это "&", и оба вернут true, условие выполнится
    if (checkFirst(0) & checkSecond(0)) 
        System.out.println("Третье условие выполнено\n");
    //здесь вызовутся оба метода, условие не выполнится, т.к. checkSecond возвр. false
    if (checkFirst(0) & checkSecond(1)) 
        System.out.println("Четвертое условие выполнено\n");
}
private static boolean checkFirst(int i) {
    System.out.println("Вызван checkFirst");
    if (i == 0)
        return true;
    return false;
}
private static boolean checkSecond(int i) {
    System.out.println("Вызван checkSecond");
    if (i == 0)
        return true;
    return false;
}

Вывод:

Вызван checkFirst
Вызван checkSecond
Первое условие выполнено
Вызван checkFirst
Вызван checkFirst
Вызван checkSecond
Третье условие выполнено
Вызван checkFirst
Вызван checkSecond
Answer 2

Простейший пример. Допустим, есть массив размером 10:

if(i < 10 && a[i] == 0) { ... }
if(i < 10 & a[i] == 0) { ... }

При i >= 10 во втором случае (&) при проверке условия будет попытка обращения к элементу за границами массива, в первом случае (&&) все отработает корректно (правая часть условия не будет проверяться, т.к. левая часть условия ложная).

Answer 3

В некоторых случаях требуется вычислять оба операнда логического опера­тора, чтобы проявились побочные эффекты:

    class SideEffects {
    public static void main(String args[]) {
    int i = 0;
    /*Значение переменной i инкрементируется, несмотря на то что проверяемое условие в операторе if ложно */
    if(false & (++i < 100)) System.out.println("Эта строка не будет отображаться");
    System.out.println("Оператор if выполняется: " + i); // отображается 1
    /* В данном случае значение переменной i не инкрементируется, т.к. второй операнд укороченного логического оператора не вычисляется,а значит, инкремент пропускается */
    if(false && (++i < 100)) System.out.println("Эта строка не будет отображаться");
    System.out.println("Оператор if выполняется: " + i); //по-прежнему отображается 1 !!
    }
}

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

Источник: Герберт Шилдт. Java 8.Руководство для начинающих, с.78

READ ALSO
Поворачивать маркер в mapsforge

Поворачивать маркер в mapsforge

У меня есть направление движения и точки трека

129
Google Maps перемещение к объекту из списка

Google Maps перемещение к объекту из списка

Есть приложение с использованием Google MapsИ в нем есть список озер

133
Как сделать чтобы во время тестов кастомный валидатор автовайрил репоизторий?

Как сделать чтобы во время тестов кастомный валидатор автовайрил репоизторий?

Использую валидатор для проверки уникальности номераВ валидаторе автовайрю репозиторий для поиска по БД

156
Редактирование степени числа

Редактирование степени числа

Как замечательно что есть такой форум на котором можно задавать вопросыПотому что голову уже сломал

134