如何解决如何在循环体内编写条件?
| 这可能有点主观,但实际上我正在寻找包含某些推理的答案。 对于循环体中的条件,我已经满足以下两种编程风格。这个:for (int i = 0; i < myArray.length; i++) {
if (myArray[i].isEmpty())
continue;
doSomeStuff();
doSomeMoreStuff();
}
还有这个:
for (int i = 0; i < myArray.length; i++) {
if (!myArray[i].isEmpty()) {
doSomeStuff();
doSomeMoreStuff();
}
}
我通常使用第一种样式,因为它使压痕级别保持理智,尤其是在存在多个条件的情况下。但是我开始怀疑第二个是否真的更干净。你有喜欢的风格吗,你能解释为什么吗?
更新:
这是一个更现实的示例。假设我正在读取这样的文件,例如\“名字:姓氏\”,例如:
John;Doe
Joe;Bloggs
这就是我将每行读入名称对象的方式,而忽略了空行(可能会发生):
while (line = file.readLine()) {
if (line.isEmpty())
continue;
String[] columns = line.split(\";\");
names.add(new Name(columns[0],columns[1]));
}
解决方法
事实是,第二种方法增加了圈复杂度,并可能导致箭头反图案。
另外,一开始就保留所有“代码不应通过此点”检查,就可以将它们组合在一起,这意味着它们更易于维护恕我直言。
,到目前为止,我更喜欢第二个,因为我发现它在语义上更易于阅读。
这使得重构更加容易。
,这很大程度上取决于实际代码的外观。如果它本质上是顺序的,那么我更喜欢满足条件的首字母ѭ4,如果它是分支的话,我会使用分支来跳过迭代;但是,如果嵌套层次太深,我可能会使用
continue
...如果您想要一个样式,并且始终在每个循环中使用它,那么我建议您使用第二个样式(分支),因为这种情况较少比continue
,它通常取决于条件。我试图避免条件否定,尤其是更复杂的条件。因此,我经常以第一种风格出现。在一开始就对特殊情况进行分类并不是一件坏事,这样一来,人们就可以一次性编写针对一般情况的算法。
,我使用continue
(有时在循环的中间使用break
或goto
),但始终将它们全部放在一行上(因此continue
不能偶然地与if
分开),并始终以“如果……”的形式提供注释\'重做。\”
注释是一个强大的工具。十个级别的缩进确实比这里和那里的ѭ9难读。某些控制流结构只是不会自己记录。
,只是重构。原因是如果MyObject为空,这是一个内部调用,它可以自问。没有理由让别人问MyObject是否为空,只是让MyObject做某事。这是属于MyObject的逻辑。您希望将逻辑尽可能多地放入对象中,以便可以被其他潜在的调用者重用,而且还可以使系统的其他部分不调用他们不拥有的对象。可以避免。
for(MyObject object : list) {
object.doABunchOfSimilarThings();
}
....
class MyObject {
...
public void doABunchOfSimilarThings() {
if(notEmpty()) {
doThing1();
doThing2();
doThing3();
}
}
...
}
,对我来说,这取决于循环的内容。
如果循环最多只包含5行和一个条件,那么我通常会使用第二种样式,因为我发现它使执行代码的确切时间变得容易一些。
如果有很多嵌套条件(没有else
),则我倾向于第一种语法,原因与您相同:防止大的缩进。使用第二种样式时,每个后续条件检查都不必要地增加了缩进级别,从而降低了可读性。
,继续,跳转,中断是认为我们不应该使用的第一句话。如果方法更长一点,您会发现自己是个坏主意。
第二课是尽可能使用积极的条件:)
,免责声明:这篇文章中的答案仅反映了回答者的想法,不应视为普遍共识。
对我来说,这与可读性有关。即使我能理解两个循环体,也有些人可能会花些时间来理解它们。
仅当数组中的元素不为空时第二个循环主体才执行,而第一个循环主体找到数组中的一个空元素并告诉for循环继续执行。
第二个循环的可读性也使对有意识的调试也很容易,就好像您告诉一个人,如果调用doSomeStuff()
或doSomeMoreStuff()
元素永远不能为空。
,第二个更好。尝试在编程时避免使用continue,break和goto(猛禽?)。他们只是拐杖。
,第二个。如果您获得许多缩进级别,则可以通过将块转换为单独的方法来进行重构。
,怎么样:
for (int i = 0; i < myArray.length; i++) {
doStuffToValue(myArray[i]);
}
void doStuffToValue(String value) {
if (value.isEmpty()) {
return;
}
doSomeStuff();
doSomeMoreStuff();
}
这样,您就可以将值的有效性作为方法而不是循环体的考虑。如果需要,您甚至可以为doStuffToValue方法编写单元测试。
,我不认为我曾经在循环中使用过continue
,尽管在函数开始时我经常将第一个习惯用法与ѭ19ѭ一起使用。在样式上明智的原因是continue
仅在需要跳过循环其余部分的上下文中起作用,而if
语句则与上下文无关。因此,ѭ11倾向于与代码的其他部分更加一致。
一个不太主观的原因是,如果您经常跳过整个循环迭代,通常可以使用一种方法来重构要在循环外部做出的决策,这会影响性能。对于您的示例,我更喜欢使用永远不会有空值的数据结构。
对于不可避免的复杂问题,而性能并不是问题,我倾向于使用Adriaan的将循环体分解为函数的方法。
在这三个原因中,语法上可能会出现continue
,最容易阅读,与使用该数据结构的其他代码保持一致的情况,并且性能最高的解决方案只是不够频繁地提出来以证明其使用是正确的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。