# 简介
Lambda
允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda
表达式可以使代码变的更加简洁紧凑。
以下是 lambda 表达式的重要特征:
- ** 可选类型声明:** 不需要声明参数类型,编译器可以统一识别参数值。
- ** 可选的参数圆括号:** 一个参数无需定义圆括号,但多个参数需要定义圆括号。
- ** 可选的大括号:** 如果主体包含了一个语句,就不需要使用大括号。
- ** 可选的返回关键字:** 如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
具体代码为
// 1. 不需要参数,返回值为 5 | |
() -> 5 | |
// 2. 接收一个参数 (数字类型), 返回其 2 倍的值 | |
x -> 2 * x | |
// 3. 接受 2 个参数 (数字), 并返回他们的差值 | |
(x, y) -> x – y | |
// 4. 接收 2 个 int 型整数,返回他们的和 | |
(int x, int y) -> x + y | |
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值 (看起来像是返回 void) | |
(String s) -> System.out.print(s) |
面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象。现实世界中,数据和行为并存,程序也是如此,因此这两种编程方式我们都得学。
# 主要内容
# 变量作用域
Lambda
使用的变量,必须被 final
修饰或者含有隐性 final
。同样的,变量在 Lambda
表达式中也不能被修改。
public static void main(String[] args) { | |
int n = 10; | |
// n = 9; | |
Runnable r = ()->{ System.out.println(n); }; | |
// n = 9; | |
//n 既不能在表达式中被修改,也不能在 Lambda 表达式之外被修改。 | |
// 总之,n 是不可修改的 | |
} |
# 方法引用
方法引用的可以简化 Lambda
表达式,但是在方法引用中不能有任何参数修改
构造引用
Student s = Student::new |
对象 **:😗* 实例方法
// public void forEach(Consumer<? super E> action) | |
//forEach 需要重写 Consumer 的 accept 方法 | |
list.forEach(n -> System.out.println(n)); | |
list.forEach(System.out::println); // 使用方法引用 | |
list.forEach((String s) -> System.out.println("*" + s + "*")); |
类名 **:😗* 静态方法
Stream<Double> stream = Stream.generate(Math::random); |
类名 **:😗* 实例方法
/* 这里如果使用第一句话,编译器会有提示: Can be replaced with Comparator.naturalOrder,这句话告诉我们 | |
String 已经重写了 compareTo () 方法,在这里写是多此一举,这里为什么这么写,是因为为了体现下面 | |
这句编译器的提示: Lambda can be replaced with method reference。好了,下面的这句就是改写成方法引用之后: | |
*/ | |
// TreeSet<String> set = new TreeSet<>((s1,s2) -> s1.compareTo(s2)); | |
TreeSet<String> set = new TreeSet<>(String::compareTo); |
# 注解 @FunctionInterface
@Documented | |
@Retention(RetentionPolicy.RUNTIME) | |
@Target(ElementType.TYPE) | |
public @interface FunctionalInterface{} |
该注解只能修饰接口。被 FunctionalInterface
注解修饰的接口,只能有一个抽象方法,被实现的方法必须被 defalut 修饰。
如果声明的方法和 java.lang.Object
中的某个方法一样,它可以不当做未实现的方法,不违背这个原则::一个被它注解的接口只能有一个抽象方法。
比如 java public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }
。
编译器会自动把满足 function interface
要求的接口自动识别为 function interface
,所以你才不需要对上面示例中的 ITest 接口增加 @FunctionInterface
注解。
# 内置四大函数接口
- 消费型接口:
Consumer< T> void accept(T t)
。
Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName); | |
greeter.accept(new Person("Luke", "Skywalker")); |
- 供给型接口:
Supplier < T> T get()
。
Supplier<Person> personSupplier = Person::new; | |
personSupplier.get(); // new Person |
- 断定型接口:
Predicate<T> boolean test(T t)
。返回值类型是固定的boolean
。
redicate<String> predicate = (s) -> s.length() > 0; | |
predicate.test("foo"); // true | |
Predicate<String> isEmpty = String::isEmpty; |
- 函数型接口:
Function<T,R> R apply(T t)
,有参有返回值的抽象方法。
Function<String, Integer> toInteger = Integer::valueOf; |
# 参考
菜鸟教程:https://www.runoob.com/java/java8-lambda-expressions.html
Java 全栈知识体系:https://pdai.tech/md/java/java8/java8-stream.html