🍊 Java学习:Java从入门到精通总结
🍊 Spring系列推荐:Spring源码解析
📆 最近更新:2022年1月1日
🍊 个人简介:通信工程本硕💪、朝着优质博主努力🌕。我写的很慢,但敢保证每一篇都是用心写的,绝对不无聊,欢迎关注我共饮一杯鸡汤~
🍊 点赞 👍 收藏 ⭐留言 📝 都是我最大的动力!
豆瓣评分9.8的图书《Effective Java》,是当今世界顶尖高手Josh Bloch的著作,在我之前的文章里我也提到过,编程就像练武,既需要外在的武功招式(编程语言、工具、中间件等等),也需要修炼心法(设计模式、源码等等)学霸、学神OR开挂。
我也始终有一个观点:看视频跟着敲代码永远只是入门,从书籍里学到了多少东西才决定了你的上限。
我个人在Java领域也已经学习了近5年,在修炼“内功”的方面也通过各种途径接触到了一些编程规约,例如阿里巴巴的泰山版规约,在此基础下读这本书的时候仍是让我受到了很大的冲激,学习到了很多约定背后的细节问题,还有一些让我欣赏此书的点是,书中对于编程规约的解释让我感到十分受用,并愿意将他们应用在我的工作中,也提醒了我要把阅读JDK源码的任务提上日程。
最后想分享一下我个人目前的看法,内功修炼不像学习一个新的工具那么简单,其主旨在于踏实,深入探索底层原理的过程很缓慢并且是艰辛的,但一旦开悟,修为一定会突破瓶颈,达到更高的境界,这远远不是我通过一两篇博客就能学到的东西。
接下来就针对此书列举一下我的收获与思考。
不过还是要吐槽一下的是翻译版属实让人一言难尽,有些地方会有误导的效果,你比如java语言里extends是继承的关键字,书本中全部翻译成了扩展 就完全不是原来的意思了。所以建议有问题的地方对照英文原版进行语义上的理解。
没有时间读原作的同学可以参考我这篇文章。
文章目录
57 最小化局部变量的作用域
要使局部变量的作用域最小化,最好的方法是在首次使用的地方声明它。过早地声明局部变量可能导致其作用域不仅过早开始而且结束太晚。
每个局部变量声明都应该包含一个初始化表达式。这个规则的一个例外是try-catch语句。如果该值必须在try块之外使用,那么它必须在try块之前声明,此时它还不能被「合理地初始化」。
循环允许声明循环变量,将其作用域限制在需要它们的确切区域。如果循环终止后不需要循环变量的内容,那么优先选择for
循环而不是while
循环。
for (Element e : c) {
... // Do Something with e
}
如果需要访问迭代器,也许是为了调用它的remove
方法,首选的习惯用法,使用传统的for
循环代替for-each
循环:
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
Element e = i.next();
... // Do something with e and i
}
要了解为什么这些for循环优于while循环,考虑以下代码片段:
Iterator<Element> i = c.iterator();
while (i.hasNext()) {
doSomething(i.next());
}
...
Iterator<Element> i2 = c2.iterator();
while (i.hasNext()) {
// BUG!
doSomethingElse(i2.next());
}
第二个循环包含一个复制粘贴错误:它初始化一个新的循环变量i2
,但是使用旧的变量i
,不幸的是,它仍在作用域范围内。生成的代码编译时没有错误,并且在不抛出异常的情况下运行,但是它的逻辑已经错了。
如果将类似的复制粘贴错误与for循环(for-each循环或传统循环)结合使用,则生成的代码就无法编译。
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
Element e = i.next();
... // Do something with e and i
}
...
// Compile-time error - cannot find symbol i
for (Iterator<Element> i2 = c2.iterator(); i.hasNext(); ) {
Element e2 = i2.next();
... // Do something with e2 and i2
}
for循环比while循环还有一个优点:它更短,增强了可读性。
下面是另一种对局部变量的作用域最小化的循环做法:
for (int i = 0, n = expensiveComputation(); i < n; i++) {
... // Do something with i;
}
它有两个循环变量,i
和n
,它们都具有完全相同的作用域。第二个变量n
用于存储第一个变量的限定值,从而避免了每次迭代中冗余计算的代价。
最后一种“最小化局部变量作用域”的最终技术是保持方法小而集中。如果把两个操作(activities)合并到同一个方法中,与其中一个操作相关的局部变量就有可能会出现在执行另一个操作的代码范围之内。为了防止这种情况发生,只需将方法分为两个:每个操作用一个方法完成。
58 for-each循环优先于传统的for循环
下面是一个传统的for循环来遍历一个集合:
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
Element e = i.next();
... // Do something with e
}
下面是数组的传统for循环的实例:
for (int i = 0; i < a.length; i++) {
... // Do something with a[i]
}
它们并不完美。迭代器和索引变量都很混乱,好在for-each
循环解决了所有这些问题。它通过隐藏迭代器或索引变量来消除
混乱和出错的机会:
for (Element e : elements) {
... // Do something with e
}
此外,使用for-each
循环也不会降低性能
当涉及到嵌套迭代时,for-each循环相对于传统for循环的优势甚至更大。下面是人们在进行嵌套迭代时经
常犯的一个错误:
enum Suit {
CLUB, DIAMOND, HEART, SPADE }
enum Rank {
ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
NINE, TEN, JACK, QUEEN, KING }
...
static Collection<Suit> suits = Arrays.asList(Suit.values());
static Collection<Rank> ranks = Arrays.asList(Rank.values(