有什么情况下最好使用无条件AND(而不是&&)

我想知道在Java中的一些情况(或者更一般地说:在编程中),当在布尔expression式中首选使用无条件AND& )而不是条件版本( && )时。

我知道他们是如何工作的,但是我不能想到使用单个&是值得的。

我在现实生活中发现了一些情况,expression式的两边都很便宜,所以为了避免分支和使用无条件&而不是&& ,它削减了一两个纳秒。 (这些是非常高性能的math工具,但是我几乎不会在其他代码中使用这个工具,如果没有详尽的基准testing来certificate它是更好的,我也不会这么做。

(为了给出具体的例子, x > 0将会非常便宜且不会产生副作用,为什么还要冒一个分支错误的预测来避免一个testing会变得如此便宜呢?当然,因为它是一个boolean所以最终的结果是if (x >= 0 && x <= 10)涉及两个分支,并且if (x >= 0 & x <= 10)只涉及一个分支。

唯一的区别是&&|| 一知道就停止评估。 举个例子:

 if (a != null && a.get() != null) 

&&一起工作的很好,但是如果a为null &你可能会得到一个NullPointerException。

唯一的情况是我可以考虑在哪里使用&如果第二个操作数有副作用,例如(可能不是最好的例子,但你明白了):

 public static void main(String[] args) { int i = 1; if (i == 0 & ++i != 2) { } System.out.println(i); //2 i = 1; if (i == 0 && ++i != 2) { } System.out.println(i); //1 } 

但是,这看起来像我的臭味代码(在这两种情况下)。

&&允许jvm进行短路评估。 也就是说,如果第一个参数是错误的,那么就不需要麻烦检查第二个参数。

一个单一&将运行双方无论。

所以,作为一个人为的例子,你可能有:

 if (account.isAllowed() & logAccountAndCheckFlag(account)) // Do something 

在这个例子中,您可能总是想logging账户所有者试图做某事的事实。

我不认为我曾经使用过一个商业编程。

维基百科很好地描述了短路评估

你更喜欢非短路操作员?

从相同的链接:

  • 未经testing的第二种情况导致未执行的副作用
  • 代码效率

短路会导致现代处理器的分支预测出现错误,并且会大大降低性能(一个值得注意的例子是高度优化的射线跟踪中轴alignment的盒子相交代码)[需要说明]。 一些编译器可以检测到这种情况,并发出更快的代码,但由于可能违反C标准,所以并不总是可能的。 高度优化的代码应该使用其他方式来做到这一点(如手动使用汇编代码)

如果有副作用必须发生,但这有点难看。

按位与( & )主要用于这个 – 按位math。

inputvalidation是一种可能的情况。 您通常希望将一个表单中的所有错误一次报告给用户,而不是在第一个报告之后停止,并强制他们重复单击提交,并且每次只收到一个错误:

 public boolean validateField(string userInput, string paramName) { bool valid; //do validation if (valid) { //updates UI to remove error indicator (if present) reportValid(paramName); } else { //updates UI to indicate a problem (color change, error icon, etc) reportInvalid(paramName); } } public boolean validateAllInput(...) { boolean valid = true; valid = valid & validateField(userInput1, paramName1); valid = valid & validateField(userInput2, paramName2); valid = valid & validateField(userInput3, paramName3); valid = valid & validateField(userInput4, paramName4); valid = valid & validateField(userInput5, paramName5); return valid; } public void onSubmit() { if (validateAllInput(...)) { //go to next page of wizard, update database, etc processUserInput(userInput1, userInput2, ... ); } } public void onInput1Changed() { validateField(input1.Text, paramName1); } public void onInput2Changed() { validateField(input2.Text, paramName2); } ... 

当然,通过重构validateAllInput()if (valid) { reportValid() ...逻辑,可以避免在validateAllInput()短路求值的需要。 但是每次调用validateField()时都需要调用提取的代码; 至less为方法调用添加10个额外的行。 像往常一样,这是一个折衷的工作最适合你的情况。

如果expression式微不足道,您可以使用&|来获得微观优化 因为你正在阻止一个分支。 即。

 if(a && b) { } if(!(a || b)) { } 

是相同的

 if (a) if (b) { } if (!a) if (!b) { } 

其中有两个地方可能发生分支。

但是使用无条件的&| ,只能有一个分支。

Whetehr这有助于与否高度依赖于代码正在做什么。

如果你使用这个,我会试着说明它为什么已经完成。

没有单一的具体用途,但你可以考虑以下情况。

 if (x > 0 & someMethod(...)) { // code... } 

考虑一下someMethod()正在做一些操作,这些操作会修改实例variables或者做一些会影响后面的行为的东西。

所以在这种情况下,如果使用&&运算符,并且第一个条件失败,它将永远不会进入someMethod() 。 在这种情况下,单个&运算符就足够了。

由于&是一个按位运算符,因此可以同时在单个操作中执行多达32个检查。 这可以成为这个非常具体的用例的显着的速度增益。 如果你需要检查大量的条件,并经常做这些事情,装箱/拆箱条件的成本将通过检查次数来分摊,或者如果你将数据以这种格式存储在磁盘和RAM上在单个位掩码中存储32个条件的空间效率更高), &运算符可以为一系列32个单独的&&提供巨大的速度优势。 例如,如果你想select所有可移动的单位,是一个步兵,有武器升级,并由玩家3控制,你可以:

 int MASK = CAN_MOVE | INFANTRY | CAN_ATTACK | HAS_WEAPON_UPGRADE | PLAYER_3; for (Unit u in allunits) { if (u.mask & MASK == MASK) { ...; } } 

在相关的问题上看到我的其他答案更多关于这个话题。

我能想到的唯一好处是当你需要调用一个方法或者执行一个代码时,不pipe第一个expression式被评估为true还是false

 public boolean update() { // do whatever you want here return true; } // ... if(x == y & update()){ /* ... */} 

虽然你可以做到这一点没有&

 if(x == y){/* ... */} update(); 

短路会导致现代处理器的分支预测出现错误,并且会大大降低性能(一个值得注意的例子是高度优化的射线跟踪中轴alignment的盒子相交代码)[需要说明]。