在学习 lambda 之前先来看一段代码,传入一个User的集合,返回符合条件的User集合
public static List<User> filter(List<User> users, Predicate<User> predicate) {
List<User> result = new ArrayList<>();
for (User user: users){
if (predicate.test(user)) result.add(user);
}
return result;
}
复制代码
代码中使用了 Predicate 接口, 接受一个泛型T,返回一个布尔值
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
复制代码
java7中,我们可以使用 匿名内部类 来作为入参来调用 filter 方法
public static List<User> filterZhang(List<User> users) {
return filter(users, new Predicate<User>() {
@Override
public boolean test(User user) {
return user.getName().startsWith("张");
}
});
}
复制代码
java8中,我们可以使用 lambda 来实现
public static List<User> filterWang(List<User> users) {
return filter(users, user -> user.getName().startsWith("王"));
}
复制代码
lambda其实是一个 箭头函数 ,也可称为 匿名函数 ,类似于 ES6 中的箭头函数,只不过javascript中使用 => , 而java中使用 ->
箭头操作符将lambda表达式分成了两部分:
抽象方法 抽象方法
上面说到的抽象方法,指的就是Predicate接口中唯一的一个抽象方法 test,接收一个泛型T,返回boolean值
boolean test(T t) 复制代码
再看看我们写的lambda表达式, 是不是接受一个泛型为User的user对象,如果user的姓王就返回true,反之返回false, 参数和返回值 一一对应
user -> user.getName().startsWith("王")
复制代码
所以 lambda箭头函数必须和 Predicate 接口中那个 唯一 的抽象方法保持一致(参数和返回值完全相同),正因为如此,lambda中会对参数类型进行 类型推断 , 我们只写了一个user, java就知道这是一个User对象
语法有如下几种格式:
() -> 具体实现 复制代码
(x) -> 具体实现 //或 x -> 具体实现 复制代码
(x,y) -> {具体实现}
复制代码
注:lambda表达式的参数列表的参数类型可以省略不写,可以进行 类型推断 。
函数式接口大部分定义在 java.util.function 包中, 且用 @FunctionalInterface 注解
需求:需要对两个数进行加减乘除等运算,怎么实现?
public static void main(String[] args) {
add(2,1);
minus(2,1);
multiply(2,1);
divide(2,1);
}
static int add(int left, int right) {
return left + right;
}
static int minus(int left, int right) {
return left - right;
}
static int multiply(int left, int right) {
return left * right;
}
static int divide(int left, int right) {
return left / right;
}
复制代码
public static void main(String[] args) {
calc(2, 1, (left, right) -> left + right);
calc(2, 1, (left, right) -> left - right);
calc(2, 1, (left, right) -> left * right);
calc(2, 1, (left, right) -> left / right);
}
static int calc(int left, int right, Calculate calculate) {
return calculate.applyAsInt(left, right);
}
@FunctionalInterface
interface Calculate {
int applyAsInt(int left, int right);
}
d
复制代码
所以用lambda的话,只需要定义一个函数式接口,不管进行什么操作,都可以用lambda解决,不用再一种运算对应一个方法。但是,还需要自己定义函数式接口,好像也没简单很多。Java考虑到这点了,所以内置了函数式接口, 大部分放在 java.util.function 包中, 接口用 @FunctionalInterface 注解。
如Predicate接口
在将lambda时举的例子,可以换成 方法引用 的写法
public static List<User> filterLi(List<User> users) {
return filter(users, Demo1::test);
}
// test 相当于 Predicat接口中抽象方法test的实现
private static boolean test(User user) {
return user.getName().startsWith("李");
}
复制代码