95

我在 Java 中有很多比较要做,我想知道其中一个或多个是否为真。比较字符串很长且难以阅读,因此为了便于阅读,我将其拆分,并自动使用快捷操作符|=而不是negativeValue = negativeValue || boolean.

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

negativeValue如果任何 default<something> 值为负,我希望是真的。这是有效的吗?它会达到我的预期吗?我在 Sun 的网站或 stackoverflow 上看不到它,但 Eclipse 似乎没有问题,并且代码可以编译并运行。


同样,如果我想执行几个逻辑交集,我可以使用&=代替&&吗?

4

8 回答 8

215

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

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

 b1 |= b2;
 b1 = b1 | b2;

&逻辑运算符 ( and |) 与条件运算符 ( &&and )的区别在于||前者不会“短路”;后者做。那是:

  • &| 始终评估两个操作数
  • &&有条件||地评估右操作数;只有当右操作数的值会影响二元运算的结果时,才会计算右操作数。这意味着在以下情况下不评估右操作数:
    • 的左操作数&&计算为false
      • (因为无论正确的操作数计算为什么,整个表达式都是false
    • 的左操作数||计算为true
      • (因为无论正确的操作数计算为什么,整个表达式都是true

所以回到你原来的问题,是的,这个结构是有效的,虽然它不完全是and|=的等效快捷方式,但它确实计算你想要的。由于您使用的运算符右侧是简单的整数比较运算,因此不短路的事实无关紧要。=|||=|

在某些情况下,需要甚至需要短路,但您的情况不是其中之一。

不幸的是,与其他一些语言不同,Java 没有&&=and ||=。这在为什么 Java 没有条件与和条件或运算符的复合赋值版本中讨论过?(&&=, ||=)

于 2010-03-21T09:44:39.737 回答
16

它不是 || 的“捷径”(或短路)运算符。和 && 是(如果他们已经知道基于 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)为那个特殊情况做 - 我只是想证明这个原则。)

于 2010-03-21T09:12:10.893 回答
3

你可以只有一个声明。用多行表示,它的读法几乎与您的示例代码完全相同,只是不太重要:

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

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

于 2010-03-21T10:14:14.600 回答
1

尽管对于您的问题来说这可能是多余的,但Guava库对 s 有一些很好的语法,并对 or/and sPredicate进行短路评估。Predicate

本质上,比较被转换成对象,打包成一个集合,然后迭代。对于 or 谓词,第一个真正的命中从迭代中返回,反之亦然。

于 2010-03-22T14:28:50.810 回答
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
});

它比“比较字符串”更具可读性,并且还具有短路的性能优势(以数组分配和方法调用为代价)。

编辑: 通过使用可变参数参数可以简单地实现更高的可读性:

方法签名将是:

boolean checkIfAnyNegative(DataType ... data)

调用可能如下所示:

checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );
于 2013-04-25T09:38:56.057 回答
1

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

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

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

这是什么意思?重点是避免样板代码并消除重复代码。

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

b1 |= b2;
于 2018-04-16T14:13:43.180 回答
0
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, 
                                       defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;
于 2010-03-21T09:15:38.240 回答
0

|| 逻辑布尔 OR
| 按位或

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

|= 不短路的原因是因为它执行按位或而不是逻辑或。也就是说:

C |= 2 与 C = C | 相同 2

java运算符教程

于 2013-01-11T19:15:04.937 回答