为什么Java没有复合赋值版本的条件和条件或运算符? (&& =,|| =)
所以对于布尔型的二元运算符,Java有&
, |
, ^
, &&
和||
。
让我们总结一下他们在这里做的简要介绍:
- JLS 15.22.2布尔逻辑运算符&,^和|
- JLS 15.23有条件的和操作符&&
- JLS 15.24条件或运算符||
对于
&
,如果两个操作数值都为true
,则结果值为true
; 否则,结果是false
。为
|
,如果两个操作数的值均为false
,则结果值为false
; 否则,结果是true
。对于
^
,如果操作数值不同,结果值为true
; 否则,结果是false
。
&&
操作符就像&
但是只有当其左侧操作数的值为true
才会计算右侧的操作数。
||
运算符就像|
但是只有在其左手操作数的值为false
时才计算其右手操作数。
现在,其中有5个有复合赋值版本,即|=
, &=
和^=
。 所以我的问题很明显:为什么Java不提供&&=
和||=
呢? 我发现我需要比我需要的&=
和|=
。
我不认为“因为太长”是一个很好的答案,因为Java有>>>=
。 这个遗漏肯定有更好的理由。
从15.26分配操作员 :
有12个分配操作员; […]
= *= /= %= += -= <<= >>= >>>= &= ^= |=
有人评论说,如果&&=
和||=
被执行,那么它将是唯一不首先评估右边的操作符。 我相信这个概念,复合赋值运算符首先评估右边是一个错误。
从15.26.2起复合赋值运算符 :
E1 op= E2
的复合赋值expression式相当于E1 = (T)((E1) op (E2))
,其中T
是E1
的types,只是E1
只被计算一次。
作为certificate,下面的代码片段抛出一个NullPointerException
,而不是ArrayIndexOutOfBoundsException
。
int[] a = null; int[] b = {}; a[0] += b[-1];
可能是因为类似的东西
x = false; x &&= someComplexExpression();
看起来应该是分配给x
和评估someComplexExpression()
,但是评估取决于x
的值的事实在语法中是不明显的。
另外,因为Java的语法是基于C的,没有人看到迫切需要添加这些运算符。 无论如何,你可能会更好地使用if语句。
原因
运算符&&=
和||=
在Java上不可用,因为对于大多数开发人员来说,这些运算符是:
- 容易出错
- 无用
例如&&=
如果Java允许&&=
运算符,那么该代码:
bool isOk = true; //becomes false when at least a function returns false isOK &&= f1(); isOK &&= f2(); //we may expect f2() is called whatever the f1() returned value
将相当于:
bool isOk = true; if (isOK) isOk = f1(); if (isOK) isOk = f2(); //f2() is called only when f1() returns true
这第一个代码很容易出错,因为许多开发人员会认为无论f1()返回的值是什么, f2()
总是被调用。 这就像bool isOk = f1() && f2();
其中f2()
仅在f1()
返回true
时被调用。
如果开发人员只在f1()
返回true
时才要调用f2()
,那么上面的第二个代码不太容易出错。
否则&=
是足够的,因为开发人员总是要调用f2()
:
同样的例子,但&=
bool isOk = true; isOK &= f1(); isOK &= f2(); //f2() always called whatever the f1() returned value
而且,JVM应该运行这个代码如下:
bool isOk = true; if (!f1()) isOk = false; if (!f2()) isOk = false; //f2() always called
比较&&
和结果
运算符的结果是否和布尔值一样?
我们来看看使用下面的Java代码:
public class qalcdo { public static void main (String[] args) { test (true, true); test (true, false); test (false, false); test (false, true); } private static void test (boolean a, boolean b) { System.out.println (counter++ + ") a=" + a + " and b=" + b); System.out.println ("a && b = " + (a && b)); System.out.println ("a & b = " + (a & b)); System.out.println ("======================"); } private static int counter = 1; }
输出:
1) a=true and b=true a && b = true a & b = true ====================== 2) a=true and b=false a && b = false a & b = false ====================== 3) a=false and b=false a && b = false a & b = false ====================== 4) a=false and b=true a && b = false a & b = false ======================
因此, 是的,我们可以用&&
代替布尔值; &
所以最好使用&=
而不是&&=
。
同样的||=
与&&=
相同的原因:
运算符|=
比||=
更不容易出错。
如果开发人员希望f2()
在f1()
返回true
时不被调用,那么我build议以下方法:
// here a comment is required to explain that // f2() is not called when f1() returns false, and so on... bool isOk = f1() || f2() || f3() || f4();
要么:
// here the following comments are not required // (the code is enough understandable) bool isOk = false; if (!isOK) isOk = f1(); if (!isOK) isOk = f2(); //f2() is not called when f1() returns false if (!isOK) isOk = f3(); //f3() is not called when f1() or f2() return false if (!isOK) isOk = f4(); //f4() is not called when ...
这在Java中是这样的,因为它在C中是这样的
现在问题为什么在C中是这样的,因为当&和&&成为不同的运算符(在C从B运行之前的某个时刻),运算符的种类被忽略了。
但是我的答案的第二部分没有任何资料来支持。
Java的原始目标之一是“简单,面向对象和熟悉”。 应用于这种情况,&=熟悉(C,C ++拥有它,在这种情况下熟悉意味着熟悉知道这两者的人)。
&& =不会很熟悉,并不是那么简单,因为语言devise者并没有想到每个操作符都可以添加到语言中,所以更less的操作符就更简单了。
很大程度上是因为Java语法基于C(或者至less是C族),并且在C中,所有这些赋值运算符都被编译为单个寄存器上的算术或按位汇编指令。 赋值运算符版本避免了临时对象,并且可能在早期的非优化编译器上产生了更高效的代码。 逻辑运算符(因为它们被称为C)等价( &&=
和||=
)与单个汇编指令没有如此明显的对应关系; 他们通常扩展到testing和分支指令序列。
有趣的是,像ruby 这样的语言有|| =和&& =。
编辑:Java和C之间的术语不同
对于布尔variables,&&和|| 在&和|时使用短路评估 不要,所以你会期望&& =和|| =也使用短路评估。 这有一个很好的用例。 特别是如果你迭代循环,你想要快速,高效和简洁。
而不是写作
foreach(item in coll) { bVal = bVal || fn(item); // not so elegant }
我想写
foreach(item in coll) { bVal ||= fn(item); // elegant }
并知道一旦bVal为真,fn()将不会被调用其余的迭代。
' &
'和' &&
'与' &&
'不一样,' &&
'是一个快捷操作,如果第一个操作数是假的,而' &
'无论如何都会这样操作(不pipe是数字还是布尔值)。
我确实同意存在更合理,但如果不存在就没那么糟糕。 我想这不是因为C没有。
真的想不出为什么。
这是允许在Ruby中。
如果我猜测,我会说它不经常使用,所以没有实施。 另一种解释可能是parsing器仅查看=之前的字符
a&b和a&b不是一回事。
&& b是返回布尔值的布尔expression式,&b是返回int的按位expression式(如果a和b是整数)。
你认为他们是一样的吗?
我想不出有什么更好的理由,那看起来不可思议的丑陋!
&
validation两个操作数,这是一个按位运算符。 Java定义了几个按位运算符,它们可以应用于整数typeslong,int,short,char和byte。
&&
停止评估第一个操作数是否为false,因为结果是错误的,这是一个逻辑运算符。 它可以应用于布尔值。
&&运算符与&运算符类似,但可以使您的代码更有效一些。 因为用&运算符表示的这两个expression式必须是真的才能使整个expression式成立,所以如果第一个expression式返回false,那么没有理由计算第二个expression式。 &运算符总是评估这两个expression式。 仅当第一个expression式为真时,&&运算符才会评估第二个expression式。
拥有一个&& =赋值操作符不会真的为语言添加新的function。 按位运算符的算术更具performance力,可以进行整数位运算,其中包括布尔运算。 逻辑运算符只能做布尔运算。