简体   繁体   English

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

[英]Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=)

So for binary operators on booleans, Java has & , |所以对于布尔值的二元运算符,Java 有& , | , ^ , && and || , ^ , &&|| . .

Let's summarize what they do briefly here:让我们在这里简要总结一下他们所做的事情:

For & , the result value is true if both operand values are true ;对于& ,如果两个操作数都为true true otherwise, the result is false .否则,结果为false

For |对于| , the result value is false if both operand values are false ; ,如果两个操作数的值都为false false otherwise, the result is true .否则,结果为true

For ^ , the result value is true if the operand values are different;对于^ ,如果操作数值不同,则结果值为true otherwise, the result is false .否则,结果为false

The && operator is like & but evaluates its right-hand operand only if the value of its left-hand operand is true . &&运算符类似于&但仅当其左侧操作数的值为true时才评估其右侧操作数。

The || || operator is like |运算符就像| , but evaluates its right-hand operand only if the value of its left-hand operand is false . ,但仅当其左侧操作数的值为false时才评估其右侧操作数。

Now, among all 5, 3 of those have compound assignment versions, namely |= , &= and ^= .现在,在所有 5 个中,其中 3 个具有复合赋值版本,即|=&=^= So my question is obvious: why doesn't Java provide &&= and ||= as well?所以我的问题很明显:为什么 Java 也不提供&&=||= 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 >>>= .而且我不认为“因为它太长”是一个好的答案,因为 Java 有>>>= There must be a better reason for this omission.这种遗漏一定有更好的理由。


From 15.26 Assignment Operators :15.26 赋值运算符

There are 12 assignment operators;有12个赋值运算符; [...] = *= /= %= += -= <<= >>= >>>= &= ^= |= [...] = *= /= %= += -= <<= >>= >>>= &= ^= |=


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 :15.26.2 复合赋值运算符

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)) , where T is the type of E1 , except that E1 is evaluated only once. E1 op= E2形式的复合赋值表达式等价于E1 = (T)((E1) op (E2)) ,其中TE1的类型,除了E1只计算一次。

As proof, the following snippet throws a NullPointerException , not an ArrayIndexOutOfBoundsException .作为证明,以下代码段抛出NullPointerException ,而不是ArrayIndexOutOfBoundsException

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];

Reason原因

The operators &&= and ||= are not available on Java because for most of the developers these operators are:运算符&&=||=Java上不可用,因为对于大多数开发人员来说,这些运算符是:

  • error-prone容易出错
  • useless无用

Example for &&= &&=示例

If Java allowed &&= operator, then that code:如果 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

would be equivalent to:将相当于:

bool isOk = true;
if (isOK) isOk = f1();
if (isOK) isOk = f2(); //f2() is called only when f1() returns true

This first code is error-prone because many developers would think f2() is always called whatever the f1() returned value.第一段代码很容易出错,因为许多开发人员会认为无论 f1() 返回什么值,总是调用f2() It is like bool isOk = f1() && f2();这就像bool isOk = f1() && f2(); where f2() is called only when f1() returns true .其中f2()仅在f1()返回true时调用。

If the developer wants f2() to be called only when f1() returns true , therefore the second code above is less error-prone.如果开发人员希望f2()仅在f1()返回true时被调用,则上面的第二个代码不太容易出错。

Else &= is sufficient because the developer wants f2() to be always called:否则&=就足够了,因为开发人员希望f2()始终被调用:

Same example but for &=同样的例子,但对于&=

bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value

Moreover, the JVM should run this above code as the following one:此外,JVM 应将上述代码运行为以下代码:

bool isOk = true;
if (!f1())  isOk = false;
if (!f2())  isOk = false;  //f2() always called

Compare && and & results比较&&&结果

Are the results of operators && and & the same when applied on boolean values?当应用于布尔值时,运算符&&&的结果是否相同?

Let's check using the following Java code:让我们使用以下 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;
}

Output:输出:

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
======================

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 when f1() returns true , then I advice the following alternatives:如果开发者想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();

or:或者:

// 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 ...

Probably because something like可能是因为像

x = false;
x &&= someComplexExpression();

looks like it ought to be assigning to x and evaluating someComplexExpression() , but the fact that the evaluation hinges on the value of x isn't apparent from the syntax.看起来它应该分配给x并评估someComplexExpression() ,但评估取决于x的值这一事实从语法中并不明显。

Also because Java's syntax is based on C, and no one saw a pressing need to add those operators.也因为 Java 的语法是基于 C 的,没有人看到添加这些运算符的迫切需要。 You'd probably be better off with an if statement, anyway.无论如何,使用 if 语句可能会更好。

It is this way in Java, because it is this way in C.在 Java 中是这样,因为在 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.现在的问题是,为什么在 C 中如此,因为当 & 和 && 成为不同的运算符(有时在 C 从 B 下降之前)时,&= 运算符的种类被简单地忽略了。

But the second part of my answer does not have any sources to back it up.但是我的答案的第二部分没有任何来源来支持它。

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.主要是因为 Java 语法基于 C(或至少是 C 系列),而在 C 中,所有这些赋值运算符都被编译为单个寄存器上的算术或按位汇编指令。 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;逻辑运算符(在 C 中称为)等价物( &&=||= )与单个汇编指令没有如此明显的对应关系; they usually expand to a test and branch sequence of instructions.它们通常扩展为测试和分支指令序列。

Interestingly, languages like ruby do have ||= and &&=.有趣的是,像 ruby这样的语言确实有 ||= 和 &&=。

Edit: terminology differs between Java and C编辑:Java 和 C 之间的术语不同

One of Java's original aims was to be "Simple, Object Oriented, and Familiar." Java 的最初目标之一是“简单、面向对象和熟悉”。 As applied to this case, &= is familiar (C, C++ have it and familiar in this context meant familiar to someone who knows those two).应用于这种情况时, &= 是熟悉的(C、C++ 有它,并且在这种情况下熟悉意味着熟悉这两个的人熟悉)。

&&= 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. &&= 不会很熟悉,也不会很简单,因为语言设计者并不想考虑他们可以添加到语言中的每个运算符,因此更少的额外运算符更简单。

For Boolean vars, && and ||对于布尔变量,&& 和 || would use short circuit evaluation while & and |将使用短路评估 while & 和 | 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而不是写作

foreach(item in coll)
{
   bVal = bVal || fn(item); // not so elegant
}

I want to write我想写

foreach(item in coll)
{
  bVal ||= fn(item);    // elegant
}

and know that once bVal is true, fn() will not be called for the remainder of the iterations.并且知道一旦 bVal 为真, fn() 将不会在剩余的迭代中被调用。

' & ' 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). ' & ' 和 ' && ' 与 ' && ' 不同,这是一个快捷操作,如果第一个操作数为 false 则不会执行,而 ' & ' 无论如何都会执行(适用于数字和布尔值)。

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.我想它不存在是因为 C 没有它。

Really can't think of why.实在想不出为什么。

It is allowed in Ruby.它在 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 =另一种解释可能是解析器只查看 = 之前的字符

我想不出比“它看起来非常丑陋”更好的理由了!

& &

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. Java 定义了几个按位运算符,它们可以应用于整数类型,long、int、short、char 和 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.逻辑运算符只能进行布尔运算。

Brian Goetz (Java Language Architect at Oracle) wrote : Brian Goetz(Oracle 的 Java 语言架构师) 写道

https://stackoverflow.com/q/2324549/ [this question] shows that there is interest in having these operators and there are no clear arguments why they don't exist yet. https://stackoverflow.com/q/2324549/ [这个问题]表明有兴趣拥有这些运算符,并且没有明确的论据为什么它们还不存在。 The question is therefore: Has the JDK team discussed adding these operators in the past and if so what where the reasons against adding them?因此,问题是:JDK 团队过去是否讨论过添加这些运算符,如果是,则反对添加它们的原因是什么?

I'm not aware of any specific discussion on this particular issue, but if someone were to propose it, the answer would likely be: it's not an unreasonable request, but it doesn't carry its weight.我不知道关于这个特定问题的任何具体讨论,但如果有人提出它,答案可能是:这不是一个不合理的要求,但它没有它的分量。

"Carrying its weight" needs to be judged by its costs and benefits, and by its cost-benefit ratio relative to other candidate features. “承担其重量”需要根据其成本和收益以及相对于其他候选功能的成本效益比来判断。

I think you are implicitly assuming (by the phrase "there is interest") that the cost is near zero and the benefit is greater than zero, so it seems an obvious win.我认为您隐含地假设(通过“有利息”一词)成本接近于零而收益大于零,因此这似乎是明显的胜利。 But this belies an incorrect understanding of cost;但这掩盖了对成本的错误理解; a feature like this affects the language spec, the implementation, the JCK, and every IDE and Java textbook.像这样的特性会影响语言规范、实现、JCK 以及每个 IDE 和 Java 教科书。 There are no trivial language features.没有微不足道的语言功能。 And the benefit, while nonzero, is pretty small.收益虽然非零,但非常小。

Secondarily, there are infinitely many features we could do, but we only have capacity to do a handful every few years (and users have a limited capacity to absorb new features.) So we have to be very careful as to which we pick, as each feature (even a trivial-seeming one) consumes some of this budget, and invariably takes it away from others.其次,我们可以做无限多的功能,但我们只能每隔几年做一些(而且用户吸收新功能的能力有限。)所以我们必须非常小心我们选择哪个,因为每个功能(即使是看似微不足道的功能)都会消耗一部分预算,并且总是从其他功能中拿走它。
It's not "why not this feature", but "what other features will we not do (or delay) so we can do this one, and is that a good trade?"这不是“为什么不使用此功能”,而是“我们将不做(或延迟)哪些其他功能以便我们可以做这个,这是一个好的交易吗?” And I can't really imagine this being a good trade against anything else we're working on.而且我真的无法想象这是与我们正在研究的任何其他事物进行的良好交易。

So, it clears the bar of "not a terrible idea" (which is already pretty good, a lot of feature requests don't even clear that), but seems unlikely to ever clear the bar of "a better use of our evolution budget than anything else."因此,它清除了“不是一个糟糕的主意”的障碍(这已经很好了,很多功能请求甚至都没有清除),但似乎不太可能清除“更好地利用我们的进化预算”的障碍比什么都重要。”

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.如果您认为需要它们,请改用 if 语句。

Ely (post just above) got the gist right: Ely(上面的帖子)的要点是正确的:

|| ||

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 == true 会发生什么;

b ||= somethingreturningaboolean(); b ||= somereturningabolean(); //???? //????

this will not invoke somethingreturningaboolean(), if b == true.如果 b == true,这将不会调用 somethingreturningabolean()。

This behavior is more obvious in the long form:这种行为在长格式中更为明显:

b = b || 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.如果您认为需要它们,请改用 if 语句。

So for binary operators on booleans, Java has & , |因此,对于布尔值上的二进制运算符,Java具有&| , ^ , && and || ^&&|| .

Let's summarize what they do briefly here:让我们在这里简要总结一下他们的工作:

For & , the result value is true if both operand values are true ;对于& ,如果两个操作数值都为true ,则结果值为true ;否则,结果值为true otherwise, the result is false .否则,结果为false

For |对于| , the result value is false if both operand values are false ;时,结果值是false如果两个操作数的值是false ; otherwise, the result is true .否则,结果为true

For ^ , the result value is true if the operand values are different;对于^ ,如果操作数值不同,则结果值为true否则,结果值为true otherwise, the result is false .否则,结果为false

The && operator is like & but evaluates its right-hand operand only if the value of its left-hand operand is true . &&运算符与&相似&但仅在其左侧操作数的值为true时才评估其右侧操作数。

The || || operator is like |运算符就像| , but evaluates its right-hand operand only if the value of its left-hand operand is false . ,但仅当其左侧操作数的值为false才对其右侧操作数求值。

Now, among all 5, 3 of those have compound assignment versions, namely |= , &= and ^= .现在,在所有5个中,有3个具有复合赋值版本,即|=&=^= So my question is obvious: why doesn't Java provide &&= and ||= as well?所以我的问题显而易见:为什么Java也不能提供&&=||= 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 >>>= .而且我不认为“因为它太长”是一个很好的答案,因为Java具有>>>= There must be a better reason for this omission.一定有一个更好的理由可以忽略这一点。


From 15.26 Assignment Operators :15.26赋值运算符开始

There are 12 assignment operators;有12个赋值运算符; [...] = *= /= %= += -= <<= >>= >>>= &= ^= |= [...] = *= /= %= += -= <<= >>= >>>= &= ^= |=


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 :15.26.2复合赋值运算符开始

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)) , where T is the type of E1 , except that E1 is evaluated only once.形式为E1 op= E2的复合赋值表达式等效于E1 = (T)((E1) op (E2)) ,其中TE1的类型,不同之处在于E1仅被评估一次。

As proof, the following snippet throws a NullPointerException , not an ArrayIndexOutOfBoundsException .作为证明,以下代码段抛出NullPointerException ,而不是ArrayIndexOutOfBoundsException

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM