Java中的快捷方式“or-assignment”(| =)运算符

时间:2010-03-21 09:06:34

标签: java assignment-operator compound-assignment or-operator

我在Java中有很长的比较,我想知道它们中的一个或多个是否真实。比较字符串很长且难以阅读,因此我将其分解以便于阅读,并自动使用快捷方式运算符|=而不是negativeValue = negativeValue || boolean

boolean negativeValue = false;
negativeValue |= (defaultStock < 0);
negativeValue |= (defaultWholesale < 0);
negativeValue |= (defaultRetail < 0);
negativeValue |= (defaultDelivery < 0);

如果任何默认&lt; something&gt;我希望negativeValue为真价值是负面的。这有效吗?它会做我期望的吗?我在Sun的网站或stackoverflow上看不到它,但Eclipse似乎没有问题,代码编译并运行。


同样,如果我想要执行多个逻辑交叉点,我可以使用&=代替&&吗?

8 个答案:

答案 0 :(得分:191)

|=是布尔逻辑运算符|JLS 15.26.2)的复合赋值运算符(JLS 15.22.2);不要与条件或||JLS 15.24)混淆。还有&=^=分别对应于布尔逻辑&^的复合赋值版本。

换句话说,对于boolean b1, b2,这两个是等价的:

 b1 |= b2;
 b1 = b1 | b2;

逻辑运算符(&|)与条件运算符(&&||)之间的差异是前者不是“短路”;后者呢。那就是:

  • &| 始终评估两个操作数
  • &&||有条件地评估右操作数 ;只有当其值可能影响二进制操作的结果时,才会评估右操作数。这意味着在以下情况下不评估右操作数:
    • &&的左操作数评估为false
      • (因为无论右操作数的评估结果如何,整个表达式都是false
    • ||的左操作数评估为true
      • (因为无论右操作数的评估结果如何,整个表达式都是true

回到原来的问题,是的,该构造是有效的,虽然|=并不完全是=||的等效快捷方式,但它会计算出你想要的内容。由于您使用的|=运算符的右侧是一个简单的整数比较运算,|没有短路的事实是无关紧要的。

有些情况下,当需要短路或甚至需要短路时,但您的情况不是其中之一。

不幸的是,与其他一些语言不同,Java没有&&=||=。这在 Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=)

的问题中进行了讨论

答案 1 :(得分:16)

它不是||的“快捷方式”(或短路)运算符和&amp;&amp; (如果他们已经知道基于LHS的结果,他们将不会评估RHS)但是它将按照工作的方式做你想做的事。

作为区别的一个例子,如果text为null,则此代码将正常:

boolean nullOrEmpty = text == null || text.equals("")

然而这不会:

boolean nullOrEmpty = false;
nullOrEmpty |= text == null;
nullOrEmpty |= text.equals(""); // Throws exception if text is null

(显然你可以针对那个特例做"".equals(text) - 我只是想证明这个原则。)

答案 2 :(得分:3)

你可以只有一个陈述。在多行中表示它几乎与您的示例代码完全相同,只是不那么强制性:

boolean negativeValue
    = defaultStock < 0 
    | defaultWholesale < 0
    | defaultRetail < 0
    | defaultDelivery < 0;

对于最简单的表达式,使用|可能比||更快,因为即使它避免进行比较,也意味着隐式使用分支,并且可能要贵很多倍。

答案 3 :(得分:1)

尽管对您的问题可能有点过分,但Guava库在Predicate s上有一些很好的语法,并对/和Predicate进行短路评估。

基本上,比较被转换为对象,打包到集合中,然后迭代。对于或谓词,第一个真实命中从迭代返回,反之亦然。和/。

答案 4 :(得分:1)

如果是关于可读性的话,我从测试逻辑中得到了分离测试数据的概念。代码示例:

// 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 );

答案 5 :(得分:1)

这是一个老帖子,但为了给初学者提供不同的视角,我想举个例子。

我认为类似复合运算符的最常见用例是+=。我相信我们都写了这样的东西:

int a = 10;   // a = 10
a += 5;   // a = 15

这有什么意义?重点是避免使用样板并消除重复的代码。

因此,下一行完全相同,避免在同一行中键入变量b1两次。

b1 |= b2;

答案 6 :(得分:0)

List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, 
                                       defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;

答案 7 :(得分:0)

||逻辑布尔或左 |按位OR

| =按位包含OR和赋值运算符

| =不是shortcircit的原因是因为它是按位或不是逻辑OR。 也就是说:


C |= 2 is same as C = C | 2

Tutorial for java operators