java8新增了一个强大的特性——函数式编程。在之前的java版本中无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法,而lambda表达式就是为了解决这种问题。
在将函数作为一等公民的语言中,lambda表达式的类型是函数,但在java中,lambda表达式是对象,必须依附于特别的对象类型——函数式接口类型。
lambda表达式是函数式编程的核心,本质是一个匿名函数,是一段没有函数名的函数体。长相如下:
(param1,param2,param3)->{ };
lambda表达式本质是对象,是函数式接口内抽象方法的实现。lambda表达式是什么类型必须要通过上下文来断定,也就是是说如果只有( )->{ },编译器并不能知道这个lambda表达式是什么类型的。
java8为使用者提供了许多的API,有了这些API我们就可以使用lambda表达式,从而实现函数式编程。
Consumer是一个interface,它被一个@FunctionalInterface注解所标注,
这是一个表示函数式接口的注解,函数式接口:一个接口里,有且只有一个抽象方法,即为函数式接口。函数式接口的实例可以通过lambda表达式来创建,通过方法引用来创建,通过构造方法引用来创建。
该接口有一个普通的方法和一个默认(default)的方法,默认方法按下不表,先说普通的这个方法。
void accept(T t);
这是个没有返回值,但有一个参数的方法。
java8以前我们逐个打印集合里的所有数据会这样写:
public static void main(String[] args) {List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);for (Integer i : list) {System.out.println(i);}}
如果使用lambda写法:
public static void main(String[] args) {List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);list.forEach(i-> System.out.println(i));}
两个程序的运行结果是一样的,并且可以发现第二个程序的第3行和之前说的lambda表达式的样子一样,这就是lambda写法,而此处的lambda写法应用了Consumer这个接口。
此处的关键在于forEach()这个方法,这个方法是Iterable接口的一个默认方法,源码长相如下:
default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for (T t : this) {action.accept(t);}}
等会,有方法体的方法怎么能出现在接口中呢?这也是是java8的一个新特性,只要在接口方法前加一个default就可以有方法体。并且如果有一个接口有defult方法,所有实现了这个接口的实现类就自然而然继承了这个方法
我们看到这个方法体其实就明白了为什么之前那两个例子执行的结果是一样的,因为他们其实本质都是对集合进行了for循环。
并且观察forEach()方法的源码可以发现,它接收Consumer接口类型作为参数,也就是我们自己写的代码:
i-> System.out.println(i)
上面已经说过,函数式接口的实例可以通过lambda表达式来创建,通过方法引用来创建,通过构造方法引用来创建。所以其实这里的传递的lambda表达式就是Consumer接口实例。
据此我们可发现,lambda表达式或者说函数式编程是定义了一种行为,具有更高层次的抽象,方法与方法之间传递参数的时候不再是传递某个值,而是传递行为。




