Lambda表达式
我们可以把Lambda表达式理解为一段可以传递的代码(把代码当做我们平常传数据一样进行传递),可以写出更简洁的代码。
Lambda表达式的语法格式;(对应接口中的抽象方法的参数列表}->{需要执行的功能,也可以叫Lambda体,对应接口的抽象方法}
Lambda是简化匿名内部类可以省略一些代码,我们的代码看着更简洁,更方便阅读
Lambda的例子;
/**
* lambda 表达式 实现函数式接口
*/
public class Test001 {
public static void main(String[] args) {
//箭头符号的意思就是Lambda的操作符
Eat a = ()->System.out.println("饿了,要吃饭");
a.eat();
}
}
@FunctionalInterface //函数式接口,只能有一个抽象方法
interface Eat{
void eat();
}
函数式接口
接口中有且仅有一个抽象方法的接口,称为函数式接口。 default 修饰方法只能 在接口中使用(只能被实现了这个接口的对象调用),在接口种被default标记的方法 为普通方法,可以直接写方法体。 可以使用注解 @FunctionalInterface 修饰, 可以检查是否是函数式接口。
Lambda表达式需要函数式接口的支持 以前我们整个java的继承关系已经使用了很多年,如果在java新版本中为了迎合函 数式接口一个接口中只有一个抽象方法,会导致以前很多接口失效,那么别人也没 法进行jdk的升级所以提供了 默认方 法,在jdk1.8之后,可以在接口中定义默认方法
无参数无返回值
public class Test001 {
public static void main(String[] args) {
//箭头符号的意思就是Lambda的操作符
Eat a = ()->System.out.println("饿了,要吃饭");
a.eat();
}
}
@FunctionalInterface //函数式接口,只能有一个抽象方法
interface Eat{
void eat();//无参数 无返回值
}
有参数无返回值
/**
* 带参 无返回值
*/
public class TestParamNoReturn {
public static void main(String[] args) {
ParamNoReturn p = ((i -> System.out.println(i)));
p.test(9);
}
}
interface ParamNoReturn{
void test(int i);//有参数 无返回值
}
无参带返回值
/**
* 无参带返回值
*/
public class TestNoParamReturn {
public static void main(String[] args) {
// NoParamReturn n = (()->{return (int)(Math.random()*11);});
// System.out.println(n.test());
NoParamReturn n1 = (()->{
Random r = new Random();
return r.nextInt(100);
});
System.out.println(n1.test());
}
}
interface NoParamReturn{
int test();//无参数带返回值
}
有参数有返回值
/**
* 带参有返回值
*/
public class TestParamReturn {
public static void main(String[] args) {
ParamReturn p = (i, j) -> {return i+j;};
System.out.println(p.test(3,4));
test1((i, j) ->{return i+j;},4,6 );
}
}
interface ParamReturn{
int test(int i,int j);//有参数 有返回值
}
四大内置函数式接口
重点
Lambda的实现依赖于函数式接口,接口可以我们自己定义,当然也可以使用JDK已 经提供好的一些函数式接口,这些接口基本已经能够满足我们的常用操作,并且在 集合等框架中已经广泛地使用了,所以我们可以直接使用这些接口。 消费型、供给型、函数型、断定型
消费型接口 Comsumer void accept(T t) 供给型接口 Supplier T get() 函数型接口 Function R apply(T t) 断定型接口 Predicate boolean test(T t)
消费型接口 Comsumer void accept(T t)
/**
* 消费型接口; 有参 无返回值 Consumer
*/
public class ConsumerTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("1111");
list.add("2222");
list.add("3333");
list.add("4444");
//forEach 方法中需要一个Consumer接口,因为Consumer接口里面的accept需要带一个参数
//将集合中每一个元素,一次给到accept 方法中,由自己决定对现在拿到的每一个元素进行什么样的操作
list.forEach((t)->{
System.out.println(t);
});
}
}
供给型接口 Supplier T get()
/**
* 供给型接口
*/
public class TestSupplier {
public static void main(String[] args) {
//提供生成随机数个数, 和提供生成器
List<Integer> list = getList(3, () -> {
return (int) Math.random() * 101;
});
//对生成的随机数遍历获取
list.forEach((t) -> {
System.out.println(t);
});
System.out.println("================================");
}
//定义一个方法,生成指定个数的list集合,里面存储都是0到100的随机整数
public static List<Integer> getList(int count, Supplier<Integer> sup) {
//1 存放随机数的集合 的大小
List<Integer> list = new ArrayList<>();
//2 用户给的生成器,生成需要的数据
for (int i = 0; i < count; i++) {
list.add(sup.get());
}
return list;
}
}
函数型接口也可以叫 功能型接口Function R apply(T t)
/**
* 功能性接口 Function
*/
public class TestFunction {
public static void main(String[] args) {
String str="wfadaffq";
//字符串前后加空格
String s1=stringHandler(str,(s -> {return " "+s+" ";}));
System.out.println(s1);
//截取字符串中的最后两个字符
String s2 = stringHandler(str,(s -> {return s.substring(s.length()-2);}));
System.out.println(s2);
}
public static String stringHandler(String str, Function<String,String> f){
return f.apply(str);//利用处理器对传进来的字符串处理
}
}
断定型接口 也可以叫做 评审型接口 Predicate boolean test(T t)
/**
* 断定型接口| Predicate 返回值 boolean类型
*/
public class TestPredicate {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("aaaaa");
list.add("bbbbbb");
list.add("bbbbdaw");
list.add("aaaada");
list.add("asdadw");
//需求; 挑选出字符个数大于5的元素
getSome(list,(s)->{return s.length()>5;}).forEach((t)->{
System.out.println(t);
});
}
//将List<String> 集合中的 满足条件的元素提取出来
public static List<String> getSome(List<String> list, Predicate<String> p){
//准备一个集合存储满足条件的元素
List<String> newList= new ArrayList<>();
//s 是一个形参 临时接受List中的每一个元素
list.forEach((s -> {
//使用 形参的p对s 就行判定
if (p.test(s)){
//如果满足条件则添加到新的集合中
newList.add(s);
}
}));
return newList;
}
}
方法的引用
若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方 法引用是Lambda表达式的另一种表现形式),主要有三种语法格式:
1对象::实例方法名
public void test1() {
//Lambda 表达式
Consumer<String> con = (x) -> System.out.println(x);
PrintStream ps = System.out;
//方法引用后的表达式
Consumer<String> con1 = ps::println;
Consumer<String> con2 = System.out::println;
con2.accept("baidu");
public void test2() {
Employee emp = new Employee();
emp.setName("张三");
emp.setAge(18);
Supplier<String> sup = () -> emp.getName();
String str = sup.get();
System.out.println(str);
Supplier<Integer> sup2 = emp::getAge;
int age = sup2.get();
System.out.println(age);
}
2,类::静态方法名
public void test3() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com1 = Integer::compare;
}
3,类::实例方法名
public void test4() {
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String, String> bp1 = String::equals;
}
注意: 1、Lambda体中调用方法的参数列表和返回值类型,要与函数式接口中抽象方法的 函数列表和返回值类型保持一致。 2、若Lambda参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方 法的参数时,可以使用ClassName::method。
构造器引用
`1
@Test
public void test5() {
Supplier<Employee> sup = () -> new Employee();
Employee emp = sup.get();
// 构造器引用方式
Supplier<Employee> sup1 = Employee::new;
Employee emp1 = sup.get();
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法参数列表保持一
致。
System.out.println(emp1);
}
`2
public void test6() {
Function<Integer, Employee> func = (x) -> new Employee(x);
func.apply(20);
// 需要调用的构造器的参数列表要与函数式接口中抽象方法参数列表保持一致
Function<Integer, Employee> func2 = Employee::new;
Employee emp1 = func2.apply(18);
System.out.println(emp1);
BiFunction<Integer, String, Employee> bf = Employee::new;
Employee emp2 = bf.apply(20, "张三");
System.out.println(emp2);
}
注意;需要调用的构造器的参数列表要与函数式接口中抽象方法参数列表保持一致