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

发布于 2024-08-22 17:20:12 字数 2340 浏览 5 评论 0原文

因此,对于布尔值的二元运算符,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)),其中 TE1 的类型,只不过 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:

For &, the result value is true if both operand values are true; otherwise, the result is false.

For |, the result value is false if both operand values are false; otherwise, the result is true.

For ^, the result value is true if the operand values are different; otherwise, the result is false.

The && operator is like & but evaluates its right-hand operand only if the value of its left-hand operand is true.

The || operator is like |, but evaluates its right-hand operand only if the value of its left-hand operand is false.

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 to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

又爬满兰若 2024-08-29 17:20:13

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.

惜醉颜 2024-08-29 17:20:13

Brian Goetz(Oracle Java 语言架构师)写道 :

<块引用>

https://stackoverflow.com/q/2324549/[这个问题]表明人们对拥有这些运算符感兴趣,并且有
目前还没有明确的论据说明为什么它们还不存在。
因此,问题是:JDK 团队过去是否讨论过添加这些运算符?如果是的话
反对添加它们的原因是什么?

我不知道关于这个特定问题的任何具体讨论,但是
如果有人提出这个建议,答案很可能是:这不是一个
虽然要求不合理,但没有分量。

“承载力”需要根据成本和收益来判断,
通过其相对于其他候选特征的成本效益比。

我认为你隐含地假设(通过“有兴趣”这个短语)
成本接近于零,而收益大于零,所以
似乎是明显的胜利。但这掩盖了一种不正确的理解
成本;像这样的功能会影响语言规范、实现,
JCK,以及每一本 IDE 和 Java 教科书。没有琐碎的语言
特征。收益虽然非零,但相当小。

其次,我们可以实现无限多的功能,但是我们
每隔几年只有能力做几次(并且用户有
吸收新功能的能力有限。)所以我们必须非常小心
至于我们选择哪个,因为每个功能(即使是看似微不足道的功能)
消耗了部分预算,并且总是从其他预算中夺走。
不是“为什么不做这个功能”,而是“还有哪些功能我们不会做”
(或延迟),这样我们就可以做这件事,这是一笔好的交易吗?”
真的无法想象这与我们的其他任何交易相比是一笔很好的交易
正在努力。

所以,它清除了“不是一个糟糕的主意”的标准(这已经很漂亮了)
很好,很多功能请求甚至没有明确这一点),但似乎
不太可能清除“更好地利用我们的进化预算”的障碍
比其他任何事情都重要。”

Brian Goetz (Java Language Architect at Oracle) wrote:

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

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

反差帅 2024-08-29 17:20:13

对于布尔变量, &&和 ||将使用短路评估,而 &和|不这样做,所以您会期望 &&= 和 ||= 也使用短路评估。这有一个很好的用例。特别是当您在循环上进行迭代时,您希望快速、高效且简洁。

而是

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

我不想写,

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

想写并知道一旦 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

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.

伤感在游骋 2024-08-29 17:20:13

'&' 和 '&&' 与 '&&' 不同,它是一个快捷操作如果第一个操作数为 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.

源来凯始玺欢你 2024-08-29 17:20:13

有趣的是我遇到了这个问题。

运算符 ||= 和 &&= 不存在,因为它们的语义很容易被误解;
如果您认为需要它们,请改用 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.

痴梦一场 2024-08-29 17:20:13

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 =

淡淡の花香 2024-08-29 17:20:13

我想不出比“它看起来丑得令人难以置信!”更好的理由了。

I cannot think of any better reason then 'It looks incredible ugly!'

贵在坚持 2024-08-29 17:20:13

&

验证两个操作数,它是一个位运算符。 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.

吃不饱 2024-08-29 17:20:12

原因

运算符 &&=||=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
======================

因此 YES 我们可以将 && 替换为 & 作为布尔值;-)

所以最好使用 &= 而不是 &&=

||= 相同

&&= 的原因相同:
运算符 |=||= 更不容易出错。

如果开发人员希望在 f1() 返回 true 时不调用 f2(),那么我建议采用以下替代方案:

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

Reason

The operators &&= and ||= are not available on Java because for most of the developers these operators are:

  • error-prone
  • useless

Example for &&=

If Java allowed &&= operator, then that code:

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. It is like bool isOk = f1() && f2(); where f2() is called only when f1() returns true.

If the developer wants f2() to be called only when f1() returns true, therefore the second code above is less error-prone.

Else &= is sufficient because the developer wants f2() to be always called:

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:

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:

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:

// 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 ...
双马尾 2024-08-29 17:20:12

可能是因为像看起来这样的东西

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

应该分配给x并评估someComplexExpression(),但事实上评估取决于值x 从语法上看不出来。

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

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.

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.

红玫瑰 2024-08-29 17:20:12

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

天气好吗我好吗 2024-08-29 17:20:12

主要是因为 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文