为什么 Java 没有条件与和条件或运算符的复合赋值版本? (&&=,||=)
因此,对于布尔值的二元运算符,Java 有 &
、|
、^
、&&
和 <代码>||。
让我们在这里简要总结一下他们所做的事情:
对于
&
,如果两个操作数均为true
,则结果值为true
;否则,结果为false
。对于
|
,如果两个操作数均为false
,则结果值为false
;否则,结果为true
。对于
^
,如果操作数值不同,结果值为true
;否则,结果为false
。
&&
运算符类似于&
,但仅当其左侧操作数的值为true< 时才计算其右侧操作数/代码>.
||
运算符与|
类似,但仅当其左侧操作数的值为false
时才计算其右侧操作数>.
现在,在所有 5 个中,其中 3 个具有复合赋值版本,即 |=
、&=
和 ^=
。所以我的问题很明显:为什么 Java 不提供 &&=
和 ||=
呢?我发现我需要这些比我需要 &=
和 |=
更重要。
而且我不认为“因为太长”是一个很好的答案,因为Java有>>>=
。这种遗漏一定有更好的理由。
来自 15.26 赋值运算符:
有12个赋值运算符; [...]
= *= /= %= += -= <<= >>= >>>= &= ^= |=
评论是如果实现了 &&=
和 ||=
,那么它将是唯一不首先评估右侧的运算符。我认为复合赋值运算符首先评估右侧的概念是错误的。
来自15.26.2 复合赋值运算符 :
E1 op= E2
形式的复合赋值表达式相当于E1 = (T)((E1) op (E2))
,其中T
是E1
的类型,只不过E1
仅计算一次。
作为证明,以下代码片段抛出 NullPointerException
,而不是 ArrayIndexOutOfBoundsException
。
int[] a = null;
int[] b = {};
a[0] += b[-1];
So for binary operators on booleans, Java has &
, |
, ^
, &&
and ||
.
Let's summarize what they do briefly here:
- JLS 15.22.2 Boolean Logical Operators &, ^, and |
- JLS 15.23 Conditional-And Operator &&
- JLS 15.24 Conditional-Or Operator ||
For
&
, the result value istrue
if both operand values aretrue
; otherwise, the result isfalse
.For
|
, the result value isfalse
if both operand values arefalse
; otherwise, the result istrue
.For
^
, the result value istrue
if the operand values are different; otherwise, the result isfalse
.The
&&
operator is like&
but evaluates its right-hand operand only if the value of its left-hand operand istrue
.The
||
operator is like|
, but evaluates its right-hand operand only if the value of its left-hand operand isfalse
.
Now, among all 5, 3 of those have compound assignment versions, namely |=
, &=
and ^=
. So my question is obvious: why doesn't Java provide &&=
and ||=
as well? I find that I need those more than I need &=
and |=
.
And I don't think that "because it's too long" is a good answer, because Java has >>>=
. There must be a better reason for this omission.
From 15.26 Assignment Operators:
There are 12 assignment operators; [...]
= *= /= %= += -= <<= >>= >>>= &= ^= |=
A comment was made that if &&=
and ||=
were implemented, then it would be the only operators that do not evaluate the right hand side first. I believe this notion that a compound assignment operator evaluates the right hand side first is a mistake.
From 15.26.2 Compound Assignment Operators:
A compound assignment expression of the form
E1 op= E2
is equivalent toE1 = (T)((E1) op (E2))
, whereT
is the type ofE1
, except thatE1
is evaluated only once.
As proof, the following snippet throws a NullPointerException
, not an ArrayIndexOutOfBoundsException
.
int[] a = null;
int[] b = {};
a[0] += b[-1];
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
Java 最初的目标之一是“简单、对象”既熟悉又熟悉。”应用于本例时,&= 很熟悉(C、C++ 都有它,在这种情况下熟悉意味着了解这两个的人很熟悉)。
&&= 不会让人熟悉,也不会简单,因为语言设计者并不想考虑他们可以添加到语言中的每个运算符,因此额外的运算符越少就越简单。
One of Java's original aims was to be "Simple, Object Oriented, and Familiar." As applied to this case, &= is familiar (C, C++ have it and familiar in this context meant familiar to someone who knows those two).
&&= would not be familiar, and it would not be simple, in the sense that the language designers were not looking to think of every operator they could add to the language, so less extra operators are simpler.
Brian Goetz(Oracle Java 语言架构师)写道 :
Brian Goetz (Java Language Architect at Oracle) wrote:
对于布尔变量, &&和 ||将使用短路评估,而 &和|不这样做,所以您会期望 &&= 和 ||= 也使用短路评估。这有一个很好的用例。特别是当您在循环上进行迭代时,您希望快速、高效且简洁。
而是
我不想写,
想写并知道一旦 bVal 为 true,fn() 将不会在剩余的迭代中被调用。
For Boolean vars, && and || would use short circuit evaluation while & and | don't, so you would expect &&= and ||= to also use short circuit evaluation. There is a good use case for this. Especially if you are iterating over a loop, you want to be fast, efficient and terse.
Instead of writing
I want to write
and know that once bVal is true, fn() will not be called for the remainder of the iterations.
'
&
' 和 '&&
' 与 '&&
' 不同,它是一个快捷操作如果第一个操作数为 false 则不执行,而 '&
' 无论如何都会执行(适用于数字和布尔值)。我确实同意它的存在更有意义,但如果它不存在也没有那么糟糕。我猜它不在那里,因为 C 没有它。
实在想不出为什么。
'
&
' and '&&
' are not the same as '&&
' is a short cut operation which will not do if the first operand is false while '&
' will do it anyway (works with both number and boolean).I do agree that it make more sense to exist but it is not that bad if it is not there. I guess it was not there because C does not have it.
Really can't think of why.
有趣的是我遇到了这个问题。
运算符 ||= 和 &&= 不存在,因为它们的语义很容易被误解;
如果您认为需要它们,请改用 if 语句。
伊利(上面的帖子)的要点是正确的:
||
如果第一个操作数的计算结果为真,则停止计算,因为结果将为真,它是一个逻辑运算符。
所以想象一下如果 b == true 会发生什么;
b ||= somereturningaboolean(); //!!??
如果 b == true,则不会调用 somereturningaboolean()。
这种行为在长形式中更为明显:
b = b ||某物返回布尔值();
这就是为什么 ||= 和 &&= 操作不存在。解释应如下:
运算符 ||= 和 &&= 不存在,因为它们的语义很容易被误解;
如果您认为需要它们,请改用 if 语句。
Funny I came across this question.
The operators ||= and &&= do not exist as their semantics are easily misunderstood;
if you think you need them, use an if-statement instead.
Ely (post just above) got the gist right:
||
stops evaluating if the first operand evaluates to true since the result will be true, it's a logical operator.
So imagine what will happen if b == true;
b ||= somethingreturningaboolean(); // !!??
this will not invoke somethingreturningaboolean(), if b == true.
This behavior is more obvious in the long form:
b = b || somethingreturningaboolean();
That's why ||= and &&= ops do not exist. The explanation should be given as:
The operators ||= and &&= do not exist as their semantics are easily misunderstood;
if you think you need them, use an if-statement instead.
Ruby 中允许这样做。
如果我猜的话,我会说它不经常使用,所以没有实现。另一种解释可能是解析器只查看 = 之前的字符
It is allowed in Ruby.
If I were to guess, I would say that it is not frequently used so it wasn't implemented. Another explanation could be that the parser only looks at the character before the =
我想不出比“它看起来丑得令人难以置信!”更好的理由了。
I cannot think of any better reason then 'It looks incredible ugly!'
&
验证两个操作数,它是一个位运算符。 Java 定义了几个位运算符,可应用于整数类型:long、int、short、char 和 byte。
&&
如果第一个操作数的计算结果为 false,则停止计算,因为结果将为 false,它是一个逻辑运算符。它可以应用于布尔值。
&&运算符类似于&运算符,但可以使您的代码更加高效。由于运算符比较的两个表达式都必须为 true 才能使整个表达式为 true,因此如果第一个表达式返回 false,则没有理由计算第二个表达式。 &运算符始终对两个表达式求值。仅当第一个表达式为 true 时, & 运算符才会计算第二个表达式。
使用 &&= 赋值运算符并不会真正为该语言添加新功能。按位运算符的算术更具表现力,可以进行整数按位算术,其中包括布尔算术。逻辑运算符只能进行布尔算术。
&
verifies both operands, it's a bitwise operator. Java defines several bitwise operators, which can be applied to the integer types, long, int, short, char, and byte.
&&
stops evaluating if the first operand evaluates to false since the result will be false, it's a logical operator. It can be applied to booleans.
The && operator is similar to the & operator, but can make your code a bit more efficient. Because both expressions compared by the & operator must be true for the entire expression to be true, there’s no reason to evaluate the second expression if the first one returns false. The & operator always evaluates both expressions. The && operator evaluates the second expression only if the first expression is true.
Having a &&= assignment operator wouldn't really add new functionality to the language. The bitwise operator's arithmetic is much more expressive, you can do integer bitwise arithmetic, which includes Boolean arithmetic. The logical operators can merely do Boolean arithmetic.
原因
运算符
&&=
和||=
在 Java 上不可用,因为对于大多数开发人员来说,这些运算是:
&&=
的示例Java 允许
&&=
运算,那么该代码:将相当于:
第一个代码是 错误-容易,因为许多开发人员会认为无论 f1() 返回值如何,
f2()
总是被调用。就像 bool isOk = f1() && f2(); 其中,仅当f1()
返回true
时才会调用f2()
。如果开发人员希望仅当
f1()
返回true
时才调用f2()
,因此上面的第二个代码不太容易出错。Else
&=
就足够了,因为开发人员希望始终调用f2()
:相同的示例,但对于
&=
此外,JVM应按以下方式运行上述代码:
比较
&&
和&
结果是运算符
&&
和 的结果&
应用于布尔值时是否相同?让我们使用以下 Java 代码进行检查:
输出:
因此 YES 我们可以将
&&
替换为&
作为布尔值;-)所以最好使用
&=
而不是&&=
。||=
相同与
&&=
的原因相同:运算符
|=
比||=
更不容易出错。如果开发人员希望在
f1()
返回true
时不调用f2()
,那么我建议采用以下替代方案:或者:
Reason
The operators
&&=
and||=
are not available on Java because for most of the developers these operators are:Example for
&&=
If Java allowed
&&=
operator, then that code:would be equivalent to:
This first code is error-prone because many developers would think
f2()
is always called whatever the f1() returned value. It is likebool isOk = f1() && f2();
wheref2()
is called only whenf1()
returnstrue
.If the developer wants
f2()
to be called only whenf1()
returnstrue
, therefore the second code above is less error-prone.Else
&=
is sufficient because the developer wantsf2()
to be always called:Same example but for
&=
Moreover, the JVM should run this above code as the following one:
Compare
&&
and&
resultsAre the results of operators
&&
and&
the same when applied on boolean values?Let's check using the following Java code:
Output:
Therefore YES we can replace
&&
by&
for boolean values ;-)So better use
&=
instead of&&=
.Same for
||=
Same reasons as for
&&=
:operator
|=
is less error-prone than||=
.If a developer wants
f2()
not to be called whenf1()
returnstrue
, then I advice the following alternatives:or:
可能是因为像看起来这样的东西
应该分配给
x
并评估someComplexExpression()
,但事实上评估取决于值x
从语法上看不出来。另外,因为 Java 的语法是基于 C 的,所以没有人看到添加这些运算符的迫切需要。无论如何,使用 if 语句可能会更好。
Probably because something like
looks like it ought to be assigning to
x
and evaluatingsomeComplexExpression()
, but the fact that the evaluation hinges on the value ofx
isn't apparent from the syntax.Also because Java's syntax is based on C, and no one saw a pressing need to add those operators. You'd probably be better off with an if statement, anyway.
在Java中是这样,因为在C中是这样。
现在的问题是为什么在C中是这样,因为当&和&&成为不同的运算符(有时在 C 从 B 继承之前),&= 各种运算符被简单地忽略了。
但我的答案的第二部分没有任何来源来支持它。
It is this way in Java, because it is this way in C.
Now the question why it is so in C is because when & and && became different operators (sometime preceding C's descent from B), the &= variety of operators was simply overlooked.
But the second part of my answer does not have any sources to back it up.
主要是因为 Java 语法基于 C(或至少是 C 系列),并且在 C 中,所有这些赋值运算符都被编译为单个寄存器上的算术或按位汇编指令。赋值运算符版本避免了临时操作,并且可能在早期的非优化编译器上生成了更有效的代码。逻辑运算符(C 语言中的术语)等效项(
&&=
和||=
)与单个汇编指令没有如此明显的对应关系;它们通常扩展为测试和分支指令序列。有趣的是,像 ruby 这样的语言确实有 ||= 和 &&=。
编辑:Java 和 C 之间的术语不同
Largely because Java syntax is based on C (or at least the C family), and in C all those assignment operators get compiled to arithmetic or bitwise assembly instructions on a single register. The assignment-operator version avoids temporaries and may have produced more efficient code on early non-optimising compilers. The logical operator (as they are termed in C) equivalents (
&&=
and||=
) don't have such an obvious correspondence to single assembly instructions; they usually expand to a test and branch sequence of instructions.Interestingly, languages like ruby do have ||= and &&=.
Edit: terminology differs between Java and C