1.什么是Lambda表达式?
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。
2.使用Lambda的限制条件
Lambda并不是任何地方都可以使用,Lambda表达式需要“函数式接口”的支持。
3.什么是函数式接口?
接口中只有一个抽象方法的接口,称为函数式接口,可以用@FunctionalInterface修饰一下,这里需要注意的是:未使用 @FunctionalInterfaces注解的接口未必就不是函数式接口,一个接口是不是函数式接口的条件只有一条,即接口中只有一个抽象方法的接口(Object类中的方法不算)。而使用@FunctionalInterface注解修饰了的接口就一定是函数式接口,添加@FunctionalInterface注解可以帮助我们检查是否是函数式接口。
函数式接口(Functional Interface)是java8新增的特性,它是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为lambda表达式。
JDK中常见的函数式接口有:
package java.lang; @FunctionalInterface public interface Runnable { void run(); }
package java.util.concurrent; @FunctionalInterface public interface Callable<V> { V call() throws Exception; }
4.lambda表达式基础语法
java中,引入了一个新的操作符“->”,该操作符在很多资料中,称为箭头操作符,或者lambda操作符;箭头操作符将lambda分成了两个部分:
左侧:lambda表达式的参数列表
右侧:lambda表达式中所需要执行的功能,即lambda函数体
以下是lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
4.1 无参数,无返回值
() -> System.out.println("hello lambda");
Runnable r = new Runnable() { @Override public void run() { System.out.println("hello runnable"); } }; r.run(); Runnable r1 = () -> System.out.println("hello lambda"); r1.run();
此时,如果右边的代码简单,只有一行代码时,{}可以省略。
4.2 有一个参数,无返回值
public class CalculatorTest { public void print(Consumer<String> msg) { System.out.println(msg); } public void doPrint(String msg) { print((str) -> System.out.println(msg)); print(str -> System.out.println(msg)); // 简写 } }
此时,左边的()可以省略。
4.3 有两个参数,Lambda体内只有一条语句,且有返回值,return可省略
public void test3() { BinaryOperator<Integer> binary = (x, y) -> x + y; System.out.println(binary.apply(1, 2));// 3 }
4.4 多个参数,多行语句
public void test4() { // 无返回值lambda函数体中用法 Runnable r1 = () -> { System.out.println("hello lambda1"); System.out.println("hello lambda2"); System.out.println("hello lambda3"); }; r1.run(); // 有返回值lambda函数体中用法 BinaryOperator<Integer> binary = (x, y) -> { int a = x * 2; int b = y + 2; return a + b; }; System.out.println(binary.apply(1, 2));// 6 }
5.典型函数式接口的使用
Consumer<T> : 消费型接口(无返回值,有去无回) void accept(T t); Supplier<T> : 供给型接口 T get(); Function<T,R> : 函数型接口 R apply(T t); Predicate<T> : 断言型接口 boolean test(T t); 四大核心接口的-->扩展子接口
Predicate接口适合用于过滤,测试对象是否符合某个条件,Predicate接口源码如下:
@FunctionalInterface public interface Predicate<T> { boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate() { return (t) -> !test(t); } default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
可以看到,Predicate接口待实现的唯一抽象方法是 boolean test(T t) 方法。我们用Predicate接口实现从整数型数组中过滤正数:
public static void main(String[] args) { List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5); filter(numbers, n -> n > 0); } public static void filter(List<Integer> numbers, Predicate<Integer> condition) { for (Integer number : numbers) { if (condition.test(number)) { System.out.println("Eligible number: " + number); } } }
运行结果如下:
Eligible number: 4
Eligible number: 5
对数组的迭代,还可以使用Stream API的方式:
public static void main(String[] args) { List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5); numbers.stream().filter(n -> n > 0).forEach(n -> System.out.println("Eligible number: " + n)); }
参考文献:https://www.jianshu.com/p/8d7f98116693
https://www.cnblogs.com/wuhenzhidu/p/lambda.html
https://blog.csdn.net/qq_28410283/article/details/80961022
https://www.runoob.com/java/java8-lambda-expressions.html