Что не так с логикой короткого замыкания в этом коде Java? - PullRequest
8 голосов
/ 12 мая 2009

Почему func3 не запускается в программе ниже? После func1 func2 не нужно оценивать, но для func3, не так ли?

if (func1() || func2() && func3()) {
        System.out.println("true");
    } else {
        System.out.println("false");
    }
}

public static boolean func1() {
    System.out.println("func1");
    return true;
}

public static boolean func2() {
    System.out.println("func2");
    return false;
}

public static boolean func3() {
    System.out.println("func3");
    return false;
}

Ответы [ 9 ]

25 голосов
/ 12 мая 2009

Вы используете короткое замыкание или. Если первый аргумент верен, то все выражение истинно.

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

Редактировать : Как отметил Крис Джестер-Янг, это на самом деле потому, что логические операторы должны иметь ассоциативность слева направо:

if (func1() || (func2() && func3()))

После того, как func1 возвращается, он становится таким:

if (true || (func2() && func3()))

После оценки короткого замыкания или становится:

if (true)
6 голосов
/ 12 мая 2009

Java-функции оцениваются согласно правилам приоритета

, поскольку "&&" имеет более высокий приоритет, чем "||", он вычисляется первым, потому что у вас не было скобок для установки явного приоритета

так что вы выражение

(A || B && C) 

что составляет

(T || F && F)

заключен в скобки как

(T || (F && F)) 

из-за правил приоритета.

Поскольку компилятор понимает, что если 'A == true', ему не нужно беспокоиться об оценке остальной части выражения, он останавливается после вычисления A.

Если бы вы заключили в скобки ((A || B) && C), тогда оно получило бы значение false.

РЕДАКТИРОВАТЬ

Другой способ, как упоминалось в других постерах, - использовать "|" и "&" вместо "||" и "&&", потому что это останавливает выражение от ярлыка. Однако из-за правил приоритета конечный результат останется прежним.

3 голосов
/ 12 мая 2009

Булевы выражения Java. Это означает, что после выполнения func1() и возврата true остальная часть этого логического значения не имеет значения, поскольку вы используете оператор or. Независимо от того, что func2() && func3() оценивает, все выражение будет оцениваться до true. Таким образом, Java даже не удосуживается оценить func2() или func3().

2 голосов
/ 12 мая 2009

Вы используете операторы ярлыков || а также &&. Эти операторы не выполняют остальную часть выражения, если результат уже определен. Для || это означает, что первое выражение истинно, а & & если первое выражение ложно.

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

2 голосов
/ 12 мая 2009

Java использует отложенную оценку.

Поскольку Func1 всегда возвращает true, все выражение ДОЛЖНО быть истинным, поэтому оно сокращает остальную часть выражения.

true || (???)

и

false && (???)

всегда будет ярлыком.

Чтобы отключить ярлык оценки, используйте | и & вместо || и &&

Мы можем использовать это для хорошего эффекта:

String s;
if (s != null && !s.equals("")) ...

Это означает, что если s равно null, нам даже не придется пытаться вызвать s.equals, и мы не будем выдавать исключение NullPointerException

2 голосов
/ 12 мая 2009
1 голос
/ 12 мая 2009

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

1 голос
/ 12 мая 2009

краткий ответ: оценка короткого замыкания

, поскольку func1 () возвращает true, нет необходимости продолжать оценку, поскольку это всегда true

0 голосов
/ 12 мая 2009

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

if (func1() | func2() & func3()) {
...