为什么Java没有条件和条件或运算符的复合赋值版本?(&& =,|| =)

pol*_*nts 77 java conditional-operator short-circuiting assignment-operator compound-assignment

因此,对于在布尔二元运算符,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)),where T的类型.E1E1

作为证据,以下片段引发了一个NullPointerException,而不是一个ArrayIndexOutOfBoundsException.

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];
Run Code Online (Sandbox Code Playgroud)

oli*_*bre 25

原因

运营商&&=||=不提供的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
Run Code Online (Sandbox Code Playgroud)

相当于:

bool isOk = true;
if (isOK) isOk = f1();
if (isOK) isOk = f2(); //f2() is called only when f1() returns true
Run Code Online (Sandbox Code Playgroud)

第一个代码容易出错,因为许多开发人员都认为f2()无论f1()返回值是什么都会被调用.这就像bool isOk = f1() && f2();在那里f2()被称为只有当f1()收益true.

如果开发人员只想f2()f1()返回时调用true,那么上面的第二个代码不容易出错.

否则&=就足够了,因为开发人员f2()总是希望被称为:

同样的例子,但是 &=

bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value
Run Code Online (Sandbox Code Playgroud)

此外,JVM应该运行以上代码,如下所示:

bool isOk = true;
if (!f1())  isOk = false;
if (!f2())  isOk = false;  //f2() always called
Run Code Online (Sandbox Code Playgroud)

比较&&&结果

是运营商的结果&&,并&同当布尔值应用?

让我们使用以下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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
======================
Run Code Online (Sandbox Code Playgroud)

因此我们可以更换&&&布尔值;-)

所以更好地使用&=而不是&&=.

同样的 ||=

原因相同&&=:
运算符|=比错误更少||=.

如果开发人员想要f2()f1()返回时不被调用true,那么我建议以下备选方案:

// 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();
Run Code Online (Sandbox Code Playgroud)

要么:

// 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 ...
Run Code Online (Sandbox Code Playgroud)

  • 当你说"这不是我们想要的东西时",我不同意.如果我写`isOK && = f2();`我希望它像`&&`那样短路. (10认同)
  • 我不同意您声称操作员容易出错或无用的说法.使用复合赋值是为了获取通常的"A = A op B"的快捷方式,所以每个人都完全知道他们在做什么,并且可以自己关心其含义.如果你的理由确实是缺席的原因,我会认为这是不必要的光顾.但是,我想感谢你添加一行`bool isOk = f1()|| f2()|| f3()|| f4();`因为那是我盲目地看待自己的原因. (3认同)
  • 如果我想这么快就这样做怎么办?&& =会比&=更快,如果它存在,所以你应该使用`if(a)a = b`来获得速度 (2认同)

Jos*_*Lee 16

可能是因为像

x = false;
x &&= someComplexExpression();
Run Code Online (Sandbox Code Playgroud)

看起来它应该分配x和评估someComplexExpression(),但评估取决于价值的事实x在语法上并不明显.

另外因为Java的语法基于C语言,没有人看到迫切需要添加这些运算符.无论如何,你可能会更好地使用if语句.

  • 我认为这不是一个好的答案,因为人们可以争辩说`x()&& y()`*看起来像它应该评估表达式的两面.很明显人们都认为`&&`是短路的,所以也应该遵循`&& =`. (34认同)
  • @jleedev,同意.我相信在这些情况下,重要的是要记住,这不等于x = x && someComplexExpression(),而是相当于x = someComplexExpression()&& x.将首先评估右侧,以便与每个其他分配操作符一致.鉴于此,&& =与&=没有不同的行为. (2认同)
  • @PSpeed,你错了。JLS 非常清楚复合分配的用途。请参阅上面我的补充。 (2认同)
  • @PSpeed:在这种情况下,“a -= b;”的工作方式与“a &amp;&amp;= b;”完全不同。 (2认同)

EFr*_*aim 9

这是Java中的这种方式,因为它在C语言中是这样的.

现在问题为什么它在C中是这样的,因为当&和&&成为不同的运算符(在C从C下降之前的某个时间),&=各种运算符被忽略了.

但我的答案的第二部分没有任何来源支持它.

  • 有趣的是 - 最近在 C 论坛上提出了这个问题;并且这个答案是链接的(虽然没有标记为重复)这使得循环论证完成! (2认同)

p00*_*0ya 6

主要是因为 Java 语法基于 C(或至少是 C 系列),并且在 C 中,所有这些赋值运算符都被编译为单个寄存器上的算术或按位汇编指令。赋值运算符版本避免了临时性,并且可能在早期的非优化编译器上生成了更高效的代码。逻辑运算符(在 C 中称为)等价物 ( &&=and ||=) 与单个汇编指令没有如此明显的对应关系;它们通常扩展为测试和分支指令序列。

有趣的是,像 ruby这样的语言确实有 ||= 和 &&=。

编辑:Java 和 C 之间的术语不同