一,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实例