1. Lambda表达式概述
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
Lambda表达式用于创建匿名函数,可以在需要函数对象的任何地方使用它们。
Lambda表达式的基本语法是:lambda arguments: expression
,其中:
arguments
是逗号分隔的参数列表,类似于函数定义中的参数列表。expression
是执行函数体的表达式。
例如,下面的代码展示了如何使用lambda表达式来定义一个简单的函数并调用它:
add = lambda x, y: x + y
result = add(3, 4)
print(result) # 输出 7
还可以将lambda表达式作为参数传递给其他函数,例如map()
和filter()
,可以将其用于列表,元组或其他序列的操作,如下所示:
numbers = [1, 2, 3, 4, 5]
squares = map(lambda x: x**2, numbers)
filtered = filter(lambda x: x > 3, numbers)
print(list(squares)) # 输出 [1, 4, 9, 16, 25]
print(list(filtered)) # 输出 [4, 5]
Lambda表达式还可以用于排序,比较或任何需要函数对象的场合。通过以上方法使用Lambda表达式,可以更加灵活地编写代码,提高代码的简洁性和可读性。
使用 Lambda 表达式可以使代码变的更加简洁紧凑.
Lambda 表达式(lambda expression)是一个匿名函数,简单来说,Lambda表达式是一个可传递的代码段。可以不借助对象传递的一个代码段。
2.1 简述lambda的由来
package demo01;
public class Test01 {
public static void main(String[] args) {
//开启一个线程 该构造函数需要传递一个Runnable类型的接口参数
Thread thread = new Thread(new My());
thread.start();//开启线程
//匿名内部类
Thread thread1=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("通过匿名内部类实现线程任务");
}
});
thread1.start();//开启线程
}
}
class My implements Runnable{
@Override
public void run() {
System.out.println("使用实现类来完成------->线程任务");
}
}
分析:
-
Thread类需要一个Runnable接口作为参数,其中的抽象方法run方法是用来指定线程任务内容的核心
-
为了指定run方法体,不得不需要Runnable的实现类.
-
为了省去定义一个Runnable 的实现类,不得不使用匿名内部类.
-
必须覆盖重写抽象的run方法,所有的方法名称,方法参数,方法返回值不得不都重写一遍,而且不能出错.
-
而实际上,只在乎方法体中的代码.
-
可以使用lambda表达式来完成上面的功能。
2.2 简单的lambda表达式。
//lambda表达式.
Runnable runnable1=()->{
System.out.println("这是lambda表达式完成线程任务");
};
Thread thread2=new Thread(runnable1);
thread2.start();
2.3 lambda表达式的语法
Lambda省去了面向对象的条条框框,Lambda的标准格式由3个部分组成:
(参数列表)->{}
():参数列表
->:连接符 连接的是参数以及方法体。
{}: 方法体。
2.4 无参无返回值的Lambda
package demo02;
public class Test02 {
public static void main(String[] args) {
//主函数调用fun方法。
//第一种:创建UserService接口的实现类,并创建该实现类对象。
//第二种: 匿名内部类的方式
// UserService userService=new UserService() {
// @Override
// public void show() {
// System.out.println("这是匿名内部类的show方法的实现");
// }
// };
// fun(userService);
//第三种lambda表达式:--该接口必须为函数式接口
UserService userService=()->{
System.out.println("lambda表示的show方法");
};
fun(userService);
}
public static void fun(UserService userService){//UserService userService=
userService.show();
}
}
//函数式接口-->里面有且仅有一个抽象方法。--只有这种接口才能使用lambda表达式。
interface UserService{
public void show();
}
2.5 有参有返回值。
package demo03;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Test03 {
public static void main(String[] args) {
List<Person> personList=new ArrayList<>();
personList.add(new Person("张三",15));
personList.add(new Person("李四",5));
personList.add(new Person("王五",65));
personList.add(new Person("赵六",45));
personList.add(new Person("田七",35));
//对集合中的元素按照年龄排序。小到大
System.out.println(personList);
//Collections:集合工具类。--匿名内部类
// Comparator<Person> comparator=new Comparator<Person>() {
// @Override //如果是0表示相同 大于0表示o1大于02
// public int compare(Person o1, Person o2) {
// return o1.getAge()-o2.getAge();
// }
// };
// Collections.sort(personList,comparator);
// System.out.println(personList);
Comparator<Person> comparator=(o1,o2)->{
//就是对函数式接口中抽象方法的简写。
return o1.getAge()-o2.getAge();
};
Collections.sort(personList,comparator);
System.out.println(personList);
}
}
class Person{
private String name;
private Integer age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
2.6 Lambda表达式的省略写法
在lambda表达式的标准写法基础上,可以使用省略写法的规则为:
-
小括号内的参数类型可以省略[ ]
-
如果小括号内有且仅有一个参数,则小括号可以省略
-
如果大括号内有且仅有一个语句,可以同时省略大括号,return 关键字及语句分号。
package demo04;
public class Test05 {
public static void main(String[] args) {
USB u=(str)-> str.toUpperCase();//lambda表达式:
// USB u=new USB() {//匿名内部类对接口中抽象方法的个数没有任何要求.
// @Override
// public String toUpper(String str) {
// return null;
// }
//
// @Override
// public String toLower(String str) {
// return null;
// }
// };
fun(u);
}
public static void fun(USB usb){
String s = usb.toUpper("hello");
System.out.println(s);
}
}
interface USB{
public String toUpper(String str);
// public String toLower(String str);
}
2.7 Lambda表达式使用的前提
Lambda表达式的语法是非常简洁的,但是Lambda表达式不是随便使用的,使用时有几个条件要特别注意
-
方法的参数或局部变量类型必须为接口才能使用Lambda
-
接口中有且仅有一个抽象方法(@FunctionalInterface)
-
后面我们使用lambda表达式主要核心使用再Stream流中。
3. 内置函数式接口
要想使用lambda表达式它的前提就是必须是函数式接口。
3.1 内置函数式接口的由来
package demo05;
public class Test {
public static void main(String[] args) {
Operation o=arr->{
int sum=0;
for(int s:arr){
sum+=s;
}
return sum;
};
fun(o);
}
public static void fun(Operation operation){
int[] arr={1,2,3,4};
int s = operation.getSum(arr);
System.out.println("数组的和:"+s);
}
}
@FunctionalInterface
interface Operation{
public int getSum(int[] arr);
}
分析:
我们知道使用Lambda表达式的前提是需要有函数式接口,而Lambda表达式使用时不关心接口名,抽象方法名。只关心抽象方法的参数列表和返回值类型。因此为了让我们使用Lambda表达式更加的方便,在JDK中提供了大量常用的函数式接口. 大多数无需自己再定义函数式接口,而可以直接使用jdk内置的函数式接口。分成四类。
3.2 消费型函数式接口Consumer
适合有参数,但是没有返回值的。
public class Test06 {
public static void main(String[] args) {
Consumer<Double> c=t->{
System.out.println("今天洗脚花费:"+t+"元");
};
fun(c,200.0);
}
public static void fun(Consumer<Double> consumer,Double money){
consumer.accept(money);
}
}
3.3 供给型函数式接口---Supplier
无参,需要返回值的接口类。
package demo06;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class Test06 {
public static void main(String[] args) {
// Consumer<Double> c=t->{
// System.out.println("今天洗脚花费:"+t+"元");
// };
// fun(c,200.0);
Supplier<Integer> s=()-> new Random().nextInt(10);
fun2(s);
}
public static void fun2(Supplier<Integer> supplier){
Integer a = supplier.get();
System.out.println("结果:"+a);
}
public static void fun(Consumer<Double> consumer,Double money){
consumer.accept(money);
}
}
3.3 函数型函数式接口---Function<T,R>
T: 参数的泛型
R:返回值的泛型。
package demo05;
import java.util.function.Function;
public class Test {
public static void main(String[] args) {
Function<int[],Integer> o=arr->{
int sum=0;
for(int s:arr){
sum+=s;
}
return sum;
};
fun(o);
}
public static void fun(Function<int[],Integer> fun){
int[] arr={1,2,3,4};
int s = fun.apply(arr);
System.out.println("数组的和:"+s);
}
}
3.4 断言型函数式接口--Predicate
T: 参数
boolean:返回值类型。
package demo06;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class Test06 {
public static void main(String[] args) {
// Consumer<Double> c=t->{
// System.out.println("今天洗脚花费:"+t+"元");
// };
// fun(c,200.0);
// Supplier<Integer> s=()-> new Random().nextInt(10);
// fun2(s);
// Function<String,String> fun=t->t.toUpperCase();
// fun3(fun,"hello world");
Predicate<String> p=t->t.length()>3;
fun4(p,"欧阳锋"); //4
}
public static void fun4(Predicate<String> predicate,String name){
boolean test = predicate.test(name);
System.out.println("是否成年:"+test);
}
public static void fun3(Function<String,String> f,String str){
String apply = f.apply(str);
System.out.println("结果:"+apply);
}
public static void fun2(Supplier<Integer> supplier){
Integer a = supplier.get();
System.out.println("结果:"+a);
}
public static void fun(Consumer<Double> consumer,Double money){
consumer.accept(money);
}
}
4. 方法引用
特殊的lambda表达式,它是对lambda表达式的一种简写方式。
4.1 方法引用的由来
package demo07;
import java.util.function.Consumer;
public class Test07 {
public static void main(String[] args) {
Consumer<int[]> c=t->{
int sum=0;
for(int a:t){
sum+=a;
}
System.out.println("数组的和:"+sum);
};
fun(c);
}
public static void fun(Consumer<int[]> consumer){
int[] arr={1,2,3,4,5};
consumer.accept(arr);
}
//求和方法
public static void sum(int[] arr){
int sum=0;
for(int a:arr){
sum+=a;
}
System.out.println("数组的和:"+sum);
}
}
如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了:---方法引用。::
package demo07;
import demo01.AAA;
import java.util.function.Consumer;
public class Test07 {
public static void main(String[] args) {
// Consumer<int[]> c=t->{
// int sum=0;
// for(int a:t){
// sum+=a;
// }
// System.out.println("数组的和:"+sum);
// };
// Consumer<int[]> c=(t)->Test07.sum(t); //
Consumer<int[]> c= Test07::sum;
fun(c);
}
public static void fun(Consumer<int[]> consumer){
int[] arr={1,2,3,4,5};
consumer.accept(arr);
}
//求和方法
public static void sum(int[] arr){
int sum=0;
for(int a:arr){
sum+=a;
}
System.out.println("数组的和:"+sum);
}
}
4.2 方法引用的类型