一 、Lambda表达式前瞻知识
什么是Lambda表达式?
可以将Lambda表达式理解为一个匿名函数; Lambda表达式允许将一个函数作为另外一个函数的参数; 我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码作为实参),也可以理解为函数式编程,将一个函数作为参数进行传递。
为什么要引入Lambda表达式?
Lambda表达式能够让程序员的编程更加高效
lambda表达式和方法引用使用前提:函数式接口
1.@FunctionalInterface 语法格式严格要求当前接口有且只能有一个尚未完成的缺省属性为 public abstract 修饰方法。
2.函数式接口一般用于方法的增强,直接作为方法的参数,实现函数式编程。
只有函数式接口的变量或者是函数式接口,才能够赋值为Lambda表达式。这个接口中,可以有默认方法,或者是静态方法。
二、Lambda表达式
1.Lambda表达式的基本语法
([Lambda参数列表,即形参列表]) -> {Lambda体,即方法体}
1.Lambda 表达式关注的是接口中方法的返回值和参数,方法名不重要
2.使用 "->"将参数和实现逻辑分离;( ) 中的部分是需要传入Lambda体中的参数;{ } 中部分,接收来自 ( ) 中的参数,完成一定的功能。
3.只有函数式接口的变量或者是函数式接口,才能够赋值为Lambda表达式。这个接口中,可以有默认方法,或者是静态方法。
2.四种lambda表达式
//接口设计
@FunctionalInterface
interface A {
void 方法名真的没有用();
}
//方法设计
public static void testLambda(A a) {
a.方法名真的没有用();
}
//代码实现
public static void main(String[] args) {
//1.匿名内部类方法
//接口无法实例化,这里实例化的是 A 接口的实现类对象(该方法在jdk1.8以后被lambda表达式完虐)
testLambda(new A() {
//缺省属性为abstract,需要重写
@Override
public void 方法名真的没有用() {
System.out.println("无参数返回值 匿名内部类对象方法实现");
}
});
/*
2. Lambda 表达式实现
【分析】
void 方法名真的没有用();
接口方法【返回值类型】 void,无返回值
接口方法【参数】 无参数
*/
testLambda(() -> {
System.out.println("Lambda 表达式初体验");
});
//Lambda 表达式有且只有一行代码,可以省略大括号
testLambda(() -> System.out.println("Lambda 表达式初体验"));
生产者接口
Supplier < T> T get() 无参有返回值的抽象方法;
//接口设计
@FunctionalInterface
interface Supplier
/**
* 无参数有返回值方法,泛型约束的是接口对应的返回值数据类型,要求按照泛型约束返回对应的数据内容
*
* @return 返回一个数据,符合泛型约束
*/
T get();
}
/*
* 当前方法要求返回一个字符串数据内容
*/
public static String testLambda(Supplier
return s.get();
}
public static void main(String[] args) {
/*
【分析】
T get(); ==> 泛型约束为 String ==> String get();
接口方法【返回值类型】 String
接口方法【参数】 无参数
Lambda 格式:() -> {必须返回一个 String 类型}
*/
String s1 = testLambda(() -> {
return "这里也是一个字符串";
});
System.out.println(s1);
/*
Lambda 优化,只要 -> 之后是一个 字符串数据内容就可以满足当前 Lambda 所需
可以省略 return ,前提是当前 Lambda 有且只有一行代码
*/
String s2 = testLambda(() -> "这里也是一个字符串");
System.out.println(s2);
/*
Lambda 内部使用使用方法局部变量
*/
String str = "name=王小明&age=23&country=中国";
String s3 = testLambda(() -> {
// str 是当前 main 方法局部变量,Lambda 内部可以直接使用
String[] split = str.split("&");
return split[0];
});
System.out.println(s3);//返回王小明
}
消费型接口
Consumer< T> void accept(T t)有参数,无返回值的抽象方法;
@FunctionalInterface
interface Consumer
/**
* 消费者接口,数据最终处理接口,数据处理终止方法接口,对应的方法要求方法有参数无返回值
*
* @param t 泛型数据数据类型 T ,支持任意类型,在接口约束之后,要求符合数据类型一致化要求
*/
void accept(T t);
}
/**
* 有参数无返回 Lambda 测试方法,方法参数是 String 类型和针对于 String 类型
* 进行数据处理的 Consumer 接口,Consumer 接口可以传入实现类对象和 Lambda 表达式
*
* @param str 目标处理的 String 字符串数据
* @param handle 已经约束为处理 String 类型数据的 Consumer 接口处理器
*/
public static void testLambda(String str, Consumer
handle.accept(str);
}
public static void main(String[] args) {
/*
1、匿名内部类 Low
*/
testLambda("孟州市炒面第一名", new Consumer
@Override
public void accept(String t) {
System.out.println(t);
}
});
/*
2. Lambda 表达式
【分析】
void accept(T t); ==> 泛型约束为 String ==> void accept(String t);
接口方法【返回值】 void
接口方法【参数】 1 个参数,String 类型
Lambda 格式
Lambda 小括号中的临时变量名称,没有数据类型体现,需要【联想】目标方法数据类型
只按照参数的个数定义临时小变量
(s) -> {大括号中无需返回值类型}
Lambda 表达式临时变量 s 对应的数据类型为 String 类型 【联想可得】
*/
testLambda("lambda表达式需要联想!!!", (s) -> {
System.out.println(Arrays.toString(s.toCharArray()));
});
/*
Lambda 优化
1. 代码块有且只有一行,可以省略大括号
2. 小括号中有且只有一个 参数,可以省略小括号
【注意】
Lambda 承担的角色是一个针对于 String 字符串的处理器
*/
testLambda("lambda表达式需要联想!!!", s -> System.out.println(Arrays.toString(s.toCharArray())));
}
2.4有参数有返回值
比较器接口
Comparator< T> int compare(T o1, T o2)有参,返回值类型为int
断定型接口(过滤器接口)
Predicate< T> boolean test(T t)有参,但是返回值类型是固定的boolean
函数型接口(类型转换器接口)
Function< T,R> R apply(T t)有参,有返回值的抽象方法
1.比较器接口
// 比较器接口
@FunctionalInterface
interface Comparator
/**
* 比较器接口要求的方法,参数是泛型参数,用户指定类型
*
* @param o1 用户在使用接口时约束的泛型对应具体数据类型参数
* @param o2 用户在使用接口时约束的泛型对应具体数据类型参数
* @return 返回值为 int 类型,0 表示两个元素一致。
*/
int compare(T o1, T o2);
}
/**
* @author Anonymous 2023/3/3 11:30
*/
public class Demo1 {
public static void main(String[] args) {
Person[] array = new Person[5];
for (int i = 0; i < array.length; i++) {
int age = (int) (Math.random() * 50);
array[i] = new Person(i + 1, "张三", age, false);
}
/*
Lambda 分享
方法
int compare(T o1, T o2); ==> 泛型约束为 Person ==> int compare(Person o1, Person o2);
方法返回值 int 类型
方法参数
1. 2个参数
2. 参数数据类型都是 Person 类型
Lambda 格式
(o1, o2) -> {所需返回值为 int 类型}
*/
sortPersonArrayUsingComparator(array, (o1, o2) -> o1.getId() - o2.getId());
// Arrays.sort(array, (o1, o2) -> o1.getAge() - o2.getAge());
for (Person person : array) {
System.out.println(person);
}
}
/**
* 排序操作,排序数组为 Person 类型,排序规则使用自定义 Comparator 接口实现,接口泛型约束 Person
* 类型
*
* @param array Person 类型数组
* @param condition 针对于 Person 类型数组的 Comparator 比较器接口实现
*/
public static void sortPersonArrayUsingComparator(Person[] array, Comparator
for (int i = 0; i < array.length - 1; i++) {
int index = i;
for (int j = i + 1; j < array.length; j++) {
/*
condition 是自定义 Comparator 排序接口方法,目前泛型约束为 Person 类型
int compare(T o1, T o2); ==> int compare(Person o1, Person o2);
当前数组存储的数据类型就是 Person 对象,可以作为 compare 方法参数,同时
利用 compare 方法返回 int 类型数据,作为排序算法规则的限制。
*/
if (condition.compare(array[index], array[j]) > 0) {
index = j;
}
}
if (index != i) {
Person temp = array[index];
array[index] = array[i];
array[i] = temp;
}
}
}
}
2.过滤器接口
// 过滤器接口,判断器接口,条件接口
@FunctionalInterface
interface Predicate
/**
* 过滤器接口约束的方法,方法参数是用户使用时约束泛型对应具体数据参数
* 返回值类型是 boolean 类型,用于条件判断,数据过来
*
* @param t 用户约束泛型对应的具体数据类型参数
* @return boolean 数据,判断结果反馈
*/
boolean test(T t);
}
public class Demo2 {
public static void main(String[] args) {
Person[] array = new Person[5];
for (int i = 0; i < array.length; i++) {
int age = (int) (Math.random() * 50);
array[i] = new Person(i + 1, "张三", age, false);
}
/*
Lambda 分析
boolean test(T t); ==> 泛型约束为 Person 类型 ==> boolean test(Person t);
方法返回值是 boolean
方法参数
1. 1 个
2. Person 类型
Lambda 格式
p -> {要求必须返回一个 boolean}
*/
Person[] temp = filterPersonArrayUsingPredicate(array, p -> p.getAge() > 10);
for (Person person : temp) {
System.out.println(person);
}
}
/**
* 过滤限定操作,利用 Predicate 过滤器接口限定数组内容
*
* @param array Person 类型数组
* @param filter Predicate 过滤器参数
* @return 过滤限定之后的新数组
*/
public static Person[] filterPersonArrayUsingPredicate(Person[] array, Predicate
Person[] temp = new Person[array.length];
int count = 0;
for (int i = 0; i < array.length; i++) {
/*
Predicate 接口提供的方法是 boolean test(T t);
目前泛型约束之后是 boolean test(Person t);
判断当前 Person 对象是否满足要求,如果满足,存储到 temp 数组中。
*/
if (filter.test(array[i])) {
temp[count++] = array[i];
}
}
return temp;
}
}
3.类型转换器接口
// 类型转换器接口
@FunctionalInterface
interface Function
R apply(T t);
}
public class Demo3 {
public static void main(String[] args) {
String str = "开封有个包青天";
/*
Lambda 分析
R apply(T t); ==> 泛型约束 T => String R => Integer
Integer apply(String t);
Lambda 格式
返回值类型 Integer
方法参数
1. 1个
2. String
s -> {必须返回 int 类型数据}
*/
int i = testLambda(str, s -> s.length());
System.out.println(i);
}
public static int testLambda(String str, Function
return fun.apply(str);
}
}
当Lambda表达式满足某种条件的时候,使用方法引用,可以再次简化代码
当Lambda表达式是通过new一个对象来完成的,那么可以使用构造引用。
import java.util.function.Supplier;
public class TestLambda {
public static void main(String[] args) {
// Supplier
Supplier
}//实际过程:将new Student()赋值给了Supplier这个函数式接口中的那个抽象方法
}
Lambda表达式的的Lambda体也是通过一个对象的方法完成,但是调用方法的对象是Lambda表达式的参数列表中的一个,剩下的参数正好是给这个方法的实参。
import java.util.TreeSet;
public class TestLambda {
public static void main(String[] args) {
TreeSet
}
3.对象::实例方法
*/ //类名::实例方法
TreeSet
set.add("Hello");
set.add("isea_you");
// set.forEach(t -> System.out.println(t));//Hello \n isea_you
set.forEach(System.out::println);
//(1)对象::实例方法,Lambda表达式的(形参列表)与实例方法的(实参列表)类型,个数是对应
}
}
4.类名::静态方法
package com.isea.java;
import java.util.stream.Stream;
public class TestLambda {
public static void main(String[] args) {
// Stream
// 类名::静态方法, Lambda表达式的(形参列表)与实例方法的(实参列表)类型,个数是对应
Stream
stream.forEach(System.out::println);
}
}