为什么Java没有条件和条件运算符的复合赋值版本? (&& =,|| =)
因此对于布尔值的二元运算符,Java有&
, |
, ^
, &&
和||
。
让我们简要总结一下他们在这里简要介绍的内容:
- JLS 15.22.2布尔逻辑运算符&,^和|
- JLS 15.23条件和运算符&&
- JLS 15.24条件运算符||
对于
&
,如果两个操作数值都为true
,则结果值为true
; 否则,结果是false
。对于
|
,如果两个操作数值都为false
,则结果值为false
; 否则,结果是true
。对于
^
,如果操作数值不同,则结果值为true
; 否则,结果是false
。
&&
运算符类似于&
但仅在其左侧操作数的值为true
时才计算其右侧操作数。
||
运算符就像|
,但仅在其左侧操作数的值为false
时才计算其右侧操作数。
现在,在所有5个中,有3个具有复合赋值版本,即|=
, &=
和^=
。 所以我的问题很明显:为什么Java不提供&&=
和||=
? 我发现我需要的不仅仅是我需要的那些&=
和|=
。
而且我不认为“因为它太长”是一个很好的答案,因为Java有>>>=
。 这种遗漏必须有更好的理由。
从15.26分配运营商 :
有12个赋值运算符; […]
= *= /= %= += -= <>= >>>= &= ^= |=
有人评论说,如果实施了&&=
和||=
,那么它将是唯一不首先评估右侧的运营商。 我相信复合赋值运算符首先评估右侧的这个概念是错误的。
从15.26.2复合赋值运算符 :
forms
E1 op= E2
的复合赋值表达式等效于E1 = (T)((E1) op (E2))
,其中T
是E1
的类型,除了E1
仅被评估一次。
作为certificate,以下代码段抛出NullPointerException
,而不是ArrayIndexOutOfBoundsException
。
int[] a = null; int[] b = {}; a[0] += b[-1];
原因
运算符&&=
和||=
在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();
其中只有当f1()
返回true
时才调用f2()
。
如果开发人员只想在f1()
返回true
时调用f2()
,那么上面的第二个代码不易出错。
Else &=
就足够了,因为开发人员希望始终调用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 ======================
因此,我们可以用&&
替换&&
作为布尔值;-)
所以最好使用&=
而不是&&=
。
对于||=
相同
与&&=
相同的原因:
operator |=
比||=
更不容易出错。
如果开发人员希望在f1()
返回true
时不调用f1()
,那么我建议以下备选方案:
// 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 ...
可能是因为像
x = false; x &&= someComplexExpression();
看起来它应该分配给x
并评估someComplexExpression()
,但是评估取决于x
的值这一事实在语法上并不明显。
另外因为Java的语法基于C语言,没有人看到迫切需要添加这些运算符。 无论如何,你可能会更好地使用if语句。
这是Java中的这种方式,因为它在C中就是这种方式。
现在问题为什么它在C中是这样的,因为当&和&&成为不同的运算符(在C从C下降之前的某个时间),&=各种运算符被忽略了。
但我的答案的第二部分没有任何来源支持它。
Java最初的目标之一是“简单,面向对象,熟悉”。 适用于这种情况,&=很熟悉(C,C ++拥有它并且在这种情况下熟悉,对于知道这两者的人来说是熟悉的)。
&& =不熟悉,并且它并不简单,因为语言设计者并不想要考虑他们可以添加到语言中的每个操作符,因此更少的额外操作符更简单。
主要是因为Java语法基于C(或至少是C系列),而在C中,所有这些赋值运算符都被编译为单个寄存器上的算术或按位汇编指令。 赋值运算符版本避免了临时性,并且可能在早期的非优化编译器上生成了更高效的代码。 逻辑运算符(因为它们在C中称为)等价物( &&=
和||=
)与单个汇编指令没有明显的对应关系; 它们通常扩展到测试和分支指令序列。
有趣的是,像ruby 这样的语言确实有|| =和&& =。
编辑:Java和C之间的术语不同
对于布尔变量,&&和|| 在&和|时会使用短路评估 不要,所以你会期望&& =和|| =也使用短路评估。 有一个很好的用例。 特别是如果你在循环中迭代,你想要快速,高效和简洁。
而不是写作
foreach(item in coll) { bVal = bVal || fn(item); // not so elegant }
我想写
foreach(item in coll) { bVal ||= fn(item); // elegant }
并且知道一旦bVal为真,就不会为剩余的迭代调用fn()。
‘ &
‘与’ &&
‘不同,’ &&
‘是一个快捷操作,如果第一个操作数为假,则不会执行,而’ &
‘无论如何都会执行(与数字和布尔值一起使用)。
我确实认为存在更有意义,但如果它不存在则不是那么糟糕。 我猜它不存在,因为C没有它。
真的想不出为什么。
它在Ruby中是允许的。
如果我猜测,我会说它不经常使用,所以它没有实现。 另一种解释可能是解析器只在=之前查看字符
a&b和&& b不是一回事。
a && b是一个返回布尔值的布尔表达式,而&b是一个返回int的按位表达式(如果a和b是整数)。
whare你认为他们是一样的吗?
我想不出更好的理由然后’看起来难看难看!’
&
validation两个操作数,它是一个按位运算符。 Java定义了几个按位运算符,可以应用于整数类型,long,int,short,char和byte。
&&
停止评估第一个操作数是否计算为false,因为结果将为false,它是一个逻辑运算符。 它可以应用于布尔值。
&&运算符类似于&运算符,但可以使您的代码更有效。 因为&运算符比较的两个表达式必须为true才能使整个表达式为true,所以如果第一个表达式返回false,则没有理由评估第二个表达式。 &运算符始终计算两个表达式。 仅当第一个表达式为true时,&&运算符才会计算第二个表达式。
拥有一个&& =赋值运算符不会真正为该语言添加新function。 按位运算符的算术更具表现力,可以进行整数位运算,包括布尔运算。 逻辑运算符只能执行布尔运算。