& vs && - как можно использовать первый случай? - PullRequest
2 голосов
/ 19 октября 2011

(a> b) & (c b) оценивается первым.Если (a> b) ложно, все выражение ложно, независимо от результата компонента (r b) && (c b) оценивается как false.Это называется коротким замыканием.

Натолкнулся на этот абзац в книге по Java.Раньше я программировал на разных языках, но никогда не обнаруживал необходимости в '&'.Зачем нужно оценивать второе утверждение, если известно, что оно не влияет на конечный результат?Есть ли польза от этого;это происходит по историческим причинам?

Тот же вопрос относится к |и ||а также.

Ответы [ 8 ]

2 голосов
/ 19 октября 2011

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

2 голосов
/ 19 октября 2011

Оператор && определяется спецификацией языка Java для выполнения оценки короткого замыкания.

Однако оператор & не равен , даже если он применяется к логическим аргументам .

Вы могли бы использовать это, если один из аргументов имел побочные эффекты, которые вы не хотели бы замкнуть. Однако, по моему опыту, это необычно, и вы столкнетесь с риском того, что кто-то "исправит" это. Было бы лучше разделить на шаги. Например, вместо:

if ( foo() & bar() ) {... }

Вы могли бы сказать:

boolean isFoo = foo();
boolean isBar = bar();
if ( isFoo && isBar ) { ... }
1 голос
/ 19 октября 2011

Разница между '&' и '&&' не очень известна, и этот пример из книги мало чем помогает.

Вот еще один пример, показывающий, как работает короткое замыкание (используя ужасные методы, имеющие побочные эффекты, но это не главное).

Представьте, что у вас есть это:

private int cnt;

private boolean a() {
    cnt++;
    return false;
}

private boolean b() {
    cnt++;
    return false;
}

Если вы выполните следующее:

    cnt = 0;
    if ( a() && b() ) {}
    System.out.println( cnt );

Будет напечатано 1.

Пока вы выполняете следующее:

    cnt = 0;
    if ( a() & b() ) {}
    System.out.println( cnt );

Должно быть напечатано 2. Поскольку в последнем случае b () должен оцениваться в соответствии со спецификациями языка, тогда как в первом случае b () не должен оцениваться согласно спецификациям языка.

1 голос
/ 19 октября 2011

Вы можете использовать & в ситуациях, когда необходимо оценить оба подвыражения. Например, если они оба имеют побочные эффекты, наблюдаемые в остальной части вашего приложения.

1 голос
/ 19 октября 2011
if(0 != ((a > b) ? 1 : 0) & ((c < d) ? 1 : 0)) {
   // but really... (a > b) && (c < d), assuming no side-effects
}

... просто используйте логические операторы (&& и ||) для условий; -) Это то, для чего они были предназначены для, Если требуется не короткое замыкание, измените код соответствующим образом.

Мне кажется, я видел один случай, в котором в некотором смысле использовалось &, но я не помню, что это было, поэтому я не нашел его действительным ;-) В таких языках, как C / В C ++, где нет дискретного «логического» типа, (вход) и результат & могут быть обработаны так, что 0 -> false и non-0 -> true. Как можно видеть, однако, Java должен перепрыгнуть через некоторое удовольствие, чтобы получить bool -> int -> bool.

Единственное оправдание для побитового оператора это, ну, в общем, побитовые операции, IMOHO. Побитовые операторы наиболее полезны при выполнении какого-либо кодирования, включая «битовые поля» и «битовые маски». Они также полезны, когда имеешь дело с забавой, возникающей из байтов только для подписи Java и т. Д.

Я думаю, что большую (единственную?) Точку, которую нужно убрать, это то, что && и || имеют короткое замыкание - они на самом деле только операторы с таким поведением (аргументы более ?: исключены); остальное - просто объяснить нетерпеливое поведение побитовых операторов. Это только усиливает правило: не вызывает побочных эффектов в условных выражениях (за исключением нескольких общепринятых идиом, но даже в этом случае сделайте его простым).

Счастливого кодирования.


Примеры побитового использования:

Представьте себе использование флагов, которые хранятся в одном «целочисленном» слоте в сериализованном формате:

int flags = 0;
if (this.encypted) {
   flags |= EncryptedMode;
}
out.write(flags);

// later on
int flags = in.readInt();
this.encrypted = (flags & EncryptedMode) != 0;

Чтение "значения без знака" байта:

byte[] data = {-42, ...}; // read in from file or something
int unsignedByte = data[0] & 0xFF;
1 голос
/ 19 октября 2011

Возможно, 2-я оценка выполняется в форме оператора присваивания или вызова метода, и в этом случае вы можете захотеть выполнить его. Я бы не использовал побитовые операторы вместо логических операторов, подобных этому. Если вам нужно выполнить что-то, переданное &&, то сделайте это до логического выражения и сохраните результат в переменной.

0 голосов
/ 19 октября 2011

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

0 голосов
/ 19 октября 2011

Ваша книга сбивает с толку вещи. По большей части вы будете использовать только «&&» и «||». Одиночные операторы '&' и '|' являются побитовыми операторами - о них вы можете прочитать здесь: http://download.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

...