🍊 Java学习:Java从入门到精通总结
🍊 Spring系列推荐:Spring源码解析
📆 最近更新:2021年12月16日
🍊 个人简介:通信工程本硕💪、阿里新晋猿同学🌕。我的故事充满机遇、挑战与翻盘,欢迎关注作者来共饮一杯鸡汤
🍊 点赞 👍 收藏 ⭐留言 📝 都是我最大的动力!
豆瓣评分9.8的图书《Effective Java》,是当今世界顶尖高手Josh Bloch的著作,在我之前的文章里我也提到过,编程就像练武,既需要外在的武功招式(编程语言、工具、中间件等等),也需要修炼心法(设计模式、源码等等)学霸、学神OR开挂。
我也始终有一个观点:看视频跟着敲代码永远只是入门,从书籍里学到了多少东西才决定了你的上限。
我个人在Java领域也已经学习了近5年,在修炼“内功”的方面也通过各种途径接触到了一些编程规约,例如阿里巴巴的泰山版规约,在此基础下读这本书的时候仍是让我受到了很大的冲激,学习到了很多约定背后的细节问题,还有一些让我欣赏此书的点是,书中对于编程规约的解释让我感到十分受用,并愿意将他们应用在我的工作中,也提醒了我要把阅读JDK源码的任务提上日程。
最后想分享一下我个人目前的看法,内功修炼不像学习一个新的工具那么简单,其主旨在于踏实,深入探索底层原理的过程很缓慢并且是艰辛的,但一旦开悟,修为一定会突破瓶颈,达到更高的境界,这远远不是我通过一两篇博客就能学到的东西。
接下来就针对此书列举一下我的收获与思考。
不过还是要吐槽一下的是翻译版属实让人一言难尽,有些地方会有误导的效果,你比如java语言里extends是继承的关键字,书本中全部翻译成了扩展 就完全不是原来的意思了。所以建议有问题的地方对照英文原版进行语义上的理解。
没有时间读原作的同学可以参考我这篇文章。
文章目录
42 Lambda优先于匿名类
自从JDK 1.1于1997年发布以来,创建函数对象的主要手段就是匿名类。下面代码是按照字符串⻓度顺序对列表进行排序,使用匿名类创建排序的比较方法:
Collections.sort(words, new Comparator<String>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
匿名类适用于需要函数对象的经典面向对象设计模式,特别是策略模式。Comparator
接口代表一种排序的抽象策略;上面的匿名类是排序字符串的具体策略。
在Java 8中,“带有单个抽象方法的接口”是特殊的,他们被称作函数式接口,Java允许利用Lambda表达式创建这些接口的实例。
Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));
Lambda的类型是Comparator <String>
,其参数s1,s2的类型是String,返回值类型int全都没有出现在代码里
编译器使用一个叫类型推断的过程从上下文中推断出这些类型。
如果编译器产生错误消息,无法推断出Lambda参数的类型,那就手动指定它。
如果用Lambda表达式代替Comparator
的构造方法,代码会更加简练:
Collections.sort(words, comparingInt(String::length));
如果用Java 8中List接口里的sort方法,代码还可以更简洁:
words.sort(comparingInt(String::length));
Java中增加了Lambda之后,使得之前不能使用函数对象的地方现在也能用了。例如,以34条里的Operation
枚举类型为例:
public enum Operation {
PLUS("+") {
public double apply(double x, double y) {
return x + y;
}
},
MINUS("-") {
public double apply(double x, double y) {
return x - y;
}
},
TIMES("*") {
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE("/") {
public double apply(double x, double y) {
return x / y;
}
};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
public abstract double apply(double x, double y);
}
使用Lambda改造的话,只要给每个枚举常量的构造器传递一个实现其行为的Lambda即可:
public enum Operation {
PLUS("+", (x, y) -> x + y),
MINUS("-", (x, y) -> x - y),
TIMES("*", (x, y) -> x * y),
DIVIDE("/", (x, y) -> x / y);
private final String symbol;
private final DoubleBinaryOperator op;
Operation(String symbol, DoubleBinaryOperator op) {
this.symbol = symbol;
this.op = op;
}
@Override
public String toString() {
return symbol;
}
public double apply(double x, double y) {
return op.applyAsDouble(x, y);
}
}
构造方法将Lambda存储在实例属性中,apply
方法将调用转发给Lambda,代码量更少,逻辑也更清晰。
使用Lambda需要注意的地方是:Lambda没有名称和文档;如果计算比较复杂,或者代码量超过几行,就不要用Lambda了。
Lambda表达式一行是最好的,三行是极限!不能再多了
传递给枚举构造方法的参数是在静态环境中计算的。因此,枚举构造方法中的Lambda表达式不能访问枚举的实例成员。如果枚举类型具有难以理解的特殊方法,使用原先的实现方式仍是首选。
匿名类在Lambda时代并未过时,可以依据以下几点来进行选择:
1. 如果想创建抽象类的实例,可以用匿名类来完成
2. 如果一个接口有多个抽象方法,创建实例要用匿名类
3. Lambda无法获得对自身的引用
在Lambda中,关键字this指向外围实例,这通常是我们想要的
不要序列化一个 Lambda 或 匿名类实例,如果想要可序列化的函数对象,如Comparator
,就使用私有静态嵌套类的实例。
43 方法引用优先于Lambda
如果方法引用看起来更简短更清晰,就用方法引用;否则还是用Lambda
Java提供了一种生成函数对象的方法,比lambda还要简洁&#x