在说一下Lambda
表达式之前,我们先了解下为什么java要引入
Lambda表达式
在java8 之前要将行为参数化我们有两种选择:
1.策略模式,根据参数传入的具体实现决定方法的实现
2.匿名内部类。
1的缺点是要新增新的行为必须创建新的行为并实现
接口;2的缺点是不得不写很多模板代码,可读性差。
引入Lambda 前提条件
在很多函数式
编程语言中允许将函数作为值,Java8也新增了这一特性,即允许方法作为值来传递,实现行为参数化。
在Java8之前筛选出隐藏文件可能需要这么做:
class="java" name="code"> File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isHidden();
}
Java8之后只需要这么做:
File[] hiddenFiles = new File(".").listFiles(File::isHidden);
其中File::isHidden被称为方法应用,只要在方法体中存在执行体,方法应用就可以传递代码。
Lambda——匿名函数
函数式编程的概念:编写把函数作为值来传递的程序。
add方法对两个int值进行求和写作: (int x,int y) -> x+y,这部分可替代写个工具类然后调用如: Math::add,这样写更为简介,也不需要编辑新的类。
Lambda特性:
1.匿名:lambda表达式是没有名字的
2.函数:为什么叫函数而不是方法呢,因为Lambda函数不像方法那样属于某个类。但和方法一样Lambda有参数列表、函数主体返回类型、抛出
异常。
3.传递:可作为值在方法参数中传递】
4.简洁
Lambda语法:
(parameters) ->
expression或 (parameters) -> { statements; }
从左往右 lambda表达式有 参数列表、箭头、和函数主体构成。
函数体中使用了花括号需要显式使用return 返回,不使用花括号则不需要return
关键字
函数式接口:
既然函数可作为值来传递那么肯定需要相应的规则,类似与我们把方法参数限定为指定接口类型一样,需要传递实现接口的类或者匿名内部类作为值,同样这里也按照规范定义了函数式接口,用来限定传递代码的参数和返回值(注意:Java8并没有引入函数这一类型)。
函数式接口与之前的接口区别就是只允许定义一个抽象方法(见下面),原因就不用多说了,都可以
理解,函数式接口中方法的签名被叫做Lambda表达式的签名,编译器会根据函数式接口的签名和上下文进行类型推断保证不会出现编译
错误,下面的是有效的。
Runnable a = () -> System.out.println(111);
a.run();
在Java8中类似Runnable、Comparable都是函数式接口。
@FunctionalInterface 注解
1、该注解只能标记在"有且仅有一个抽象方法"的接口上。
2、JDK8接口中的
静态方法和默认方法,都不算是抽象方法。
3、接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
4、该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响,类似@override。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
使用函数式接口
为了简化Java内置了常见的几种函数式接口Predicate<T>、Consumer<T>和Function<T,R>
Predicate有一个抽象方法test,输入为人意类型返回 boolean类型
Consumer有一个抽象方法accept,返回为空,输入为任意类型。
Function 有一个抽象方法返回为R类型输入为T类型。