Когда Java оценивает соединение (&&), действительно ли оно равно exp2, если exp1 равно false? - PullRequest
3 голосов
/ 25 февраля 2012

Мне интересно, гарантируется ли, что в Java-программе логическое выражение справа от конъюнкции (exp2 выше) НЕ будет оцениваться, пока выражение слева (exp1) будет оценено как false.Мне интересно, потому что у меня есть выражение, подобное следующему:

if (var != null && var.somePredicate())
   // do something

Если Java не гарантирует прекращение оценки (var != null && var.somePredicate()) после того, как видит, что var равно нулю, то оно может попытаться оценить1006 *, которая выдаст исключение NullPointerException.

Итак, мой вопрос: гарантирует ли Java определенное поведение, когда дело доходит до этого?Или было бы безопаснее написать

if (var != null)
{
   if (var.somePredicate())
      // do something
}

Ответы [ 5 ]

6 голосов
/ 25 февраля 2012

Из спецификации языка Java, 15.23 Оператор условного и & & :

Оператор && похож на & (§15.22.2), но оценивает свой правый операнд, только если значение его левого операнда равно true .

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

4 голосов
/ 25 февраля 2012

Нет, Java использует Оценка короткого замыкания . Если expr1 равно false, expr2 не будет оцениваться, поэтому ваше использование && совершенно безопасно.

Кроме того, если у вас есть if (exp1 || exp2) { .. } - exp2 не будет оцениваться, если exp1 равно true.

2 голосов
/ 25 февраля 2012

Давайте выполним наш собственный эксперимент, посмотрев непосредственно на коды операций, сгенерированные из этого примера кода:

public class Compare {

        public static void main(String... args) {
          boolean t = true;
          boolean f = false;
          if(f && t) {
            System.out.println("Both true");
          }
          else {
            System.out.println("One false");
          }
        }

}

javap -v генерирует:

   0:   iconst_1
   1:   istore_1
   2:   iconst_0
   3:   istore_2
   4:   iload_2
   5:   ifeq    23
   8:   iload_1
   9:   ifeq    23
   12:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   15:  ldc #3; //String No
   17:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   20:  goto    31
   23:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   26:  ldc #5; //String Yes
   28:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   31:  return

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

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

1 голос
/ 25 февраля 2012

Если вы используете && или ||, java будет использовать оценку короткого замыкания (т.е. не оценивать второе выражение, если в этом нет необходимости)

Если вы используете & или |, java всегда будет оценивать второе выражениедаже если первое было правдой

0 голосов
/ 25 февраля 2012

Это безопасно, Java выполняет оценку короткого замыкания.

...