方法引用
1、概述
- 就是把已有的方法拿过来用,当做函数式接口中抽象方法的方法体
-
像之前这样写排序
-
Lambda表达式都不是最简洁的
Arrays.sort(arr, (o1, o2) -> o2 - o1);
-
比如现在已经有一个写好的subtraction方法,在比较规则这里可以直接引用subtraction方法
2、注意事项
-
也不是什么方法都可以被引用的,必须满足以下要求:
- 引用处必须是函数式接口
- 被引用的方法必须是已经存在的
- 被引用方法的形参和返回值需要跟抽象方法保持一致
- 被引用方法的功能要满足当前需求
-
要求1:引用处必须是函数式接口
-
要求2:被引用的方法必须是已经存在的
-
要求3:被引用方法的形参和返回值需要跟抽象方法保持一致
-
要求4:被引用方法的功能要满足当前需求
3、例子
package com.app.demo34_method_reference_test;
import java.util.Arrays;
import java.util.Comparator;
public class Tets1 {
public static void main(String[] args) {
/*
方法引用
需求:创建一个数组,进行倒序排列
*/
Integer[] arr = {3, 5, 1, 2, 6, 4};
// 匿名内部类
/*Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});*/
// lambda表达式
// 因为第二个参数的类型Comparator是一个函数式接口
/*Arrays.sort(arr, (Integer o1, Integer o2) -> {
return o2 - o1;
});*/
// lambda表达式简化格式
// Arrays.sort(arr, (o1, o2) -> o2 - o1);
// 方法引用
// 1.引用处必须是函数式接口
// 2.被引用的方法必须已存在
// 3.被引用方法的形参和返回值必须跟抽象方法的形参和返回值一致
// 4.被引用方法的功能必须满足当前的需求
// 表示引用Test1类里面的subtraction方法
// 把这个方法当做抽象方法的方法体
Arrays.sort(arr, Tets1::subtraction);
System.out.println(Arrays.toString(arr));
}
// 可以是Java已经写好的,也可以是一些第三方的工具类
public static int subtraction(int num1, int num2) {
return num2 - num1;
}
}
[6, 5, 4, 3, 2, 1]
Process finished with exit code 0
小结
1、什么是方法引用?
- 把已经存在的方法拿过来用,当做函数式接口抽象方法的方法体。
2、::
是什么符号?
- 方法引用符号
3、方法引用时要注意什么?
- 引用处需要是函数式接口
- 被引用的方法必须是已存在的
- 被引用的方法的形参和返回值需要跟抽象方法一致
- 被引用的方法的功能要满足当前的需求
4、分类
(1)引用静态方法
-
格式:
类名::静态方法
-
范例:
Integer::parseInt
-
练习:
集合中有以下数字,要求把它们都变成int类型
“1”, “2”, “3”, “4”, “5”
package com.app.demo34_method_reference_test; import java.util.ArrayList; import java.util.Collections; import java.util.function.Function; public class Test2 { public static void main(String[] args) { /* 练习(引用静态方法): 集合中有以下数字,要求把它们都变成int类型 "1", "2", "3", "4", "5" */ ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "1", "2", "3", "4", "5"); // 把它们都变成int类型 // 匿名内部类 /*list.stream().map(new Function<String, Integer>() { @Override public Integer apply(String s) { int n = Integer.parseInt(s); return n; } }).forEach(s -> System.out.print(s + " "));*/ // lambda表达式 /*list.stream() .map( s -> Integer.parseInt(s)) .forEach(s -> System.out.print(s + " "));*/ // 方法引用 list.stream().map(Integer::parseInt).forEach(s -> System.out.print(s + " ")); } }
1 2 3 4 5 Process finished with exit code 0
(2)引用成员方法
-
格式:
对象::成员方法
-
引用其他类:
其他类对象::成员方法
-
引用本类:
this::成员方法
-
引用父类:
super::方法名
-
注意:不能在静态方法里引用本类、父类的成员方法
-
练习1:
集合中有一些名字,按照要求过滤数据:
名字:"张无忌","周芷若","赵敏","张强","张三丰" 要求:只要以张开头,而且名字是3个字的
package com.app.demo34_method_reference_test; import java.util.ArrayList; import java.util.Collections; import java.util.function.Consumer; import java.util.function.Predicate; public class Test3 { public static void main(String[] args) { /* 练习(引用成员方法): 集合中有一些名字,按照要求过滤数据: 名字:"张无忌","周芷若","赵敏","张强","张三丰" 要求:只要以张开头,而且名字是3个字的 */ // 1.创建集合,添加数据 ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "张无忌","周芷若","赵敏","张强","张三丰"); // 2.只要以张开头,而且名字是3个的 // 匿名内部类 /*list.stream().filter(new Predicate<String>() { @Override public boolean test(String s) { return s.startsWith("张") && s.length() == 3; } }).forEach(new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } });*/ // lambda表达式 /*list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3) .forEach(s -> System.out.println(s));*/ // 引用其他类的成员方法: // 格式:其他类对象::成员方法 /*list.stream().filter(new StringOperation()::stringJude) .forEach(System.out::println);*/ // 引用本类的成员方法: // 格式:this::成员方法 // this报错原因:因为在静态方法中是没有this的 /*list.stream().filter(this::stringJude) .forEach(System.out::println);*/ // 解决办法:直接new本类对象即可 list.stream().filter(new Test3()::stringJude).forEach(System.out::println); } public boolean stringJude(String s) { return s.startsWith("张") && s.length() == 3; } }
张无忌 张三丰 Process finished with exit code 0
-
练习2:
GUI界面中点击事件的方法引用写法
package com.app.demo34_method_reference_test; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /* 界面父类 */ class MyJFrame extends JFrame{ public void superMethod1(ActionEvent e) { System.out.println("注册按钮被点击了一下~"); } } /* 界面类 */ class JFrameTest extends MyJFrame{ // 创建按钮对象 JButton login = new JButton(); JButton register = new JButton(); public JFrameTest() { // 初始化界面 initJFrame(); // 给界面添加组件 initView(); this.setVisible(true); } public void initView() { login.setText("登录"); login.setBounds(250, 150, 100, 100); // 引用本类的成员方法 login.addActionListener(this::thisMethod1); this.getContentPane().add(login); register.setText("注册"); register.setBounds(250, 250, 100, 100); // 引用父类的成员方法 register.addActionListener(super::superMethod1); this.getContentPane().add(register); } public void thisMethod1(ActionEvent e) { System.out.println("登录按钮被点击了一下~"); } //初始化组件,在这个界面中添加内容 public void initJFrame() { this.setSize(633, 423);//设置宽高 this.setTitle("界面 V1.0");//设置标题 this.setDefaultCloseOperation(3);//设置关闭模式 this.setLocationRelativeTo(null);//居中 this.setAlwaysOnTop(true);//置顶 this.setLayout(null);//取消内部默认布局 } } /* 测试类 */ public class Test4 { public static void main(String[] args) { new JFrameTest(); } }
(3)引用构造方法
-
格式:
类名::new
-
范例:
Student::new
-
练习:
集合里面存储姓名和年龄,比如:张无忌,15
要求:将数据封装成Student对象并收集到List集合中
package com.app.demo34_method_reference_test; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } // 构造方法 public Student(String s) { this.name = s.split(",")[0]; this.age = Integer.parseInt(s.split(",")[1]); } /** * 获取 * * @return name */ public String getName() { return name; } /** * 设置 * * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * * @return age */ public int getAge() { return age; } /** * 设置 * * @param age */ public void setAge(int age) { this.age = age; } public String toString() { return "Student{name = " + name + ", age = " + age + "}"; } } public class Test5 { public static void main(String[] args) { /* 练习(引用构造方法): 集合里面存储姓名和年龄,比如:张无忌,15 要求:将数据封装成Student对象并收集到List集合中 */ // 1.创建集合,添加数据 ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "张无忌,15", "周芷若,19", "关羽,23", "甄姬,44"); System.out.println(list); // 2.将数据封装成Student对象 /*List<Student> studentList = list.stream().map(new Function<String, Student>() { @Override public Student apply(String s) { return new Student(s.split(",")[0], Integer.parseInt(s.split(",")[1])); } }).collect(Collectors.toList());*/ List<Student> studentList = list.stream() .map(Student::new) // 引用构造方法 .collect(Collectors.toList()); System.out.println(studentList); } }
[张无忌,15, 周芷若,19, 关羽,23, 甄姬,44] [Student{name = 张无忌, age = 15}, Student{name = 周芷若, age = 19}, Student{name = 关羽, age = 23}, Student{name = 甄姬, age = 44}] Process finished with exit code 0
(4)其他引用方式
-
使用类名引用成员方法
-
格式:
类名::成员方法
-
范例:
String::substring
-
练习:
集合里面一些字符串,要求变成大写后进行输出
package com.app.demo34_method_reference_test; import java.util.ArrayList; import java.util.Collections; import java.util.function.Function; public class Test6 { public static void main(String[] args) { /* 练习(使用类名引用成员方法): 集合里面一些字符串,要求变成大写后进行输出 方法引用的规则: 1、需要有函数式接口 2、被引用的方法必须已经存在 3、被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致 4、被引用方法的功能需要满足当前的需求 抽象方法形参的详解: 第一个形参:表示被引用方法的调用者,决定了可以引用哪些类中的方法 在Stream流当中,第一个参数一般表示流里面的每一个数据 假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法 第二个形参到最后一个形参:跟被引用方法的形参保持一致, 如果没有第二个形参,说明被引用的方法需要是无参的成员方法 局限性: 不能引用所有类中的成员方法。 是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法 */ */ // 1.创建集合,添加数据 ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "abc", "AAA", "bbb"); // 2.要求变成大写后进行输出 /*list.stream().map(new Function<String, String>() { @Override public String apply(String s) { return s.toUpperCase(); } }).forEach(s -> System.out.println(s));*/ list.stream() .map(String::toUpperCase) // 使用类名引用成员 .forEach(s -> System.out.println(s)); } }
ABC AAA BBB Process finished with exit code 0
-
-
引用数组的构造方法
-
格式:
数据类型[]::new
-
范例:
int[]::new
-
练习:
集合中存储一些整数,收集到数组当中。
package com.app.demo34_method_reference_test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.function.IntFunction; import java.util.function.Supplier; import java.util.stream.Collectors; public class Test7 { public static void main(String[] args) { /* 练习:引用数组的构造方法 集合中存储一些整数,收集到数组当中。 细节: 数组的类型,需要跟流中数据的类型保持一致。 */ // 1.创建集合,添加数据 ArrayList<Integer> list = new ArrayList<>(); Collections.addAll(list, 1, 3, 2, 9, 5, 6); // 2.收集到数组当中 /*Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() { @Override public Integer[] apply(int value) { return new Integer[value]; } });*/ Integer[] arr = list.stream() .toArray(Integer[]::new); // 引用数组的构造方法 System.out.println(Arrays.toString(arr)); } }
[1, 3, 2, 9, 5, 6] Process finished with exit code 0
-
小结
1、引用静态方法的格式?
类名::静态方法
2、引用成员方法的格式?
引用其他类 ——> 对象::成员方法
引用本类 ——> this::成员方法
引用父类 ——> super::成员方法
3、引用构造方法的格式?
类名::new
4、如何使用类名引用成员方法,注意点是什么?
-
格式:
类名::成员方法
-
注意点:
- 不能引用所有类中的成员方法;
- 如果抽象方法的第一个参数是A类型的,那就只能引用A类中的成员方法
5、如何引用数组的构造方法?
数据类型[]::new
5、综合小练习
练习1
- 集合中存储一些字符串的数据,比如:张三,23
- 要求:收集到Student类型的数组当中(使用方法引用完成)
package com.app.demo34_method_reference_test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
/*
学生类
*/
class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 引用构造方法
public Student(String s) {
this.name = s.split(",")[0];
this.age = Integer.parseInt(s.split(",")[1]);
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
public class Test8 {
public static void main(String[] args) {
/*
方法引用的综合小练习:
练习1:
集合中存储一些字符串的数据,比如:张三,23
要求:收集到Student类型的数组当中(使用方法引用完成)
*/
// 1.创建集合,添加数据
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三,23", "李四,24", "王五,25");
System.out.println(list);
// 2.收集到Student类型的数组当中
Student[] stuArr = list.stream()
.map(Student::new) // 先将String 转换成 Student对象
.toArray(Student[]::new); // 再将Student对象 收集到 数组中
System.out.println(Arrays.toString(stuArr));
}
}
[张三,23, 李四,24, 王五,25]
[Student{name = 张三, age = 23}, Student{name = 李四, age = 24}, Student{name = 王五, age = 25}]
Process finished with exit code 0
练习2
- 创建集合添加学生对象,学生对象属性:name,age
- 要求:只获取姓名并放到数组当中(使用方法引用完成)
package com.app.demo34_method_reference_test;
import java.util.ArrayList;
import java.util.Arrays;
/*
学生类
*/
class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 引用构造方法
public Student(String s) {
this.name = s.split(",")[0];
this.age = Integer.parseInt(s.split(",")[1]);
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
public class Test9 {
public static void main(String[] args) {
/*
方法引用的综合小练习
练习2:
创建集合添加学生对象,学生对象属性:name,age
要求:只获取姓名并放到数组当中(使用方法引用完成)
*/
// 1.创建集合,添加数据
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("张三丰", 34));
list.add(new Student("杨幂", 32));
list.add(new Student("孙悟空", 94));
list.add(new Student("龙皮", 56));
System.out.println(list);
// 2.只获取姓名并放到数组当中
String[] arr = list.stream()
.map(Student::getName) // 先将Student对象 转换成 String,然后只获取姓名
.toArray(String[]::new); // 最后将姓名信息放到数组中
System.out.println(Arrays.toString(arr));
}
}
[Student{name = 张三丰, age = 34}, Student{name = 杨幂, age = 32}, Student{name = 孙悟空, age = 94}, Student{name = 龙皮, age = 56}]
[张三丰, 杨幂, 孙悟空, 龙皮]
Process finished with exit code 0
练习3:
- 创建集合添加学生对象,学生对象属性:name,age
- 要求:把姓名和年龄拼接成:张三-23的字符串,并放到数组当中(使用方法引用完成)
package com.app.demo34_method_reference_test;
import java.util.ArrayList;
import java.util.Arrays;
class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 构造方法
public Student(String s) {
this.name = s.split(",")[0];
this.age = Integer.parseInt(s.split(",")[1]);
}
/*
方法引用:
1、引用处需要是函数式接口
2、被引用的方法必须已经存在
3、被引用的方法的形参和返回值必须与需要跟抽象方法保持一致
4、被引用的方法的功能需要满足当前的需求
*/
// 引用静态方法
public static String StringJoint(Student student) {
return student.getName() + "-" + student.getAge();
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
public class Test10 {
public static void main(String[] args) {
/*
方法引用的综合小练习
练习3:
创建集合添加学生对象,学生对象属性:name,age
要求:把姓名和年龄拼接成:张三-23的字符串,并放到数组当中(使用方法引用完成)
*/
// 1.创建集合,添加数据
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("张三", 13));
list.add(new Student("李四", 14));
list.add(new Student("王五", 15));
list.add(new Student("铁蛋", 23));
list.add(new Student("赵六", 11));
list.forEach(s -> System.out.println(s));
// 2.把姓名和年龄拼接成:张三-23的字符串,并放到数组当中
String[] arr = list.stream()
// 先将Student对象 转换成 String,然后在Student类中定义静态方法StringJoint,按照要求拼接:姓名-年龄
.map(Student::StringJoint)
// 最后将拼接结果放到数组中
.toArray(String[]::new);
System.out.println(Arrays.toString(arr));
}
}
Student{name = 张三, age = 13}
Student{name = 李四, age = 14}
Student{name = 王五, age = 15}
Student{name = 铁蛋, age = 23}
Student{name = 赵六, age = 11}
[张三-13, 李四-14, 王五-15, 铁蛋-23, 赵六-11]
Process finished with exit code 0