提问人:David Mason 提问时间:3/21/2010 最后编辑:RaedwaldDavid Mason 更新时间:3/8/2019 访问量:68883
Java 中的快捷方式“or-assignment”(|=) 运算符
Shortcut "or-assignment" (|=) operator in Java
问:
我在 Java 中要做一长串比较,我想知道其中一个或多个是否为真。比较字符串很长且难以阅读,因此为了可读性,我将其分解,并自动使用快捷运算符而不是 .|=
negativeValue = negativeValue || boolean
boolean negativeValue = false;
negativeValue |= (defaultStock < 0);
negativeValue |= (defaultWholesale < 0);
negativeValue |= (defaultRetail < 0);
negativeValue |= (defaultDelivery < 0);
如果任何默认值<something>值为负数,我希望为 true。这有效吗?它会达到我的期望吗?我在 Sun 的站点或 stackoverflow 上看不到它,但 Eclipse 似乎没有问题,并且代码可以编译和运行。negativeValue
同样,如果我想执行几个逻辑交集,我是否可以使用 ?&=
&&
答:
它不是“快捷方式”(或短路)运算符,因为 ||和 && 是(如果他们已经知道基于 LHS 的结果,他们不会评估 RHS),但它会在工作方面做你想要的。
作为差异的示例,如果为 null,则此代码没问题:text
boolean nullOrEmpty = text == null || text.equals("")
而这不会:
boolean nullOrEmpty = false;
nullOrEmpty |= text == null;
nullOrEmpty |= text.equals(""); // Throws exception if text is null
(显然,你可以为这种特殊情况做 - 我只是想证明这个原理。"".equals(text)
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale,
defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;
评论
negativeValue = defaultStock < 0 || defaultWholesale < 0
是布尔逻辑运算符 (JLS 15.22.2) 的复合赋值运算符 (JLS 15.26.2);不要与条件或(JLS 15.24)混淆。还有和相对应的布尔逻辑版本和分别。|=
|
||
&=
^=
&
^
换言之,对于 ,这两者是等价的:boolean b1, b2
b1 |= b2;
b1 = b1 | b2;
逻辑运算符 ( 和 ) 与它们的条件对应运算符 ( 和 ) 的区别在于前者不会“短路”;后者确实如此。那是:&
|
&&
||
&
并始终计算两个操作数|
&&
并有条件地评估正确的操作数;仅当右操作数的值可能影响二进制操作的结果时,才会计算该操作数。这意味着在以下情况下不会评估正确的操作数:||
- 的左操作数计算结果为
&&
false
- (因为无论正确的操作数计算为什么,整个表达式都是
false
)
- (因为无论正确的操作数计算为什么,整个表达式都是
- 的左操作数计算结果为
||
true
- (因为无论正确的操作数计算为什么,整个表达式都是
true
)
- (因为无论正确的操作数计算为什么,整个表达式都是
- 的左操作数计算结果为
所以回到你最初的问题,是的,这个构造是有效的,虽然不完全是 和 的等效快捷方式,但它确实计算了你想要的东西。由于您使用的运算符的右侧是一个简单的整数比较操作,因此不短路的事实是微不足道的。|=
=
||
|=
|
在某些情况下,需要短路,甚至需要短路,但您的方案不是其中之一。
不幸的是,与其他一些语言不同,Java 没有 和 。这在问题中讨论过 为什么 Java 没有条件赋值和条件运算符和条件运算符的复合赋值版本?(&&=, ||=).&&=
||=
评论
|
你可以只有一个语句。它用多行表示,读起来几乎与示例代码完全相同,只是不那么必要:
boolean negativeValue
= defaultStock < 0
| defaultWholesale < 0
| defaultRetail < 0
| defaultDelivery < 0;
对于最简单的表达式,使用可能比因为即使它避免进行比较,也意味着隐式使用分支,而这可能要花费很多倍。|
||
评论
busy
虽然对于您的问题来说可能有点矫枉过正,但 Guava 库有一些很好的 s 语法,并且对 or/和 s 进行短路评估。Predicate
Predicate
从本质上讲,比较被转换为对象,打包成一个集合,然后迭代。对于 或谓词,第一个真正的命中从迭代返回,反之亦然。
||逻辑布尔值 OR
|按位 OR
|= 按位包含 OR 和赋值运算符
|= 不缩短的原因是因为它执行的是按位 OR 而不是逻辑 OR。 也就是说:
C |= 2 is same as C = C | 2
评论
如果是关于可读性,我有从测试逻辑中分离测试数据的概念。代码示例:
// declare data
DataType [] dataToTest = new DataType[] {
defaultStock,
defaultWholesale,
defaultRetail,
defaultDelivery
}
// define logic
boolean checkIfAnyNegative(DataType [] data) {
boolean negativeValue = false;
int i = 0;
while (!negativeValue && i < data.length) {
negativeValue = data[i++] < 0;
}
return negativeValue;
}
代码看起来更冗长且不言自明。您甚至可以在方法调用中创建一个数组,如下所示:
checkIfAnyNegative(new DataType[] {
defaultStock,
defaultWholesale,
defaultRetail,
defaultDelivery
});
它比“比较字符串”更具可读性,并且还具有短路的性能优势(以数组分配和方法调用为代价)。
编辑:通过使用 varargs 参数可以简单地实现更高的可读性:
方法签名为:
boolean checkIfAnyNegative(DataType ... data)
通话可能如下所示:
checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );
评论
这是一篇旧文章,但为了给初学者提供不同的视角,我想举个例子。
我认为类似复合运算符最常见的用例是.我敢肯定我们都写过这样的东西:+=
int a = 10; // a = 10
a += 5; // a = 15
这有什么意义呢?关键是要避免样板并消除重复的代码。
因此,下一行执行完全相同的操作,避免在同一行中键入变量两次。b1
b1 |= b2;
评论
longNameOfAccumulatorAVariable += 5;
longNameOfAccumulatorAVariable = longNameOfAccumulatorVVariable + 5;
评论
||=
|=
|=
a |= b;
a = a | b;
a
||=