第一章 为什么要关心Java 8
- 语言面临“要么改变,要么衰亡”的压力,工程师面临“要么持续学习,要么淘汰”的压力
- 现有的Java编程实践并不能很好地利用多核处理器(问:Java 8是如何更好的利用多核处理的?)
Java8 新增的Lambda、Sream、Optional等新概念和功能,能够方便我们编写既简洁又高效的程序
第二章 通过行为参数化传递代码
行为(方法/代码)参数化:就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成不同行为的能力,可让代码更好的适应不断变化的要求。
优化策略模式
public interface Strategy {
int doOperation(int num1, int num2);
}
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationSubstract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
// 传统策略方式实现,弊端,每个策略对应一个策略类
@Test
public void traditionalStrategyPatternTest() {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubstract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
// 使用行为参数化的方式进行优化,只需依赖两个即可实现,具体的策略转化为行为参数,避免策略过多引起的策略类爆炸问题
@Test
public void behavioralParamsStrategyPatternTest() {
Context context = new Context(((num1, num2) -> num1 + num2));
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(((num1, num2) -> num1 - num2));
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(((num1, num2) -> num1 * num2));
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
// 匿名内部类同样页可实现类似上述的需求,但相对于行为参数化来说更加啰嗦,不够简洁
第三章 Lambda表达式
- Lambda:可理解为简洁的表示可传递的匿名函数的一种方式,它没有名称,但有参数列表、函数主题、返回类型、还可包含一个可抛出的异常列表
- Lambda构成:Lambda由参数列表、尖头(->)、主体组成
- 基本语法
(parameters) -> expression
// 或
(parameters) -> {expression;}
示例:
(Integer number1,Integer number2) -> number1+number2
- 使用方式:可以在任何函数式接口上使用lambda表达式
- 函数式接口定义:只定义了一个抽象方法的接口
- 环绕执行模式:反向AOP,AOP是在业务逻辑之外增加切点切面,执行诸如日志记录,事务控制等操作,而环绕执行则是在“切点”,“切面”定义好的情况下,执行不同的业务逻辑。
示意图:
如业务需求为读取某个资源之前,需要初始化相关的资源,读取之后,需要关闭对应的资源
伪代码如下:
interface Reader{
void reader();
}
public void read(Reader reader){
// 读取之前的准备操作
preSomething();
// 执行读取
reader();
closeSomething();
}
public static void main(String[] args){
read(System.out.println("读取xxxx.file"));
read(System.out.println("读取xxxx.sql"));
read(System.out.println("读取xxxx.hd"));
}
- 类型检查:上下文
- 类型推断:上下文
- 使用局部变量:局部变量必须显示的声明为final,如在表达式中使用了局部变量,并对局部变量进行了二次赋值,则会编译报错(原因:实例变量存储在堆中,局部变量在栈中)
- 方法引用:可以重复使用现有的方法定义,并像lambda一样传递,可看作调用特定方法的Lambda的一种快捷调用方式,相当于Lambda的语法糖
示例
List<Integer> integers = Arrays.asList(23, 123, 4, 5, 6);
// lambda 方式
integers.forEach(a->System.out.println(a));
// 方法引用
integers.forEach(System.out::println);
方法引用的分类:
- 类名指向静态方法的引用
- 类名指向任意类型实例方法的方法引用
- 指向现有对象的实例方法的方法引用
总结:
函数式编程相对于指令式编程,函数式编程只需要指出希望的结果-“做什么”,而不用操心执行的步骤-“如何做”