07.方法引用【5种常用的::及案例展示】
lambda表达式冗余!!!!!
- lambda表达式冗余!!!!!
在使用lambda表达式的时候也会出现代码冗余的情况,
比如:用lambda表达式求一个数组的和。
【案例】:lambda表达式-数组求和
public static void fun8(Consumer<int[]> consumer) {
int[] arr = {22, 33, 44, 23, 4, 5};
consumer.accept(arr);
}
@Test
@DisplayName("案例:统计数组中所有数据的求和")
public void test8() {
fun8((arr) -> {
int sum = 0;
for (int i : arr) {
sum += i;
}
System.out.println(sum);
});
Result:
131
我们使用lambda表达式写数组求和,为什么不直接写一个方法求和呢?
普通方式-方法求和:
public static void printMax(int a[]){
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组和:" + sum);
}
@Test
@DisplayName("案例:普通方式-统计数组中所有数据的求和")
public void test9() {
int arr[] = {2,54,2,45};
printMax(arr);
}
Result:
数组和:103
为什么要用方法引用
lambda 冗余解决方案
因为在lambda表达式中要执行的代码和我们另一个方法中的代码是一样的,这时就没有必要重写一份逻辑了,这时我们就可以使用方法引用
,方法引用其实就是引用重复代码。
首先还是先定一个静态方法,计算数据的求和方法。
public static void fun8(Consumer<int[]> consumer) {
int[] arr = {22, 33, 44, 23, 4, 5};
consumer.accept(arr);
}
public static void printMax(int a[]){
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组和:" + sum);
}
@Test
@DisplayName("案例:方法引用")
public void test10() {
fun8(MyTest::printMax);
}
方法引用的语法格式
::
双冒号为方法引用运算符,而它所在的表达式称为方法引用
。
方法引用的应用场景
如果lambda表达式所要实现的方案,已经有其他的方法存在相同的方案,那么则可以使用方法引用。
常见的引用方式
方法引用在JDK8中式相当灵活的,有以下几种形式:
- instanceName::methodName 对象::方法名
- ClassName::staticMethodName 类名::静态方法
- ClassName::methodName 类名::普通方法
- ClassName::new 类名::new 调用的构造器
- TypeName[]::new String[]::new 调用数组的构造器
常用的引用方式-细节
对象名::方法名【最常见的一种用法】
如果一个类中已经存在了一个成员方法,则可以通过对象名引用成员方法。
先看lambda表达式中如何获取时间对象的毫秒差:
@Test
@DisplayName("lambda表达式获取时间")
public void test11() {
Date date = new Date();
System.out.println("返回的日期对象是date = " + date);
Supplier<Long> supplier = () ->{return date.getTime();};
System.out.println("时间差毫秒为:" + supplier.get());
}
使用方法引用
改进:
@Test
@DisplayName("使用方法引用优雅的获取时间差-lambda表达式获取时间")
public void test12() {
Date date = new Date();
System.out.println("返回的日期对象是date = " + date);
Supplier<Long> supplier = date::getTime;
System.out.println("时间差毫秒为:" + supplier.get());
}
对象名::方法名 ⚠️:
方法引用
的方法,参数要和接口中的抽象方法的参数一样。- 当接口抽象方法有返回值时,被引用的方法也必须有返回值。
类名::静态方法【也是比较常用的】
先看lambda表达式获取当前系统时间的信息的【案例】
@Test
@DisplayName("lambda表达式获取当前系统时间的信息")
public void test13() {
Supplier<Long> supplier = ()->{
return System.currentTimeMillis();
};
System.out.println(supplier.get());
}
紧接着,我们使用方法引用
优雅写代码:
@Test
@DisplayName("方法引用:类名::静态方法名")
public void test14() {
Supplier<Long> supplier = System::currentTimeMillis;
System.out.println(supplier.get());
}
类名::引用实例方法
java面向对象,类名只能调用静态方法,类名引用实例方法是有前提的,实际上是拿第一个参数作为方法的调用者。
lambda表达式案例:传入一个String,求长度:
@Test
@DisplayName("lambda表达式案例:传入一个String,求长度")
public void test15() {
Function<String, Integer> function = (s) ->{
return s.length();
};
System.out.println(function.apply("Hello, world!"));
}
优雅的使用 方法引用
改造:类名::引用实例方法
@Test
@DisplayName("优雅的使用 `方法引用`改造:lambda表达式案例:传入一个String,截取")
public void test16() {
Function<String, Integer> f = String::length;
Integer le = f.apply("hello");
System.out.println(le);
BiFunction<String,Integer,String> function =String::substring;
String msg = function.apply("Hello, world!", 3);
System.out.println("截取后"+msg);
}
Result:
5
截取后lo, world!
类名::构造器
由于构造器的名称和类名完全一致,所以构造器引用使用::new
的格式使用。
【案例】lambda表达式案例:获取Person对象:
package com.lambda.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author:kaiyang.cui
* @Package:com.lambda.domain
* @Project:jdk8
* @name:Person
* @Date:2023/4/2 下午3:58
* @Filename:Person
* @Description:Person实体类
* @Version:1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private String name;
private Integer age;
private Integer height;
}
@Test
@DisplayName("lambda表达式案例:获取Person对象")
public void test17() {
Supplier<Person> supplier = ()->{return new Person();};
Person person = supplier.get();
System.out.println("person = " + person);
}
Result:
person = Person(name=null, age=null, height=null)
【案例】优雅的改造lambda表达式获取Person对象:
@Test
@DisplayName("优雅的改造lambda表达式获取Person对象")
public void test18() {
Supplier<Person> supplier = Person::new;
Person person = supplier.get();
System.out.println("person = " + person);
}
Result:
person = Person(name=null, age=null, height=null)
上面的Person对象是null,我们来改造赋值:
package com.lambda.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author:kaiyang.cui
* @Package:com.lambda.domain
* @Project:jdk8
* @name:Person
* @Date:2023/4/2 下午3:58
* @Filename:Person
* @Description:Person实体类
* @Version:1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private String name;
private Integer age;
// private Integer height;
}
@Test
@DisplayName("优雅的改造lambda表达式获取Person对象,赋值版")
public void test19() {
BiFunction<String,Integer,Person> function = Person::new;
System.out.println(function.apply("张三",22));
}
Result:
Person(name=张三, age=22)
数组::构造器
数组是怎么构造出来的 ?
【案例】lambda 返回数组的长度
@Test
@DisplayName("lambda 返回数组的长度")
public void test20() {
Function<Integer, String[]> function = (len)->{
return new String[len];
};
String[] arr = function.apply(3);
System.out.println(arr.length);
}
【案例改造】方法引用 优雅实现:lambda 返回数组的长度
@Test
@DisplayName("方法引用 优雅实现:lambda 返回数组的长度")
public void test21() {
Function<Integer, String[]> function = String[]::new;
String[] arr = function.apply(3);
System.out.println("arr的长度是 = " + arr.length);
}
总结
方法引用是对lambda表达式符合特定情况下对一种缩写方式,使得lambda表达式更加精简,也可以理解为lambda表达式的缩写形式
注意: 方法引用只能引用已经存在的方法。