命名块来限制variables范围:好主意?
多年来,我一直在使用命名块来限制临时variables的范围。 我从来没有在其他地方看到过这个,这让我怀疑这是不是一个好主意。 特别是因为Eclipse IDE默认将这些标记为警告。
我已经用我自己的代码来使用这个效果了。 但是由于好的程序员在看到它的时候会不信任它,所以我真的有两种方法可以从这里开始:
- 避免这样做,或者
- 促进它,希望它会成为一个成语。
示例(在更大的方法中):
final Date nextTuesday; initNextTuesday: { GregorianCalendar cal = new GregorianCalendar(); ... // About 5-10 lines of setting the calendar fields nextTuesday = cal.getTime(); }
在这里,我使用的是一个GregorianCalendar来初始化一个date,我想确保我不会意外地重用它。
有些人评论说,你实际上并不需要命名该块。 虽然这是真的,但原始块更像是一个错误,因为意图不清楚。 此外,命名的东西鼓励你思考块的意图。 这里的目标是识别不同部分的代码,而不是将每个临时variables赋给它自己的范围。
很多人评论说最好是直接采用小方法。 我同意这应该是你的第一本能。 但是,可能有几个缓解因素:
- 为了甚至考虑一个命名块,代码应该是短的,一次性的代码,永远不会在其他地方调用。
- 一个命名块是一个快速的方法来组织一个超大的方法,而不用创build一个十几个参数的一次性方法。 当一个课程处于不断变化之中时,情况尤其如此,而且input可能会随着版本的变化而变化。
- 创build一个新的方法鼓励重用,如果用例不完善,这可能是不明智的。 一个命名块更容易(至less在心理上)扔掉。
- 特别是对于unit testing,你可能需要为一次性断言定义十几个不同的对象,而且它们只是不同而已,你还不能find一种方法将它们合并成less数的方法,你也不能想办法将它们与不是一英里长的名称区分开来。
使用命名范围的优点:
- 不能意外重用临时variables
- 有限的范围给垃圾收集器和JIT编译器提供了关于程序员意图的更多信息
- 块名称提供了一个代码块的评论,我发现比开放式评论更可读
- 使代码从大方法重构成小方法变得更容易,反之亦然,因为命名块比非结构化代码更容易分离。
缺点:
不是惯用的:程序员谁也没有看到命名块的使用(即每个人,但我)认为这是错误的,因为他们无法find块名称的引用。 (就像Eclipse一样。)要成为一个惯用的东西是一场艰苦的战斗。
它可以作为不良编程习惯的借口,例如:
- 制定巨大的,单一的方法,其中几个小方法会更清晰。
- 压痕层太深,不易读取。
注意:基于一些深思熟虑的回答,我已经广泛地编辑了这个问题。 谢谢!
我只是直接重构成更小的方法。 如果一个方法足够大,需要像这样分解,如果可能的话,真的需要分解成多个方法。
虽然限制范围是好的,这不是真正的命名块是什么。 这是单一的,很less是一件好事。
如果这是不好的,那么为什么这是一种语言的function! 这是有目的的,你find了。
我经常按照你的例子编写代码。 当你想初始化一个variables时,需要做一些小小的计算来计算出应该是什么,并且涉及到一些variables……那么你不希望这些variables在整个范围内函数,那么包含初始化的一个小范围很好。
迷你示波器是将代码分解为“段落”的简单方法。 如果你分裂成方法,那么当这些方法不能从别的地方被调用,并且有一系列需要执行的顺序的时候,你可以使代码更难导航。
它总是一个平衡点,但如果你认为这将是最容易维护,它实际上增加了未来的代码读者的价值,如果它的所有内联,然后去。
没有硬性规定。 有的时候,我会有点厌倦,他们把所有的东西都放在自己的方法或者课堂上,这成为了一个噩梦。 有一个很好的平衡!
有时我使用未命名的块来隔离需要准备一些不可改变的东西的可变的东西。 我不把块放在不可变的variables声明下。
final String example; { final StringBuilder sb = new StringBuilder(); for(int i = 0; i < 100; i++) sb.append(i); example = sb.toString(); }
当我为这个块find其他用途时,或者只是认为这是阻碍,我把它变成一个方法。
使用块来限制范围是我书中的一个很好的技巧。
但是既然你使用标签来完成评论的工作,为什么不直接使用实际的评论呢? 这将消除有关未标注标签的混淆。
这是我第一次看到其他人使用块。 噢! 我以为我是唯一的一个。 我知道我没有发明它 – 记得在某处读过它 – 可能来自我以前的C ++世界。
我不使用标签,但只是评论我在做什么。
我不同意那些要求你把它提取成方法的人。 我们在这样的块中所做的大部分事情并不是真正的可重用块。 这是有道理的一个大的初始化和是的,我已经使用块来防止复制/粘贴错误。
BR,
〜一
如果你有5到10行的代码可以安全地放到这样的块中,那么相同的代码也可以被提取到一个方法中。
这看起来似乎只是一种语义上的差异,但至less在解压缩到一种方法后,您将获得重用能力的好处。
仅仅因为它们存在并不意味着它们应该被使用。 通过使用新的私有方法可以更好地获得使用命名块获得的大部分优点。
- 您将无法使用新方法中声明的临时variables
- GC和JIT编译器将通过使用新方法收集相同的信息
- 使用新方法的描述性名称(在您的情况下使用“private Date initNextTuesday()”)将允许自我评论代码优势
- 当你已经“预先考虑”它时,不需要重构代码
除了这些好处之外,您还可以获得代码重用的好处,并且可以缩短长时间的方法。
我会使用一个评论块,而不是在那里添加一个标签。
当我看到一个标签时,我不能认为没有别的东西在引用这个块。
如果我改变块的行为,那么标签名称可能不再合适。 但是我不能只是伸出手去改变它:我将不得不查看剩余的方法来确定标签正在调用哪个标签。 在这一点上,我会发现这是一个未被引用的标签。
在这个例子中使用注释更清晰,因为它描述了块的行为,而不需要维护者的任何额外的工作。
这是我书中的一个很好的技巧。 pipe理大量的一次性使用方法是邪恶的,你提供给块命名的原因是很好的。
生成的字节码是什么样的? 那将是我唯一的犹豫。 我怀疑它删除块名称,甚至可能从更大的优化中受益。 但是你必须检查。
对不起复活这个,但我没有看到任何人提到我认为是非常重要的一点。 让我们看看你的例子:
final Date nextTuesday; initNextTuesday: { GregorianCalendar cal = new GregorianCalendar(); ... // About 5-10 lines of setting the calendar fields nextTuesday = cal.getTime(); }
在这里包含这个初始化逻辑可以让你更容易理解你是否从上到下阅读文件,关心每一行。 但是想想你如何阅读代码。 你是否从文件顶部开始阅读并继续阅读? 当然不是! 你唯一能做的就是在代码审查期间。 相反,根据以前的知识,堆栈跟踪等,您可能有一个起点。然后,通过执行path进一步向下/向上钻取,直到find所需内容。 根据执行path优化阅读,而不是代码评论。
阅读nextTuesday
使用的代码的人是否真的想了解它是如何初始化的? 我会争辩说,他们需要的唯一信息是下个星期二对应的Date
。 所有这些信息都包含在其声明中。 这是一个应该被分解成私有方法的代码的完美例子,因为不需要理解读者关心的逻辑 。
final Date nextTuesday; initNextTuesday: { GregorianCalendar cal = new GregorianCalendar(); //1 //2 //3 //4 //5 nextTuesday = cal.getTime(); }
VS:
final Date nextTuesday = getNextTuesday();
您希望在通过模块的途中读到哪一个?
名称块帮助:使用break作为转到的forms
使用rest作为一个文明的formsgoto。
class Break { public static void main(String args[]) { boolean t = true; first: { second: { third: { System.out.println("Before the break."); if (t) break second; // break out of second block System.out.println("This won't execute"); } System.out.println("This won't execute"); } System.out.println("This is after second block."); } } }
使用break从嵌套循环中退出
class BreakLoop4 { public static void main(String args[]) { outer: for (int i = 0; i < 3; i++) { System.out.print("Pass " + i + ": "); for (int j = 0; j < 100; j++) { if (j == 10) break outer; // exit both loops System.out.print(j + " "); } System.out.println("This will not print"); } System.out.println("Loops complete."); } }
来源链接
我已经在我的一些C#中做到了这一点。 我不知道你可以命名块,但我不得不尝试,看看它是否也可以在C#中使用。
我认为范围块可以是一个好主意,因为你可以在代码块中封装特定于代码的代码,在那里你可能不想把代码分割成它自己的函数。
至于嵌套它们的缺点,我发现程序员更多的不是范围块本身。
这里命名的范围在技术上是可以的,只是它们不是经常以这种方式使用。 因此,当别人来维护你的代码时,可能不会马上明白为什么他们在那里。 恕我直言,一个私人帮手方法将是一个更好的select…
我喜欢用block来限制var scope。 很多时候我被短暂的变化所困扰,因为这些变化很大,应该在使用后马上消失。 很长的方法+许多非最终的variables使得很难推断编码者的意图,尤其是在评论很less的情况下。 考虑到我在方法中看到的大部分逻辑如下所示
Type foo(args..){ declare ret ... make temp vars to add information on ret ... make some more temp vars to add info on ret. not much related to above code. but previously declared vars are still alive ... return ret }
如果增值税的范围比整个方法体小,我可以很快忘记其中的大部分(好东西)。
我也同意太多或太less的私人事物导致意大利面代码。
其实我想找的东西就像在函数式语言中的嵌套方法,似乎它在Java中的表亲是{ BLOCK }(内部类和labmdaexpression式不是这个..)。
不过,我宁愿使用未命名的块,因为这可能会误导人们试图find对标签的引用,加上我可以用注释块更好地解释。
对于使用私有方法,我将其视为使用块的下一步。