Java-方法引用,lambda表达式的另一种写法

操千曲而后晓声,观千剑而后识器

基本规则

把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体

方法引用的初使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package function;

import java.util.Arrays;
import java.util.Comparator;

public class FunctionDemo1 {
public static void main(String[] args) {
// 创建一个整型数组,对其倒序排序
Integer[] arr = {1, 5, 6, 2, 4, 8, 3, 9};

//匿名内部类
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println(Arrays.toString(arr));

System.out.println("----------------------------------");


// lambda表达式
Arrays.sort(arr, ((o1, o2) -> o2 - o1));
System.out.println(Arrays.toString(arr));

System.out.println("----------------------------------");


// 方法引用
Arrays.sort(arr,FunctionDemo1::sub);
System.out.println(Arrays.toString(arr));

}

public static int sub(int a,int b){
return b-a;
}


}

方法引用的分类

引用静态方法

格式: 类名::静态方法 范例 : Integer::paseInt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 将“1”,“2”,“3”,“4”,“5”转为数字12345

package function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Function;

public class FunctionDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"1", "2", "3", "4", "5");

// Stream流转为数字
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
int i = Integer.parseInt(s);
return i;
}
}).forEach(num -> System.out.println(num));

System.out.println("-------------------------------------------");

// 使用方法引用
// 使用引用方法 原方法内部的参数是什么已经变得不重要
// 而是关注内部逻辑,内部逻辑相同就可以用其他方法引用
list.stream().map(Integer::parseInt).forEach(System.out::println);
}



}

引用成员方法


引用本类、父类方法,需要在非静态方法中引用,静态类中没有this

引用其他类的成员方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 调用方法的类

package function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;

public class FunctionDemo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三丰", "张无忌", "胡图图", "张三", "佩奇");

// Stream流
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));

System.out.println("------------------------------------");


// 方法引用 引用其他类的方法
list.stream().filter(new Zhang3Judge()::pd).forEach(System.out::println);

}
}

// 其他类
package function;

public class Zhang3Judge {
public boolean pd(String s) {
return s.startsWith("张") && s.length() == 3;
}
}


引用本类的成员方法

引用父类的成员方法

引用构造方法


引用构造方法就是为了创建这个类的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 需求 : 集合里面存储姓名和年龄,要求封装成Student对象并收集到List集合中
package function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class FunctionDemo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三丰-23", "张三丰-23", "Alie-24", "Mike-25", "John-26", "Alan-27", "iKun-28", "Angle-29", "Elen-30");

// 将字符串封装为对象
// String——————>Student
List<Student> newList = list.stream().map(new Function<String, Student>() {
@Override
public Student apply(String s) {
String[] split = s.split("-");
String name = split[0];
String Sage = split[1];
int age = Integer.parseInt(Sage);
return new Student(name, age);
}
}).collect(Collectors.toList());
System.out.println(newList);


System.out.println("-----------------------------");

// 使用构造方法
// 使用构造方法创建对象,需要注意方法的形参是否与构造方法一致,构造方法不需要返回值,但是需要注意构造方法执行后生成的对象跟抽象方法的返回值保持一致
List<Student> newList2 = list.stream().map(Student::new).collect(Collectors.toList());
System.out.println(newList2);


}
}


// 学生类
package function;

public class Student {
private String name;
private Integer age;

public Student() {
}

public Student(String name, Integer age) {
this.name = name;
this.age = age;
}

/*
此处为重要部分,为了匹配抽象方法 构造方法重载
*/
public Student(String str){
String[] split = str.split("-");
this.name = split[0];
this.age = Integer.parseInt(split[1]);
}

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;
}
}

其他调用方式

使用类名引用成员方法

格式: 类名::成员方法

独有的方法引用规则:

  1. 需要有函数式接口
  2. 被引用的方法必须已经存在
  3. 被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需保持一致
  4. 被引用方法的功能需要满足当前要求

抽象方法形参的详解:

第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法

在Stream流中,第一个参数一般都表示流里面的每一个数据

假设流里面的数据都是字符串,那么使用这种方式进行方法引用,只能引用 String这个类中的方法

第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个形参,说明被引用的方法需要是无参的成员方法

局限性:

不能引用所有类中的成员方法

跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;

public class FunctionDemo5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "hello", "world!", "MY", "WorLD");

// 获取list 的 Stream流对象
list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
String s1 = s.toUpperCase();
return s1;
}
}).forEach(System.out::println);

// 方法引用
// 拿着流里面的数据,去调用String类中的toUpperCase方法,方法的返回值就是转换后的结果
list.stream().map(String::toUpperCase).forEach(System.out::println);

}
}

引用数组的构造方法


细节:数组的类型必须和流中的数据类型保持一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package function;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.IntFunction;

public class FunctionDemo6 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 5, 6, 9, 8, 7, 8);

Integer[] array = list.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
System.out.println(Arrays.toString(array));


// 引用数组

System.out.println("===========================");
Integer[] array1 = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(array1));
}
}

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package function;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class FunctionTest1 {
public static void main(String[] args) {

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三丰-23", "张三丰-23", "Alie-24", "Mike-25", "John-26", "Alan-27", "iKun-28", "Angle-29", "Elen-30");
Student[] array = list.stream().map(Student::new).toArray(Student[]::new);
System.out.println(Arrays.toString(array));

}
}

// Student对象
package function;

public class Student {
private String name;
private Integer age;

public Student() {
}

public Student(String name, Integer age) {
this.name = name;
this.age = age;
}

public Student(String str){
String[] split = str.split("-");
this.name = split[0];
this.age = Integer.parseInt(split[1]);
}

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;
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package function;

import java.util.ArrayList;
import java.util.Arrays;

public class FunctionTest2 {
public static void main(String[] args) {
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("zhangsan", 23));
students.add(new Student("lisi", 24));
students.add(new Student("wangwu", 25));

String[] names = students.stream().map(Student::getName).toArray(String[]::new);
System.out.println(Arrays.toString(names));
}
}

// Student类
package function;

public class Student {
private String name;
private Integer age;

public Student() {
}

public Student(String name, Integer age) {
this.name = name;
this.age = age;
}

public Student(String str){
String[] split = str.split("-");
this.name = split[0];
this.age = Integer.parseInt(split[1]);
}

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;
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}