Почему мы обычно используем `||`, а не `|`, в чем разница?
Мне просто интересно, почему мы обычно используем логическое ИЛИ ||
между двумя логическими значениями не поразрядно ИЛИ |
Хотя они оба работают хорошо.
Я имею в виду, посмотрите на следующее:
if(true | true) // pass
if(true | false) // pass
if(false | true) // pass
if(false | false) // no pass
if(true || true) // pass
if(true || false) // pass
if(false || true) // pass
if(false || false) // no pass
Можем ли мы использовать |
вместо ||
? То же самое с &
а также &&
,
27 ответов
Если вы используете ||
а также &&
формы, а не |
а также &
В формах этих операторов Java не потрудится оценить только правый операнд.
Это вопрос, хотите ли вы замкнуть оценку или нет - большую часть времени вы хотите.
Хороший способ проиллюстрировать преимущества короткого замыкания - рассмотреть следующий пример.
Boolean b = true;
if(b || foo.timeConsumingCall())
{
//we entered without calling timeConsumingCall()
}
Как отмечали Джереми и Питер, еще одно преимущество для короткого замыкания - проверка нулевой ссылки:
if(string != null && string.isEmpty())
{
//we check for string being null before calling isEmpty()
}
|
не выполняет оценку короткого замыкания в логических выражениях. ||
прекратит оценку, если первый операнд истинен, но |
не будет.
К тому же, |
может использоваться для выполнения операции побитового ИЛИ со значениями байтов / коротких / целых / длинных. ||
не могу.
Так что просто для того, чтобы использовать другие ответы на примере, короткое замыкание имеет решающее значение в следующих защитных проверках:
if (foo == null || foo.isClosed()) {
return;
}
if (bar != null && bar.isBlue()) {
foo.doSomething();
}
С помощью |
а также &
вместо этого может привести к NullPointerException
быть брошенным здесь.
Логический ||
а также &&
проверяйте правую сторону только при необходимости. |
а также &
проверяйте оба все время.
Например:
int i = 12;
if (i == 10 & i < 9) // It will check if i == 10 and if i < 9
...
Перепишите это:
int i = 12;
if (i == 10 && i < 9) // It will check if i == 10 and stop checking afterward because i doesn't = 10
...
Другой пример:
int i = 12;
if (i == 12 | i > 10) // It will check if i == 12 and it will check if i > 10
...
Перепишите это:
int i = 12;
if (i == 12 || i > 10) // It will check if i == 12, it does, so it stops checking and executes what is in the if statement
...
Также обратите внимание на распространенную ловушку: операторы без ленивства имеют приоритет над ленивыми, поэтому:
boolean a, b, c;
a || b && c; //resolves to a || (b && c)
a | b && c; //resolves to (a | b) && c
Будьте осторожны при их смешивании.
В дополнение к короткому замыканию следует помнить, что выполнение побитовой логической операции со значениями, которые могут быть отличны от 0 или 1, имеет совершенно иной смысл, чем условная логика. Хотя это, как правило, то же самое для |
а также ||
, с &
а также &&
вы получаете очень разные результаты (например, 2 & 4
0/ ложное время 2 && 4
1/ правда).
Если то, что вы получаете от функции, на самом деле является кодом ошибки, и вы проверяете не ноль, это может иметь большое значение.
Это не такая большая проблема в Java, где вам приходится явно указывать тип на булево или сравнивать с 0 и т.п., но в других языках с похожим синтаксисом (C/C++ и др.) Это может быть довольно запутанным.
Также обратите внимание, что & и | может применяться только к значениям целочисленного типа, а не ко всему, что может быть эквивалентно булевому тесту. Опять же, в не-Java языках есть довольно много вещей, которые можно использовать как логическое с неявным != 0
сравнение (указатели, поплавки, объекты с operator bool()
и т. д.) и побитовые операторы почти всегда бессмысленны в этих контекстах.
Единственный раз, когда вы будете использовать |
или же &
вместо ||
или же &&
это когда у вас очень простые логические выражения, а стоимость короткой обрезки (то есть ветки) больше, чем время, которое вы экономите, не оценивая более поздние выражения.
Однако это микрооптимизация, которая редко имеет значение, за исключением кода самого низкого уровня.
А | б: оценить б в любом случае
|| b: оценивать b, только если a оценивается как ложное
|| является логическим или оператором в то время как | является побитовым или оператором.
boolean a = true;
boolean b = false;
if (a || b) {
}
int a = 0x0001;
a = a | 0x0002;
Помимо того, что | является побитовым оператором: || является оператором короткого замыкания - когда один элемент ложный, он не будет проверять другие.
if(something || someotherthing)
if(something | someotherthing)
если что-то ИСТИННО, || не буду ничего оценивать, пока | Сделаю. Если переменные в ваших операторах if на самом деле являются вызовами функций, используйте || возможно, сохранит много производительности.
Операторы ||
а также &&
называются условными операторами, в то время как |
а также &
называются побитовыми операторами. Они служат разным целям.
Условные операторы работают только с выражениями, которые статически оцениваются как boolean
с левой и правой стороны.
Битовые операторы работают с любыми числовыми операндами.
Если вы хотите выполнить логическое сравнение, вы должны использовать условные операторы, так как вы добавите некоторый тип безопасности типов в свой код.
Примечание: у Java есть |=, но нет ||=
Пример того, когда вы должны использовать || это когда первое выражение является тестом, чтобы увидеть, взорвется ли второе выражение. Например, используя один | в следующем случае может привести к NPE.
public static boolean isNotSet(String text) {
return text == null || text.length() == 0;
}
Другие ответы хорошо справились с функциональной разницей между операторами, но ответы могут относиться практически ко всем существующим на сегодняшний день C-производным языкам. Вопрос помечен Java, поэтому я постараюсь ответить специально и технически для языка Java.
&
а также |
могут быть либо целочисленными побитовыми операторами, либо логическими логическими операторами. Синтаксис для побитовых и логических операторов ( §15.22):
AndExpression:
EqualityExpression
AndExpression & EqualityExpression
ExclusiveOrExpression:
AndExpression
ExclusiveOrExpression ^ AndExpression
InclusiveOrExpression:
ExclusiveOrExpression
InclusiveOrExpression | ExclusiveOrExpression
Синтаксис для EqualityExpression
определено в §15.21, который требует RelationalExpression
определенный в §15.20, который в свою очередь требует ShiftExpression
а также ReferenceType
определены в §15.19 и §4.3 соответственно. ShiftExpression
требует AdditiveExpression
определенный в §15.18, который продолжает детализацию, определяя основную арифметику, унарные операторы и т. д. ReferenceType
детализирует все различные способы представления типа. (В то время как ReferenceType
не включает в себя примитивные типы, определение примитивных типов в конечном счете требуется, так как они могут быть типом измерения для массива, который является ReferenceType
.)
Битовые и логические операторы имеют следующие свойства:
- Эти операторы имеют разный приоритет, с
&
имеющий наивысший приоритет и|
самый низкий приоритет- Каждый из этих операторов синтаксически левоассоциативен (каждая группа слева направо).
- Каждый оператор является коммутативным, если выражения операндов не имеют побочных эффектов.
- Каждый оператор ассоциативный.
- Побитовые и логические операторы могут использоваться для сравнения двух операндов числового типа или двух операндов типа
boolean
, Все остальные случаи приводят к ошибке времени компиляции.
Различие между тем, служит ли оператор как побитовый оператор или логическим оператором, зависит от того, являются ли операнды "конвертируемыми в примитивный целочисленный тип" ( §4.2) или они имеют типы boolean
или же Boolean
( §5.1.8).
Если операнды являются целочисленными типами, двоичное числовое продвижение ( §5.6.2) выполняется для обоих операндов, оставляя оба обоих как long
с или int
с для операции. Тип операции будет типом (повышенных) операндов. В таком случае, &
будет побитовым И, ^
будет побитовым эксклюзивным ИЛИ, и |
будет поразрядно включенным ИЛИ. ( §15.22.1)
Если операнды boolean
или же Boolean
, операнды будут подвергнуты преобразованию распаковки в случае необходимости ( §5.1.8), и тип операции будет boolean
, &
приведет к true
если оба операнда true
, ^
приведет к true
если оба операнда различны, и |
приведет к true
если любой из операндов true
, ( §15.22.2)
По сравнению, &&
является "условно-оператором" ( §15.23) и ||
является "условно-или оператором" ( §15.24). Их синтаксис определяется как:
ConditionalAndExpression:
InclusiveOrExpression
ConditionalAndExpression && InclusiveOrExpression
ConditionalOrExpression:
ConditionalAndExpression
ConditionalOrExpression || ConditionalAndExpression
&&
как &
за исключением того, что он оценивает правый операнд, только если левый операнд true
, ||
как |
за исключением того, что он оценивает правый операнд, только если левый операнд false
,
Условно-А обладает следующими свойствами:
- Оператор условного оператора and синтаксически является левоассоциативным (он группируется слева направо).
- Условный оператор-and полностью ассоциативен в отношении как побочных эффектов, так и значения результата. То есть для любых выражений
a
,b
, а такжеc
, оценка выражения((a) && (b)) && (c)
дает тот же результат, с теми же побочными эффектами, происходящими в том же порядке, что и при оценке выражения(a) && ((b) && (c))
,- Каждый операнд условного оператора and должен иметь тип
boolean
или жеBoolean
или произошла ошибка во время компиляции.- Тип условного выражения и выражения всегда
boolean
,- Во время выполнения выражение левого операнда вычисляется первым; если результат имеет тип
Boolean
, он подвергается распаковке преобразования ( §5.1.8).- Если полученное значение
false
, значение условного выражения иfalse
и выражение правого операнда не оценивается.- Если значение левого операнда
true
затем вычисляется правое выражение; если результат имеет типBoolean
, он подвергается распаковке преобразования ( §5.1.8). Полученное значение становится значением условного выражения и выражения.- Таким образом,
&&
вычисляет тот же результат, что и&
наboolean
операнды. Он отличается только тем, что выражение правого операнда вычисляется условно, а не всегда.
Условно-Или имеет следующие свойства:
- Условный оператор или синтаксически является левоассоциативным (он группируется слева направо).
- Условный оператор или полностью ассоциативен в отношении как побочных эффектов, так и значения результата. То есть для любых выражений
a
,b
, а такжеc
, оценка выражения((a) || (b)) || (c)
дает тот же результат, с теми же побочными эффектами, происходящими в том же порядке, что и при оценке выражения(a) || ((b) || (c))
,- Каждый операнд условного оператора или оператора должен иметь тип
boolean
или жеBoolean
или произошла ошибка во время компиляции.- Тип условного выражения или выражения всегда
boolean
,- Во время выполнения выражение левого операнда вычисляется первым; если результат имеет тип
Boolean
, он подвергается распаковке преобразования ( §5.1.8).- Если полученное значение
true
, значение условного выражения илиtrue
и выражение правого операнда не оценивается.- Если значение левого операнда
false
затем вычисляется правое выражение; если результат имеет типBoolean
, он подвергается распаковке преобразования ( §5.1.8). Результирующее значение становится значением условного выражения или выражения.- Таким образом,
||
вычисляет тот же результат, что и|
наboolean
или жеBoolean
операнды. Он отличается только тем, что выражение правого операнда вычисляется условно, а не всегда.
Короче говоря, как @JohnMeagher неоднократно указывал в комментариях, &
а также |
на самом деле, это недолговечные логические операторы в конкретном случае, когда boolean
или же Boolean
, С хорошими практиками (то есть: никакие вторичные эффекты), это незначительная разница. Когда операнды не boolean
с или Boolean
Однако операторы ведут себя совершенно по- разному: побитовые и логические операции просто плохо сравниваются на высоком уровне программирования Java.
1).(Выражение1 | выражение2), | Оператор будет оценивать expression2 независимо от того, является ли результат expression1 истинным или ложным.
Пример:
class Or
{
public static void main(String[] args)
{
boolean b=true;
if (b | test());
}
static boolean test()
{
System.out.println("No short circuit!");
return false;
}
}
2). (Выражение1 || выражение2), || Оператор не будет оценивать expression2, если expression1 имеет значение true.
Пример:
class Or
{
public static void main(String[] args)
{
boolean b=true;
if (b || test())
{
System.out.println("short circuit!");
}
}
static boolean test()
{
System.out.println("No short circuit!");
return false;
}
}
|| возвращает логическое значение, используя два значения ИЛИ (поэтому его называют ЛОГИЧЕСКИМ или)
IE:
if (A || B)
Вернет true, если A или B - true, или false, если они оба false.
| является оператором, который выполняет побитовую операцию над двумя значениями. Чтобы лучше понять побитовые операции, вы можете прочитать здесь:
Не короткое замыкание может быть полезным. Иногда вы хотите убедиться, что два выражения оценивают. Например, скажем, у вас есть метод, который удаляет объект из двух отдельных списков. Возможно, вы захотите сделать что-то вроде этого:
class foo {
ArrayList<Bar> list1 = new ArrayList<Bar>();
ArrayList<Bar> list2 = new ArrayList<Bar>();
//Returns true if bar is removed from both lists, otherwise false.
boolean removeBar(Bar bar) {
return (list1.remove(bar) & list2.remove(bar));
}
}
Если ваш метод вместо этого использовал условный операнд, он не сможет удалить объект из второго списка, если первый список вернул false.
//Fails to execute the second remove if the first returns false.
boolean removeBar(Bar bar) {
return (list1.remove(bar) && list2.remove(bar));
}
Это не удивительно полезно, и (как и в большинстве задач программирования) вы можете достичь этого другими способами. Но это случай использования побитовых операндов.
Основное различие между ними заключается в том, что | сначала преобразует значения в двоичные, затем выполняет битовую обработку или операцию. Между тем, || не преобразует данные в двоичный файл, а просто выполняет выражение или в исходном состоянии.
int two = -2; int four = -4;
result = two | four; // bitwise OR example
System.out.println(Integer.toBinaryString(two));
System.out.println(Integer.toBinaryString(four));
System.out.println(Integer.toBinaryString(result));
Output:
11111111111111111111111111111110
11111111111111111111111111111100
11111111111111111111111111111110
Читать подробнее: http://javarevisited.blogspot.com/2015/01/difference-between-bitwsie-and-logical.html
Одно главное отличие заключается в том, что || и && демонстрируют "короткое замыкание", поэтому RHS будет оцениваться только при необходимости.
Например,
if (a || b) {
path1...
} else {
path2..
}
Выше, если a равно true, b не будет проверяться, и path1 выполняется. Если | Тогда обе стороны будут оценены, даже если "а" истинно.
Смотрите здесь и здесь, для получения дополнительной информации.
Надеюсь это поможет.
Когда у меня возник этот вопрос, я создал тестовый код, чтобы получить представление об этом.
public class HelloWorld{
public static boolean bool(){
System.out.println("Bool");
return true;
}
public static void main(String []args){
boolean a = true;
boolean b = false;
if(a||bool())
{
System.out.println("If condition executed");
}
else{
System.out.println("Else condition executed");
}
}
}
В этом случае мы меняем только левое значение условия if, добавляя a или b.
||
Сценарий, когда левая сторона истинна [if(a||bool())]
выход "If condition executed"
||
Сценарий, когда левая сторона ложна [if(b||bool())]
Выход-
Bool
If condition executed
Conclusion of ||
При использовании ||
Правая сторона проверяет только когда левая сторона ложна.
|
Сценарий, когда левая сторона истинна [if(a|bool())]
Выход-
Bool
If condition executed
|
Сценарий, когда левая сторона ложна [if(b|bool())]
Выход-
Bool
If condition executed
Conclusion of |
При использовании |
проверьте как левую, так и правую сторону.
После внимательного прочтения этой темы мне все еще непонятно, использую ли |
как логический оператор соответствует практике шаблонов Java.
Недавно я изменил код в запросе на вытягивание, обращаясь к комментарию, где
if(function1() | function2()){
...
}
пришлось изменить на
boolean isChanged = function1();
isChanged |= function2();
if (isChanged){
...
}
Какая на самом деле принятая версия?
Документация Java не упоминает
|
как логический оператор ИЛИ без короткого замыкания.
Не заинтересованы в голосовании, а больше в выяснении стандарта?! Обе версии кода компилируются и работают должным образом.
Обычно я использую, когда есть прединкрементный и постинкрементный оператор. Посмотрите на следующий код:
package ocjpPractice;
/**
* @author tithik
*
*/
public class Ex1 {
public static void main(String[] args) {
int i=10;
int j=9;
int x=10;
int y=9;
if(i==10 | ++i>j){
System.out.println("it will print in first if");
System.out.println("i is: "+i);
}
if(x==10 ||++x>y){
System.out.println("it will print in second if");
System.out.println("x is: "+x);
}
}
}
выход:
он будет печататься первым, если
я есть: 11
он напечатает в секунду, если
х это: 10
и то и другое if
блоки одинаковы, но результат другой. когда есть |
оба условия будут оценены. Но если это ||
, оно не будет оценивать второе условие, поскольку первое условие уже выполнено.
Есть много вариантов использования, предлагающих, почему вы должны пойти на ||
скорее, чем |
, Некоторые случаи использования должны использовать |
Оператор, чтобы проверить все условия.
Например, если вы хотите проверить проверку формы и хотите показать пользователю все недопустимые поля с текстами ошибок, а не только первое недопустимое поле.
||
оператор будет,
if(checkIfEmpty(nameField) || checkIfEmpty(phoneField) || checkIfEmpty(emailField)) {
// invalid form with one or more empty fields
}
private boolean checkIfEmpty(Widget field) {
if(field.isEmpty()) {
field.setErrorMessage("Should not be empty!");
return true;
}
return false;
}
Так с приведенным выше фрагментом, если пользователь отправляет форму со ВСЕМИ пустыми полями, ТОЛЬКО nameField
будет показано с сообщением об ошибке. Но если вы измените его на
if(checkIfEmpty(nameField) | checkIfEmpty(phoneField) | checkIfEmpty(emailField)) {
// invalid form with one or more empty fields
}
Он покажет правильное сообщение об ошибке в каждом поле, независимо от true
условия.
Взгляни на:
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/operators.html
| поразрядно включается ИЛИ
|| логично ИЛИ
| является побитовым оператором. || логический оператор
Один займет два бита и / или их.
Кто-то определит истину (это ИЛИ это). Если это правда или это правда, тогда ответ верен.
Ох, и черт побери, люди быстро отвечают на эти вопросы.