在 Java 中显式地比较布尔常量(例如 if (b = = false))是否不好?

写下:

if (b == false) //...


while (b != true) //...

一直都是是不是应该写:

if (!b) //...


while (!b) //...

大概在性能上没有差异(或者有差异吗?)但是你如何权衡两者之间的明确性、简洁性、清晰性、可读性等?

更新

为了限制主观性,我还希望引用权威的编码风格指南中的任何一条,来说明哪一条总是更可取,或者在什么时候使用哪一条。


注意 : 变量名 b只是作为一个例子使用的,它是 ala foobar

35146 次浏览

除了在初学者编写的代码中,我从未见过前者; 它总是后者,而且我不认为任何人真的会对它感到困惑。另一方面,我觉得

int x;
...
if(x) //...

if(x != 0) //...

更具争议性,在这种情况下,我更喜欢后者

在我看来,这简直是令人讨厌。不过,我不会因此而引起骚动。

这不一定是坏事,只是多余而已。而且,实际的变量名称权重很大。我宁愿例如 if (userIsAllowedToLogin)超过 if (b)或甚至更坏的 if (flag)

至于性能问题,编译器会以任何方式对其进行优化。

至于权威的来源,我不能找到一些明确的东西,在 Java 代码约定最初由 Sun 编写,但至少 检查方式有一个 SimplifyBooleanExpression模块,将警告这一点。

我更喜欢第一个,因为它更清晰。机器可以读取任何一个同样好,但我尝试为其他 读取代码,而不仅仅是机器。

你不应该使用第一种风格。我见过人们使用:

  • if ( b == true )
  • if ( b == false )

我个人觉得很难读,但还过得去。然而,我对这种风格有一个很大的问题,那就是它导致了你展示的令人难以置信的反直觉的例子:

  • if ( b != true )
  • if ( b != false )

这就需要读者付出更多的努力来确定作者的意图。就我个人而言,我发现包含明确的真假比较是多余的,因此难以阅读,但这就是我。

你不应该使用第一种风格的最重要的原因是因为这两种风格都是有效的:

if (b = false) //...


while (b = true) //...

也就是说,如果您不小心遗漏了一个字符,您将创建一个赋值而不是比较。赋值表达式计算所赋的值,因此上面的第一条语句将值 false赋给 b并计算为 false。第二个函数将 true赋值给 b,因此无论您在循环中如何处理 b,它的计算结果总是 true

恕我直言,我认为如果你只是把 bool 变量的名字放在 "Is"前面,这将是不言而喻的,而且更有意义,然后,你可以去掉与 truefalse的显式比较

例如:

isEdited  // use IsEdited in case of property names
isAuthorized // use IsAuthorized in case of property names

等等

这很大程度上取决于品味。

就我个人而言,我发现 if (!a) {if (a == false) {少很多 可读(编辑: 对我来说) ,因此在以后维护代码时更容易出错,我已经转换为使用后一种形式。

基本上,我不喜欢选择逻辑运算符号而不是单词(C 对 Pascal) ,因为对于 a = 10 and not b = 20读取比 a == 10 && !(b==20)容易,但这就是 Java 的方式。

任何支持“ = = 错误”方法的人显然,他从来没有长时间地盯着代码看,也没有错过这个叹号。是的,你可以得到代码盲。

就个人而言,我会重构代码,这样我就不会使用负面的测试。

if (b == false) {
// false
} else {
// true
}

或者

boolean b = false;
while(b == false) {
if (condition)
b = true;
}

恕我直言,在90% 的情况下,代码可以重构,因此不需要阴性测试。

我觉得很糟糕。

while (!b) {
// do something
}

读起来比

while (b != true) {
// do something
}

通常的指导原则是永远不要对布尔值进行测试。有些人认为,额外的冗长增加了清晰度。添加的代码可能会帮助一些人,但每个读者将需要阅读更多的代码。

今天早上,我花了半个小时才找到一个错误,代码是

    if ( !strcmp(runway_in_use,"CLOSED") == IPAS_FALSE)
printf(" ACTIVE    FALSE \n");   else
printf(" ACTIVE    TRUE \n");

如果它是按照正常的约定编码的,我就能更快地发现它是错误的:

    if (strcmp(runway_in_use, "CLOSED"))
printf(" ACTIVE    FALSE \n");   else
printf(" ACTIVE    TRUE \n");

我更喜欢长的方法,但我比较使用 ==而不是 !=99% 的时间。

我知道这个问题是关于 Java 的,但是我经常在不同语言之间切换,例如,在 C#中,比较(比如) == false可以帮助处理可为空的 bool 类型。因此,我养成了这样的习惯: 与 truefalse进行比较,但使用 ==运算符。

我这样做:

if(isSomething == false)if(isSomething == true)

但我讨厌这些:

if(isSomething != false)if(isSomething != true)

因为显而易见的可读性原因!

只要你保持你的代码可读性,这将无关紧要。

第一个(b = = false)不被接受的原因之一是,初学者通常没有意识到第二个选择(!B)是完全可能的。因此,使用第一种形式可能会指出对布尔表达式和布尔变量的误解。通过这种方式,使用第二种形式已经成为某种形式: 当有人写这个,他/她可能明白发生了什么。

我认为,这使得差异被认为比实际情况更为重要。

这是我对 StackOverflow 的第一个回答,所以友好一点..。 最近在重构的时候,我注意到有两个代码块几乎完全相同,但是有一个代码块完全相同

for (Alert alert : alerts) {
Long currentId = alert.getUserId();


if (vipList.contains(currentId)) {
customersToNotify.add(alert);


if (customersToNotify.size() == maxAlerts) {
break;
}
}
}

而另一个

for (Alert alert : alerts) {
Long currentId = alert.getUserId();


if (!vipList.contains(currentId)) {
customersToNotify.add(alert);


if (customersToNotify.size() == maxAlerts) {
break;
}
}
}

所以在这种情况下,创建一个同时适用于这两种情况的方法是有意义的使用 boolean == condition来翻转含义

private void appendCustomersToNotify(List<Alert> alerts
List<Alert> customersToNotify, List<Long> vipList, boolean vip){


for (Alert alert : alerts) {
Long currentId = alertItem.getUserId();


if (vip == vipList.contains(currentId)) {
customersToNotify.add(alertItem);


if (customersToNotify.size() == maxAlerts) {
break;
}
}
}
}

虽然两者都是有效的,但对我来说,第一个感觉像是一个类型错误。

对我来说,b == false看起来和 (i == 0) == false一样错误?

布尔值不是具有2个可能值的枚举。你不能拿它们来比较。布尔型是谓词,表示一些真值。它们有特定的操作符,如 &|^!

要反转一个表达式的真值,可以使用操作符“ !”,发音为“ not”。

正确的命名,它变得自然: !isEmpty读“不是空的”,对我来说相当可读。
isEmpty == false读起来像“它是空的是假的”,我需要更多的时间来处理。

我不会详细说明所有的细节,因为许多人已经正确回答了。

在功能方面,它给出了相同的结果。

至于样式,这是一个偏好的问题,但我相信 !condition更具可读性。

对于性能方面的论点,我看到许多人说,这没有什么区别,但他们没有任何理由来证明自己的主张。让我们再深入一点。那么当你比较它们时会发生什么?

首先,逻辑上讲:

if(condition == false)

在这种情况下,if正在比较它所需要执行的值和括号之间的值,括号必须被计算出来。

if(!condition)

在这种情况下,if被直接与条件的相反(非)进行比较。所以不是2个比较,而是1个比较和1个 NOT 操作,这样更快。

当然,没有经过测试我是不会这么说的。下面是我所做的测试的一个快速截图。!condition的速度几乎是1000万次迭代的两倍。 Https://imgur.com/a/jrpvkmw

编辑: 我在 C # 中测试了这个,使用 Visual Studio 编译。有些编译器可能更聪明,并对其进行了适当的优化,这将使性能相同。