如果有条件,则返回set.add()的布尔值?


15

set类的add运算符返回一个布尔值,如果元素(要添加的元素)不存在则为true,否则为false。在写字

if (set.add(entry)) {
    //do some more stuff
}

在编写简洁的代码方面被认为是好的风格?我想知道既然您一次执行两项操作。1)添加元素,2)检查元素是否存在。


6
您正在谈论的是standard java.util.Set,它add在元素不存在时返回true ,对吧?
user2357112支持Monica's

1
我通常会考虑相反的测试:if (!set.add(entry)) {// entry already present, possibly a case you want to handle}
njzk2

一次做两件事有什么问题吗?
user207421 '17

@ user2357112是的,没错。
安德烈亚斯·布劳恩

Answers:


19

是的。

使操作返回布尔值的通常点是,您可以使用它来进行决策,即在if构造内。您可以意识到这种潜力的唯一另一种方法是将返回值存储在变量中,然后立即在中使用它if,这很愚蠢,而且肯定不比编写任何方式可取if(operation()) { ... }。因此,只要继续执行此操作,我们就不会(因此)判断您。


感谢您的回答。正如@Niels vanReijmersdal在他的答案中指出的那样,这样做破坏了命令和查询的分离,不是吗?您不认为那很重要吗?
安德烈亚斯·布劳恩

4
@AndreasBraun我个人认为命令查询分离是愚蠢的。一种方法既执行动作又返回与该动作相关的值通常是合乎逻辑的。在两者之间强制人为分离会导致不必要的冗长代码。

1
@ dan1111:的确如此。此外,“命令和查询分离”导致“先检查后行动”和类似的反模式,这可能会在多线程上下文中中断。当世界其他地方试图同时为健壮和高效的SMP解决方案建立原子融合操作时,宣传这种分离是很奇怪的……
Holger

2
@JörgW Mittag:第759页是什么?由于原子操作本质上不受“先检查后行动”反模式的影响,因此将其拆分为阅读完整内容的“整个章节”,如何使构造线程安全无济于事。再次。由于您没有命名任何实际参数,因此我没有“对这些参数的特定异议”。
Holger

1
@JörgW Mittag:好吧,我正在谈论此页面上的答案,不鼓励使用Set.add单个操作而不使用其他方法。如果预期的操作是添加单个元素并确定是否已添加,则不需要更强大的替代方案,而该替代方案仍会使操作复杂而无益。希望您知道这Set.add是一种内置的JRE方法,无需先学习700页以上的书即可使用。
Holger

12

我会说它不是尽可能干净,因为它迫使维护者已经知道或查找返回值的含义。这是否意味着已经成功插入了不存在的值?如果您不经常使用它,您将不会知道,即使这样做,也要花很多心思。

我希望以下内容:

boolean added = set.add(entry);

if (added) {
    //do some more stuff
}

是的,有点冗长,但是编译器应该生成几乎完全相同的字节码,即使多年未使用Java集的人也可以遵循逻辑而无需查找任何内容。



9
查找方法比尝试了解原始开发人员对使用该方法的范围之外声明的冗余变量的意图要少。在所有现代Java IDE中,开发人员都可以将鼠标指针悬停在某个方法上,并立即访问其文档。优秀的开发人员在使用任何不熟悉的API时都会不断地这样做。
凯文·克鲁姆维德

9
我第二个@Holger。如果您不知道Set.add,那么您是没有经验的人,应该通过这些方法来学习它们并变得更有经验。
恢复莫妮卡

7
notAlreadyPresent不是最好的措辞。我将使用added,并希望读者知道为什么不将值添加到Set中。
njzk2

3
@JustinTime:使用注释来描述代码的作用被广泛认为是不好的做法。您的代码应该是自描述的。在代码审查中,我将您的示例标记为不可接受。
BlueRaja-Danny Pflughoeft

8

如果为true表示成功,那么这是很好的清晰代码。

有一个普遍的约定,即函数或方法在成功时返回true(或某些结果为true)。只要您的代码遵循该规则,我认为将方法置于条件中就可以了。

在我看来,这样的代码不必要地混乱了:

boolean frobulate_succeeded = thing.frobulate();

if (frobulate_succeeded) {
    ...
}

感觉就像您在重复自己。

但是,问题在于返回值的含义。您说“一个布尔值,它指示添加的元素是否已经存在”,这可能意味着true表示该元素存在(并且未发生添加)。如果真是这样,我理想上将方法的返回行为更改为更常规。如果不可能,我将添加一个额外的中间变量,该变量使您可以在代码中清楚地标记返回结果(如其他人所建议)。


将项目添加到集合中,成功意味着什么?不抛出异常意味着成功。真与假意味着在这种情况下更具体。
恢复莫妮卡

@ Solomonoff'sSecret在这种情况下,异常意味着该集合拒绝添加该元素,这false意味着未添加该元素是因为该元素已经被包含,并且true意味着该元素尚未被包含。add()如果该元素尚未包含在集合中,则As 将其添加到集合中,true因此意味着该元素已成功添加到集合中。
贾斯汀时间-恢复莫妮卡

@JustinTime您将对这两种情况添加自己的价值判断。另一种解释是成功是当方法返回时,该项目位于集合中。如果项目已经在集合中,则add无需执行任何操作即可成功。如果该商品尚未在集合中,则将其add添加到集合中即可成功。哪种解释正确是任意的。从语言中可以看出,对成功的定义不太那么随意:如果该方法正常返回,则该方法成功。
恢复莫妮卡

1
对成功的最起码的任意定义是,该方法成功执行了它打算执行的任务。如果我有一个方法firstLessThanSecond(int l, int r),并且返回trueif l > rfalseif l <= r,则该方法即使成功返回也不会成功。
贾斯汀时间-恢复莫妮卡

1
@JustinTime add是合同的缩写。文档开始于“将指定的元素添加到该集合中(如果尚不存在)”,无论该项目是否已经存在于集合中,这都可以满足。您可以随意解释返回值,但最终只是您的解释。在第二个示例中,该方法评估条件是否为真。如果条件为假,则该方法当然不会失败,因为它已成功评估了条件。
恢复莫妮卡

2

我会说这非常像C。在大多数情况下,我希望使用一个描述性名称的变量来表示突变结果,并且在某种if情况下不会发生突变。

如果立即重用此变量,则编译器将消除该变量。人类将更容易阅读源代码。对我来说,这更重要。

如果有人必须通过在if条件中添加and/ or子句来扩展条件,则.add()由于短路评估,在某些情况下,他们可能最终不会调用。除非特别预计会发生短路,否则可能会导致错误。


如果我写if (set.contains(entry)){set.add(entry); //do more stuff}的话,编译器也消除了吗?
安德烈亚斯·布劳恩

1
@AndreasBraun:我不这么认为。编译器不了解contains和之间的语义链接add。此外,它还可以完成entry在集合中查找的双重工作。这对于很大的集合和非常轻的循环可能会起作用。
9000

1
因此,我认为您宁愿不写if (set.contains(entry)){set.add(entry); //do more stuff}而是改用卡尔·比勒费尔特的答案?
安德烈亚斯·布劳恩

@AndreasBraun:完全是(支持该答案)。
9000

1
好点。ifs中的突变非常棘手,因为将来的开发人员可能还会遇到其他短路情况。
njzk2

0

您的代码似乎破坏了命令查询分离清洁代码书功能结构视频中对此进行了讨论。因此,从“简洁代码”的角度来看,我认为它不是好样式。

“干净的代码既简单又直接。干净的代码读起来像写得很好的散文。简洁的代码永远不会掩盖设计者的意图,而是充满清晰的抽象和直接的控制线。

-Grady Booch的《面向对象的分析和应用程序设计》一书的作者”

对我来说,您代码的意图尚不清楚。如果在添加条目成功时成功执行了if,或者在已经存在时成功执行了if操作?什么add()回报?该项目?错误代码?


2
好吧,是的,这也是我的想法。但是我也认为@Kilian Foth有一点。如果我想分开查询和命令,那我不得不写些if (set.contains(entry)){set.add(entry); //do more stuff}看起来很傻的东西。您对此有何看法?
安德烈亚斯·布劳恩

我不知道此代码的域和上下文来建议一个好名字,但我会将其包装在一个功能明确的函数中。例如:didEntryExistOrCreateEntry(entry),它可以包含您的contains()+ add()逻辑并返回一个布尔值。这里有类似的问题:softwareengineering.stackexchange.com/questions/149708/…,它在干净的代码之外讨论了这种做法。
Niels van Reijmersdal

6
我认为命令查询分隔规则是愚蠢的,尤其是应用于这样的情况时,其中方法既执行操作又返回操作的成功状态。但是,您也不会解释规则是什么,也不会提供太多理由。由于这些原因而被否决。

1
“ add()返回什么?” 我希望任何进行代码审查的Java开发人员都知道该Collectionapi。
njzk2

3
同意@ dan1111。它之所以特别愚蠢,是因为它为比赛条件提供了肥沃的土壤。
Paul Draper
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.