一,Lambda表达式

随着多核CPU和大数据的流行,为了写出在多核CPU上运行良好的程序
人们开发出了java.util.concurrent包和很多第三方类库,试图将并发抽象化

面对大型数据集合,java还欠缺高效的并行操作,开发者能够使用java8编写复杂的集合处理算法,让代码在多核CPU上高效运行,在语言层面上修改现有Java,Java8引入了Lambda表达式

使用Lambda表达式,是将复杂性抽象到类库的过程
使用全新的Stream API操作对象和集合类,方便写出简洁易读的并发代码,从而提升代码性能
比起复杂的线程安全代码,Lambda表达式只需学习一些新语法就能极大地降低开发时间和成本

面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象


二,初识Lambda表达式

命令式编程-将行为和按钮事件关联:

button.addActionListener(new ActionListener()){
	public void actionPerformed(ActionEvent event){
		System.out.println("hello Lambda")
	}
}
使用了匿名内部类注册监听,
为了调用一行逻辑不得不加上4行冗余的样板代码,影响代码的可读性
实际上,我们不想传入对象,只想传入行为

使用Lambda表达式-将行为和按钮事件关联:

button.addActionListener(event -> System.out.println("hello Lambda") )
传入一段没有函数名的代码块
event是参数名,
->将参数和Lambda表达式主体分开

对比:

传统写法使用匿名内部类来显式声明参数类型,
而在Lambda表达式中并没有需指定参数类型,程序依然可以编译,
这是因为javac会根据程序上下文推断出参数的类型,

这意味着,如果参数类型明确,就无需再显式指定

三,Lambda表达式举例

1,

Runnable noArgs = () -> System.out.println("hello Lambda");

空括号()表示无参数
2,

ActionListener noArg = event -> System.out.println("hello Lambda");

只有一个参数时,可省略参数的括号
3,

Runnable multistatement = () -> {
	System.out.println("hello Lambda");
	System.out.println("hello Lambda");
}

Lambda表达式主题是一段代码块,使用大括号{}将代码块括起来
代码块中可以return和抛出异常
只有一行代码的Lambda表达式可以省略大括号{}
4,

binaryOperator<Long> add = (x, y) -> x + y

以上代码并不是计算,而是创建一个函数,用来计算相加的结果
add的类型是binaryOperator,它不是两数的和,而是两数相加的那行代码

binaryOperator<Long> addExplicit = (Long x, Long y) -> x + y

Lambda表达式可以由编译器推断出参数的类型,也可以显式声明参数类型,此时需要小括号括起来


四,目标类型:

Lambda表达式可以赋值给局部变量也可以传递给方法作为参数
局部变量或参数的类型就是Lambda表达式的目标类型

Lambda表达式的类型依赖于上下文环境,可由编译器推断出来
例如Java初始化数组时,数组的类型就是根据上下文推断出来的
只有将null赋值给一个变量才能知道他的类型

final String[] array = { "hello", "Lambda" }

五,Lambda表达式的类型

Lambda表达式的类型:函数接口(只有一个抽象方法的接口)


六,类型推断:

java7引入了目标类型推断的拓展–菱形操作符,可以使javac推断出泛型参数的类型
例如:

Map<String, Integer> map = new HashMap<>();

变量map使用了菱形操作符,无需明确声明泛型类型,编译器就能推断出HashMap的泛型类型
前提是必须声明变量的泛型类型

Java8则可以省略Lambda表达式中的所有参数类型
javac根据Lambda表达式上下文信息就能推断出参数的正确类型
程序依然经过类型检查保证运行的安全性,但无需显式声明类型
这就是类型推断


七,类型推断举例-Predicate:

Predicate<Integer> atLeast5 = x -> x > 5

表达式x > 5是Lambda表达式的主体
返回值为Lambda表达式主体的值

public interface Predicate<T>{
	boolean test(T t);
}

Predicate有一个泛型参数,Lambda表达式实现了Predicate接口,因此它的单一参数被推断为Integer类型
javac还可以检查Lambda表达式的返回值是不是boolean,就是Predicate接口的方法返回值类型


七,类型推断举例-BinaryOperator:

该接口接受两个参数,返回一个值,参数和值的类型相同

BinaryOperator<Long> add = (x, y) - > x + y;

虽然类型推断系统可以推断出参数的类型,但若信息不够,虽然类型推断系统也无能为力
这是会报告编译错误

例如:

BinaryOperator add = (x, y) - > x + y;

此时编译器就会报错:

Operator '& #x002B;' cannot be applied to java.lang.Object, java.lang.Object

编译器认为参数和返回值都是java.lang.Object实例