提问人:polygenelubricants 提问时间:2/24/2010 最后编辑:polygenelubricants 更新时间:9/2/2022 访问量:19869
为什么 Java 没有条件和条件或运算符的复合赋值版本?(&&=, ||=)
Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=)
问:
因此,对于布尔值上的二进制运算符,Java 有 、 、 和 。&
|
^
&&
||
让我们在这里简要总结一下他们的工作:
对于 ,如果两个操作数值均为 ;否则,结果为 。
&
true
true
false
对于 ,如果两个操作数值均为 ;否则,结果为 。
|
false
false
true
对于 ,如果操作数值不同,则结果值为;否则,结果为 。
^
true
false
运算符类似于,但仅当其左手操作数的值为 时才计算其右操作数。
&&
&
true
运算符类似于 ,但仅当其左操作数的值为 时,才计算其右操作数。
||
|
false
现在,在所有 5 个中,其中 3 个具有复合赋值版本,即 和 。所以我的问题很明显:为什么 Java 不提供 and?我发现我需要的比我需要的还要多。|=
&=
^=
&&=
||=
&=
|=
而且我不认为“因为它太长”是一个好的答案,因为 Java 有.这种遗漏一定有更好的理由。>>>=
有 12 个赋值运算符;[...]
= *= /= %= += -= <<= >>= >>>= &= ^= |=
有人评论说,如果实施了,那么它将是唯一不首先评估右侧的操作员。我认为复合赋值运算符首先计算右侧的想法是错误的。&&=
||=
形式的复合赋值表达式等价于 ,其中 是 的类型,只不过只计算一次。
E1 op= E2
E1 = (T)((E1) op (E2))
T
E1
E1
作为证明,以下代码片段抛出 ,而不是 .NullPointerException
ArrayIndexOutOfBoundsException
int[] a = null;
int[] b = {};
a[0] += b[-1];
答:
在 Java 中是这样,因为在 C 中也是这样。
现在的问题是,为什么在C中会这样,因为当&和&&成为不同的运算符时(在C从B下降之前的某个时间),&=运算符的多样性被忽略了。
但我回答的第二部分没有任何来源来支持它。
评论
这在 Ruby 中是允许的。
如果我猜的话,我会说它不经常使用,所以它没有实现。另一种解释可能是解析器只查看 = 之前的字符
评论
我想不出更好的理由了,'它看起来非常丑陋!
评论
&&=
'&
' 和 '' 不一样,因为 '' 是一个快捷方式操作,如果第一个操作数是假的,则不会这样做,而 '' 无论如何都会这样做(适用于数字和布尔值)。&&
&&
&
我确实同意存在更有意义,但如果它不存在,它并没有那么糟糕。我想它不存在,因为 C 没有它。
真的想不出为什么。
Java 的最初目标之一是“简单、面向对象和熟悉”。在这种情况下,&= 是熟悉的(C,C++ 有它,在这种情况下,熟悉意味着知道这两者的人熟悉)。
&&= 不会很熟悉,也不会很简单,因为语言设计者不会考虑他们可以添加到语言中的每个运算符,所以更少的额外运算符更简单。
很大程度上是因为 Java 语法是基于 C(或至少是 C 系列)的,而在 C 中,所有这些赋值运算符都会被编译为单个寄存器上的算术或按位汇编指令。赋值运算符版本避免了临时性,并且可能在早期的非优化编译器上生成了更有效的代码。逻辑运算符(在 C 中称为)等价物 ( 和 ) 与单个汇编指令没有如此明显的对应关系;它们通常扩展到测试和分支指令序列。&&=
||=
有趣的是,像 ruby 这样的语言确实有 ||= 和 &&=。
编辑:Java和C之间的术语不同
评论
&
|
^
&&
||
bool
&&=
可能是因为类似的东西
x = false;
x &&= someComplexExpression();
看起来它应该分配给和评估,但从语法中看不出评估取决于 的值这一事实并不明显。x
someComplexExpression()
x
此外,因为 Java 的语法是基于 C 语言的,没有人认为迫切需要添加这些运算符。无论如何,你最好使用 if 语句。
评论
x() && y()
&&
&&=
>>>
>>>=
a -= b;
a &&= b;
原因
运算符 和 在 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() 返回值如何,它总是被调用。这就像只有在返回时才调用 where。f2()
bool isOk = f1() && f2();
f2()
f1()
true
如果开发人员只想在返回时被调用,那么上面的第二个代码就不太容易出错。f2()
f1()
true
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
======================
因此,是的,我们可以替换为布尔值;-)&&
&
所以最好用.&=
&&=
同样||=
与 的原因相同:
运算符比 更不容易出错。&&=
|=
||=
如果开发人员不想在退货时被调用,那么我建议以下替代方案: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();
艺术
// 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 ...
评论
&
&&
if (a) a = b
a&=b;
if(a) a=b;
b
if(a) a=b;
isOK &&= f2();
&&
A = A op B
bool isOk = f1() || f2() || f3() || f4();
对于布尔变量、&& 和 ||将使用 & 和 |不要,所以你会期望 &&= 和 ||= 也使用短路评估。这是一个很好的用例。特别是如果你在循环中迭代,你希望快速、高效和简洁。
而不是写作
foreach(item in coll)
{
bVal = bVal || fn(item); // not so elegant
}
我想写
foreach(item in coll)
{
bVal ||= fn(item); // elegant
}
并且知道一旦 bVal 为真,fn() 将不会在剩余的迭代中被调用。
评论
if (fn(item)) { bVal = true; break; }
&
验证两个操作数,它是一个按位运算符。Java 定义了几个按位运算符,这些运算符可以应用于整数类型 long、int、short、char 和 byte。
&&
如果第一个操作数的计算结果为 false,则停止计算,因为结果将为 false,它是一个逻辑运算符。它可以应用于布尔值。
&&运算符类似于&运算符,但可以使你的代码更有效率。由于 & 运算符比较的两个表达式都必须为 true,整个表达式才能为 true,因此如果第一个表达式返回 false,则没有理由计算第二个表达式。& 运算符始终计算这两个表达式。&& 运算符仅在第一个表达式为 true 时计算第二个表达式。
使用 &&= 赋值运算符不会真正为语言添加新功能。按位运算符的算术更具表现力,可以做整数按位算术,其中包括布尔算术。逻辑运算符只能做布尔运算。
Brian Goetz(Oracle 的 Java 语言架构师)写道:
https://stackoverflow.com/q/2324549/[这个问题]表明有兴趣拥有这些运营商,并且那里 没有明确的论据说明为什么它们还不存在。 因此,问题是:JDK 团队过去是否讨论过添加这些运算符,如果是的话 反对添加它们的原因是什么?
我不知道关于这个特定问题的任何具体讨论,但是 如果有人提出它,答案可能是:它不是 不合理的要求,但它没有分量。
“负重其道理”需要根据其成本和收益来判断,并且 按其相对于其他候选特征的成本效益比。
我认为你是在含蓄地假设(通过“有兴趣”这句话) 成本接近于零,收益大于零,所以它 似乎是一个明显的胜利。但这掩盖了对 成本;像这样的功能会影响语言规范、实现、 JCK 以及所有 IDE 和 Java 教科书。没有琐碎的语言 特征。收益虽然不为零,但非常小。
其次,我们可以做无限多的功能,但是我们 每隔几年才有能力做一小撮(并且用户有一个 吸收新功能的能力有限。所以我们必须非常小心 至于我们选择哪个,因为每个功能(即使是看似微不足道的功能) 消耗了其中的一部分预算,并且总是从其他预算中拿走它。
这不是“为什么不做这个功能”,而是“我们不会做其他功能 (或延迟)这样我们就可以做这个,这是一笔好交易吗?而我 真的无法想象这是对我们其他任何东西的好交易 正在工作。因此,它清除了“不是一个可怕的想法”(这已经很漂亮了)的障碍 很好,很多功能请求甚至没有清除这一点),但似乎 不太可能清除“更好地利用我们的进化预算”的障碍 比什么都重要。
有趣的是,我遇到了这个问题。
运营商 ||= 和 &&= 不存在,因为它们的语义很容易被误解; 如果您认为需要它们,请改用 if-statement。
Ely(上面的帖子)说对了要点:
||
如果第一个操作数的计算结果为 true,则停止计算,因为结果为 true,它是一个逻辑运算符。
所以想象一下,如果 b == true,会发生什么;
乙 ||= somethingreturningaboolean();// !!??
如果 b == true,则不会调用 somethingreturningaboolean()。
这种行为在长形式中更为明显:
b = b ||somethingreturningaboolean();
这就是为什么 ||= 和 &&= 运算不存在。解释应如下: 运营商 ||= 和 &&= 不存在,因为它们的语义很容易被误解; 如果您认为需要它们,请改用 if-statement。
评论