我想知道Java中的一些案例(或者更一般地说:
在编程中)当布尔表达式中首选使用无条件AND
(&
)而不是条件版本(&&
)时。
我知道它们是如何工作的,但我不能考虑使用单&
值得的情况。
答案 0 :(得分:60)
我已经在现实生活中找到了表达式的两面都非常便宜的情况,所以它削减了一两纳秒以避免分支并使用无条件&
代替&&
。 (但这些是非常高性能的数学工具;我几乎从不在其他代码中使用它,如果没有详尽的基准测试来证明它更好,我也不会这样做。)
(举一个具体的例子,x > 0
将是超级便宜和无副作用。为什么要冒险分支错误预测,以避免测试会变得如此便宜?当然,因为它是一个boolean
最终结果将在分支中使用,但if (x >= 0 && x <= 10)
涉及两个分支,而if (x >= 0 & x <= 10)
只涉及一个。)
答案 1 :(得分:20)
唯一的区别是&&
和||
一旦知道就会停止评估。例如:
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
}
然而,对我来说这看起来像是臭臭的代码(在这两种情况下)。
答案 2 :(得分:15)
&amp;&amp;允许jvm进行短路评估。也就是说,如果第一个参数为false,那么它就不需要费心检查第二个参数。
单身&amp;无论如何都会双方都这样做。
所以,作为一个人为的例子,你可能会:
if (account.isAllowed() & logAccountAndCheckFlag(account))
// Do something
在该示例中,您可能始终要记录帐户所有者尝试执行某些操作的事实。
我不认为我曾经使用过单曲&amp;但是在商业节目中。
答案 3 :(得分:11)
维基百科很好地描述了Short Circuit Evaluation
您更喜欢非短路运营商?
来自同一个链接:
短路可能导致现代分支预测错误 处理器,并大大降低性能(一个值得注意的例子是 高度优化的光线,光线中的轴对齐框交叉代码 追查)[需要澄清]。一些编译器可以检测到这种情况 并发出更快的代码,但由于可能,并不总是可能的 违反C标准。高度优化的代码应该使用其他代码 这样做的方法(如汇编代码的手动使用)
答案 4 :(得分:7)
如果有必然发生的副作用,但这有点难看。
按位AND(&
)主要用于 - 按位数学。
答案 5 :(得分:7)
输入验证是一种可能的情况。您通常希望在一次传递中将表单中的所有错误报告给用户,而不是在第一次传递之后停止,并强制他们重复单击提交,每次只收到一个错误:
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() ...
逻辑,您可以在validateField()
中轻松避免短路评估的需要;但是每次调用validateField()时你都需要调用提取的代码;至少为方法调用添加10行。一如既往,这是一种权衡取舍最适合你的案例。
答案 6 :(得分:6)
如果表达式很简单,您可以使用&
或|
进行微优化,因为您正在阻止分支。即
if(a && b) { }
if(!(a || b)) { }
与
相同if (a) if (b) { }
if (!a) if (!b) { }
有两个地方可以发生分支。
但是,使用无条件&
或|
,只能有一个分支。
这有用与否有很大程度上取决于代码的作用。
如果您使用此功能,我会对其进行评论,以便明确说明原因。
答案 7 :(得分:5)
没有任何特定用途的单一&amp;但你可以考虑以下情况。
if (x > 0 & someMethod(...))
{
// code...
}
考虑someMethod()
正在做一些操作,这些操作将修改实例变量或做一些会在以后处理时影响行为的操作。
因此,在这种情况下,如果您使用&&
运算符且第一个条件失败,则永远不会进入someMethod()
。在这种情况下,单个&
运算符就足够了。
答案 8 :(得分:3)
因为&
是一个逐位运算符,所以您可以同时在一个操作中进行多达32次检查。对于这种非常具体的用例,这可以成为显着的速度增益。如果你需要检查大量的条件,并经常这样做,装箱/拆箱的成本是按支票的数量摊销的,或者你是以那种格式存储你的数据在磁盘和内存上(它在单个位掩码中存储32个条件的空间效率更高,&
运算符可以比一系列32个单&&
提供巨大的速度优势。例如,如果你想选择所有可以移动的单位,步兵,武器升级,并由玩家3控制,你可以这样做:
int MASK = CAN_MOVE | INFANTRY | CAN_ATTACK | HAS_WEAPON_UPGRADE | PLAYER_3;
for (Unit u in allunits) {
if (u.mask & MASK == MASK) {
...;
}
}
有关该主题的更多信息,请参阅my other answers相关问题。
答案 9 :(得分:1)
我能想到的唯一好处是,当您需要调用方法或执行代码时,无论第一个表达式是否被评估为true
或false
:
public boolean update()
{
// do whatever you want here
return true;
}
// ...
if(x == y & update()){ /* ... */}
虽然您可以在没有&
的情况下执行此操作:
if(x == y){/* ... */}
update();
答案 10 :(得分:1)
短路可能导致现代处理器上的分支预测错误,并显着降低性能(一个值得注意的例子是高度优化的光线,在光线跟踪中使用轴对齐的盒子交叉代码)[需要澄清]。