先介绍下Lambda表达式,函数式接口会在穿插的例子后面介绍。
Lambda:允许把函数作为一个方法的参数(函数作为参数传递进方法中),Lambda表达式最终返回的是函数式接口的一个对象实例,因此需要依赖于函数式接口。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。
语法:
(parameters) -> expression
或
(parameters) ->{ statements; }
语法总共分为三部分
Lambda的四个特性:
函数式接口:只包含一个抽象方法的接口,这个抽象方法定义了这个接口的目标及用途,同时JAVA8中还引用了一个注解来标识函数式接口:@FunctionalInterface。
@FunctionalInterface:可以被在任何的函数式接口上,但是函数式接口不一定需要此注解。当使用@FunctionalInterface定义函数式接口时,如果在接口定义多个(非静态和非默认)方法,则会编译报错,但是有个例外:函数式接口中可以定义java.long.Object类中的所有方法,函数式接口中可以有多个静态方法和默认方法。
下面通过一些例子来介绍Lambda的标准写法及使用四个特性的简化写法。
先定义两个函数式接口:
//FunctionalInterface声明一个接口为函数式接口,此注解非必须
@FunctionalInterface
interface TestService {
int sum(int a,int b);
//java.long.Object的方法
boolean equals(Object obj);
//java.long.Object的方法
String toString();
//默认方法
default void getStr(String str){
System.out.println("str="+str);
}
//静态方法
static void getName(String name){
System.out.println("name="+name);
}
}
//此函数式接口不使用注解
interface BService {
void sum(String b);
}
Lambda的完整写法为
TestService testService = (int a, int b) -> {
return a * b *3;
};
System.out.println("testService result " + testService.sum(2,3));
输出为
testService result 18
使用特性a的写法
TestService testServiceA = (a, b) -> { return a * b *3; };
System.out.println("testServiceA result " + testServiceA.sum(2,3));
输出为
testServiceA result 18
使用特性b的写法
BService testServiceB = b -> { System.out.println("test B = " + b); };
testServiceB.sum("参数B");
输出为
test B = 参数B
使用特性c的写法
BService testServiceC = c -> System.out.println("test C = " + c);
testServiceC.sum("参数C");
输出为
test C = 参数C
使用特性d的写法
TestService testServiceD = (a, b) -> a * b *3;
System.out.println("testServiceD result " + testServiceD.sum(2,3));
输出为
testServiceD result 18
通过Lambda的四个特性我们基本把它的各种书写方式都描述了一下,但是没能很直观的描述出把函数作为一个方法的参数,因此再找个直观点的例子:
在java7中我们对集合排序通常是使用Collections的sort方法并且传入一个Comparator的对象实例,像这样写:
List list = Arrays.asList("a", "b", "d");
Collections.sort(list, new Comparator() {
public int compare(String o1, String o2) {
return (o2).compareTo(o1);
}
});
如果是在java8中,那就可以使用Lambda,像这样写:
List list = Arrays.asList("a", "b", "d");
Collections.sort(list,( e1, e2 ) -> e1.compareTo( e2 ));
这样是不是就能很直观的看到Lambda的用法。
至于函数式接口中是否使用注解@FunctionalInterface,则看具体使用场景。
如果使用注解@FunctionalInterface,在编写接口过程中如果有不符合函数式接口规范的地方就会直接编译报错
如果不使用注解@FunctionalInterface,在编写接口过程中即使有不符合函数式接口规范的地方也不会报错,只会在使用Lambda表达式的地方报错