有什么情况下最好使用无条件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的盒子相交代码)[需要说明]。