Java8新特性2:Lambda表达式和方法引用
回顾之前《JavaSE-23.3》:
https://www.cnblogs.com/yppah/p/14875254.html
https://www.cnblogs.com/yppah/p/14875479.html
https://www.cnblogs.com/yppah/p/14875492.html
https://www.cnblogs.com/yppah/p/14875500.html
https://www.cnblogs.com/yppah/p/14875507.html
1. 什么是lambda表达式
Lambda 表达式(lambda expression)是一个匿名函数,简化我们调用匿名函数的过程。
Lambda好处: 简化我们匿名内部类的调用。
Lambda+方法引入 代码变得更加精简。
package com.yppah.service;
/**
* @Author: haifei
* @Date: 2022/7/20 19:35
*/
public interface OrderService {
void get();
/**
* 如果需要使用到OrderService接口
* 接口是无法new、可以通过匿名内部类new
*/
}
package com.yppah.myLambda;
import com.yppah.service.OrderService;
/**
* @Author: haifei
* @Date: 2022/7/20 19:44
*/
public class Test02 {
public static void main(String[] args) {
/*// 通过匿名内部类创建一个接口的子类,用父类(接口)接收
// 通过匿名内部类的方式调用接口中的方法
OrderService orderService = new OrderService() {
@Override
public void get() { //匿名内部类
System.out.println("get");
}
};
orderService.get();*/
// 简写
/*new OrderService() {
@Override
public void get() { //匿名内部类
System.out.println("get");
}
}.get();*/
((OrderService) () -> {
System.out.println("get");
}).get();
/*new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" :run...");
}
}).start();*/
new Thread(() ->
System.out.println(Thread.currentThread().getName()+" :run...")
).start();
}
}
2. lambda表达式规范
2.1 函数接口定义
Java中使用Lambda表达式的规范,必须是为函数接口
函数接口的定义:在该接口中只能存在一个抽象方法,该接口称作为函数接口
使用Lambda表达式 依赖于函数接口
- 在函数接口中只能够允许有一个抽象方法
- 在函数接口中可以定义object类中方法
- 可以使用默认或者静态方法
- @FunctionalInterface 表示该接口为函数接口
package com.yppah.myLambda.p2;
/**
* @Author: haifei
* @Date: 2022/7/20 20:29
*/
@FunctionalInterface // 函数接口(要求该接口中只能有一个抽象函数,不然注解会报错。但可以有默认或静态方法)
public interface MyFunctionalInterface {
void get();
default void add(){
System.out.println("add");
}
// 在函数接口中定义object类中方法
String toString();
}
2.2 java内置的函数接口
JDK中自带的函数接口:
-
java.lang.Runnable
-
java.util.concurrent.Callable
-
java.security.PrivilegedAction
-
java.util.Comparator
-
java.io.FileFilter
-
java.nio.file.PathMatcher
-
java.lang.reflect.InvocationHandler
-
java.beans.PropertyChangeListener
-
java.awt.event.ActionListener
-
javax.swing.event.ChangeListener
java系统内置哪些函数接口?
2.2.1 消费型接口
Conusmer<T>
void accept(T t);
BiConusmer<T,U>
void accept(T t,U u);//增加一种入参类型
2.2.2 供给型接口
Supplier<T>
void get();
2.2.3 函数型接口
Function<T ,R>
R apply(T t);
UnaryOperator<T>
T apply(T t);//入参与返回值类型一致
BiFunction <T ,U,R>
R apply(T t,U u);//增加一个参数类型
BinaryOperator<T>
T apply(T t1,T t2);//l两个相同类型入参与同类型返回值
ToIntFunction<T>//限定返回int
ToLongFunction<T>//限定返回long
ToDoubleFunction<T>//限定返回double
IntFunction<R>//限定入参int,返回泛型R
LongFunction<R>//限定入参long,返回泛型R
DoubleFunction<R>//限定入参double,返回泛型R
2.2.4 断言型接口
Predicate<T>
boolean test(T t);
2.3 Lambda语法
参数列表:()
分隔符:->
方法体:{}
()->{}
2.3.1 无参方法调用
package com.yppah.myLambda.p3;
/**
* @Author: haifei
* @Date: 2022/10/25 14:03
*/
@FunctionalInterface
public interface AcanthopanaxInterface {
void get(); //函数接口必须有且仅有一个抽象方法
}
package com.yppah.myLambda.p3;
import com.yppah.myLambda.p2.MyFunctionalInterface;
/**
* @Author: haifei
* @Date: 2022/10/25 14:03
*/
public class Test03 {
public static void main(String[] args) {
// 1. 使用匿名内部类调用
new AcanthopanaxInterface() {
@Override
public void get() {
System.out.println("get");
}
}.get();
// 2. 使用lambda表达式调用
// ((AcanthopanaxInterface) () -> System.out.println("get")).get();
AcanthopanaxInterface acanthopanaxInterface = () -> {
System.out.println("get");
};
acanthopanaxInterface.get();
}
}
2.3.2 带参和返回值
package com.yppah.myLambda.p4;
/**
* @Author: haifei
* @Date: 2022/10/25 14:54
*/
@FunctionalInterface
public interface YouShenInterface {
String get(int i, int j);
}
package com.yppah.myLambda.p4;
/**
* @Author: haifei
* @Date: 2022/10/25 14:54
*/
public class Test04 {
public static void main(String[] args) {
// 1. 使用匿名内部类调用
YouShenInterface youShenInterface = new YouShenInterface() {
@Override
public String get(int i, int j) {
return i + "--" + j;
}
};
System.out.println(youShenInterface.get(1, 2));
// 2. 使用lambda表达式调用
YouShenInterface youShenInterface2 = (i, j) -> {
return i+"--"+j;
};
System.out.println( youShenInterface2.get(3, 4));
}
}
2.3.3 精简语法
- 如果方法体中只有一条语句的情况下,可以不需要写{}
- 如果方法体中只有一条return的情况下,不需要些{}和return
package com.yppah.myLambda.p5;
import com.yppah.myLambda.p3.AcanthopanaxInterface;
import com.yppah.myLambda.p4.YouShenInterface;
/**
* @Author: haifei
* @Date: 2022/10/25 15:04
*/
public class Test05 {
public static void main(String[] args) {
// 1-1
AcanthopanaxInterface acanthopanaxInterface = () -> {
System.out.println("无参无返回的lambda");
};
acanthopanaxInterface.get();
// 1-2
((AcanthopanaxInterface)()->{
System.out.println("无参无返回的lambda");
}).get();
// 2-1
AcanthopanaxInterface acanthopanaxInterface2 = () -> System.out.println("无参无返回的lambda");
acanthopanaxInterface2.get();
// 2-2
((AcanthopanaxInterface)()-> System.out.println("无参无返回的lambda")).get();
// "有参有返回值的1ambda"
// 3-1
YouShenInterface youShenInterface = (i, j) -> {
return i+"-"+j;
};
System.out.println(youShenInterface.get(1, 2));
// 3-2
YouShenInterface youShenInterface2 = (i, j) -> i+"-"+j;
System.out.println(youShenInterface2.get(3, 4));
// 3-3
String result = ((YouShenInterface) (i, j) -> i + "-" + j).get(5, 6);
System.out.println(result);
}
}
2.4 lambda案例
2.4.1 foreach集合遍历
package com.yppah.myLambda.p6;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
* @Author: haifei
* @Date: 2022/10/25 15:40
*/
public class Test06 {
public static void main(String[] args) {
List<String> arrayList = new ArrayList<>();
arrayList.add("tom");
arrayList.add("amy");
arrayList.add("sam");
/*arrayList.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
arrayList.forEach(s -> System.out.println(s));
}
}
2.4.2 集合排序
package com.yppah.myLambda.p6;
/**
* @Author: haifei
* @Date: 2022/10/25 15:47
*/
public class User {
private String userName;
private int age;
public User(String userName, int age) {
this.userName = userName;
this.age = age;
}
public User() {
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
package com.yppah.myLambda.p6;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* @Author: haifei
* @Date: 2022/10/25 15:47
*/
public class Test07 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("tom", 22));
userList.add(new User("amy", 18));
userList.add(new User("sam", 26));
/*userList.sort(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o1.getAge()-o2.getAge();
}
});*/
/*userList.forEach((t) -> {
System.out.println(t.toString());
});*/
/*userList.sort((o1, o2) -> {
return o1.getAge()-o2.getAge();
});*/
userList.sort((o1, o2) -> o1.getAge()-o2.getAge());
userList.forEach(t -> System.out.println(t.toString()));
}
}
2.4.3 线程调用
package com.yppah.myLambda.p6;
/**
* @Author: haifei
* @Date: 2022/10/25 16:03
*/
public class Test08 {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类-" + Thread.currentThread().getName());
}
}).start();
new Thread(() -> System.out.println("lambda表达式-" + Thread.currentThread().getName())).start();
}
}
2.5 方法引入
2.5.1 概念和规则
方法引用提供了非常有用的语法,可以直接引用已有的java类或对象的方法或构造器。方法引用其实也离不开Lambda表达式,与lambda联合使用 ,方法引用可以使语言的构造更加紧凑简洁,减少冗余代码。
方法引用提供非常有用的语法,可以直接引用已有的java类或者对象中方法或者构造函数,方法引用需要配合Lambda表达式语法一起使用减少代码的冗余性问题。
//方法引入实际上就是lambda表达式中直接引入方法
//方法引入规范:[引入方法的参数列表、返回类型]与[函数接口数列表、返回类型]必须保持一致
函数接口
方法引入
2.5.2 静态方法引入
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 14:46
*/
@FunctionalInterface
public interface MessageInterface {
void get(Integer a);
}
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 14:43
*/
public class Test09 {
public static void main(String[] args) {
// 1. 最原生的匿名内部类调用方式
MessageInterface messageInterface = new MessageInterface() {
@Override
public void get(Integer a) {
System.out.println("get a: " + a);
}
};
messageInterface.get(1);
// 2. lambda表达式改写上述
MessageInterface messageInterface2 = a->System.out.println("get a: " + a);
messageInterface2.get(2);
// 新需求:在lambda表达式的方法体中直接引入方法
MessageInterface messageInterface3 =(a) -> {
Test09.getStatic(a);
};
messageInterface3.get(3);
// 精简一下上述代码:方法引入
// 3. 方法引入写法
MessageInterface messageInterface4 = Test09::getStatic;
messageInterface4.get(4);
//方法引入实际上就是lambda表达式中直接引入方法
//方法引入规范:[引入方法的参数列表、返回类型]与[函数接口数列表、返回类型]必须保持一致
}
public static void getStatic(Integer a) {
System.out.println("getStatic a: "+ a);
}
}
2.5.3 实例方法引入
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 14:46
*/
@FunctionalInterface
public interface MessageInterface2 {
String getMsg();
}
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 16:08
*/
public class Test10 {
public static void main(String[] args) {
// MessageInterface2 messageInterface2 = ()->{return "999"};
MessageInterface2 mi2 = ()->"999";
System.out.println(mi2.getMsg()); //999
Test10 test10 = new Test10();
MessageInterface2 mi22 = ()->test10.objGet(); //lambda表达式方式
System.out.println(mi22.getMsg()); //2222
MessageInterface2 mi23 = test10::objGet; //方法引入方式
System.out.println(mi23.getMsg()); //2222
}
public String objGet() {
return "2222";
}
}
2.5.4 构造方法引入
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 16:20
*/
public class Message {
private String msgId;
private String msgName;
public Message() {
}
@Override
public String toString() {
return "Message{" +
"msgId='" + msgId + '\'' +
", msgName='" + msgName + '\'' +
'}';
}
}
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 14:46
*/
@FunctionalInterface
public interface MessageInterface3 {
Message getMsg();
}
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 16:22
*/
public class Test11 {
public static void main(String[] args) {
MessageInterface3 mi3 = ()->{
return new Message();
};
System.out.println(mi3.getMsg()); //Message{msgId='null', msgName='null'}
//语法
//函数接口返回类型::new
MessageInterface3 mi32 = Message::new;
System.out.println(mi32.getMsg()); //Message{msgId='null', msgName='null'}
}
}
2.5.5 对象方法引入
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 16:40
*/
public interface TestService {
String get(Test12 test12);
}
package com.yppah.myLambda.p7;
/**
* @Author: haifei
* @Date: 2022/10/27 16:40
*/
public class Test12 {
public static void main(String[] args) {
// 方式1:匿名内部类
TestService testService = new TestService() {
@Override
public String get(Test12 test12) {
return test12.objGet();
}
};
System.out.println(testService.get(new Test12())); //nbgeigei
// 方式2:lambda表达式
TestService testService2 = test12 -> test12.objGet();
System.out.println(testService2.get(new Test12())); //nbgeigei
// 方式3:方法引入
// 方式3中的Test12::objGet相当于方式2中的test12 -> test12.objGet()
TestService testService3 = Test12::objGet;
System.out.println(testService3.get(new Test12())); //nbgeigei
}
public String objGet() {
return "nbgeigei";
}
}
案例:
package com.yppah.myLambda.p7;
import java.util.function.Function;
/**
* @Author: haifei
* @Date: 2022/10/27 16:56
*/
public class Test13 {
public static void main(String[] args) {
//需求: 利用JAVA内置的Function函数接口求字符串长度
// 方式1:lambda
Function<String, Integer> function = str->str.length();
System.out.println(function.apply("123456")); //6
// 方式2:方法引用
Function<String, Integer> function2 = String::length;
System.out.println(function2.apply("654321")); //6
}
}
方法引入详见置顶链接