Java方法引用
- 基础知识
- 什么是方法引用?
把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体
- 使用方法引用的条件
方法引用必须满足以下几个条件:
1.引用处必须是函数式接口
2,被引用的方法必须已经存在
3,被引用方法的形参和返回值
需要跟抽象方法保持一致
4.被引用方法的功能要满足当前需求
比如,使用Arrays.sort方法时我们需要实现一个Comparator接口的匿名类,使用方法引用后,可以使用已定义的满足上述条件的方法进行实现。
Arrays.sort(arr,new Comparator<Integer>(){@overridepublic int compare(Integer o1,Integer o2){return o2 -o1;}});
可以使用如下方法:
public int subtraction(int nl,int n2){return n2 -n1;}
示例,如下:
import java.util.Arrays;
import java.util.Comparator;public class FuncInvokeDemo1 {public static void main(String[] args) {//需求:创建一个数组,进行倒序排列Integer[] arr ={3,5,4,1,6,2};//1.匿名内部类实现/*Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});// 输出System.out.println(Arrays.toString(arr));*///2.lambda表达式实现Arrays.sort(arr, (Integer o1, Integer o2) -> {return o2 - o1;});System.out.println(Arrays.toString(arr));//3.lambda表达式简化格式实现/*Arrays.sort(arr, (o1, o2) -> o2 - o1);System.out.println(Arrays.toString(arr));*///4.方法引用//需要满足的条件://a.引用处需要是函数式接口//b.被引用的方法需要己经存在//c.被引用方法的形参和返回值需要跟抽象方法的形参和返回值保持一致//d.被引用方法的功能需要满足当前的要求//本类中的示例静态方法subtraction满足要求,可用于方法引用// 使用双冒号::操作符,表示把subtraction方法当成实现的接口的抽象方法的方法体Arrays.sort(arr, FuncInvokeDemo1::subtraction);}/*** 被引用的方法体实现* @param i1 参数1* @param i2 参数2* @return 参数2-参数1*/public static int subtraction(Integer i1, Integer i2){return i2 - i1;}
}
- 小结
1.什么是方法引用?
把已经存在的方法拿过来用,当做函数式接口中抽象方法的方法体
2.::是什么符号?方法引用符
3.方法引用时要注意什么?
●需要有函数式接口
●被引用方法必须已经存在
●被引用方法的形参和返回值需要跟抽象方法保持一致
●被引用方法的功能要满足当前的需求
- 方法引用的分类
- 引用静态方法
格式:类名::静态方法
范例:Integer::parseInt
练习:
集合中有以下数字,要求把他们都变成int类型“1”“2”“3”“4”“5”。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;public class FInvokeDemo2 {public static void main(String[] args) {// 创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "1", "2", "3", "4", "5");// 使用stream和匿名内部类List<Integer> iList = list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s);}}).collect(Collectors.toList());//System.out.println(iList);// 使用stream和lambda// 引用方法时比lambda更简洁List<Integer> iList2 = list.stream().map(Integer::parseInt).collect(Collectors.toList());System.out.println(iList2);}
}
- 引用成员方法
格式:对象::成员方法
①其他类:其他类对象::方法名
②本类:this::方法名
③父类:super::方法名
注意:引用本类的静态方法时也需要使用类名进行引用,而不能使用this关键字。另外,引用本类的成员方法时,也不能在本类的静态方法里使用this关键字引用,需要首先new一个本类的对象才可以。因此,使用this::和super::的引用处不能是静态方法内。
练习1:
集合中有下些名字,按照要求过滤数据
数据:"张无忌","周芷若","赵敏","张强","张三丰"
要求:只要以张开头,而且名字是3个字的
提供方法体的外部类:
public class StringOperation {/*** 方法引用体* @param s* @return*/public boolean stringJudge(String s){return s.startsWith("张") && s.length() == 3;}
}
使用方法体的代码:
import java.util.ArrayList;
import java.util.Collections;public class FInvokeDemo3 {public static void main(String[] args) {// 创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");// 过滤数据并打印/*list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));*/// 引用成员方法时可以new一个对象list.stream().filter(new StringOperation()::stringJudge).forEach(s -> System.out.println(s));// 引用成员方法前创建一个对象// 然后使用对象名进行引用StringOperation so = new StringOperation();list.stream().filter(so::stringJudge).forEach(s -> System.out.println(s));}
}
练习2:
GUI界面中点击事件的方法引用写法
- 引用其他类的成员方法
- 引用本类的成员方法
- 引用父类的成员方法
- 引用构造方法
格式:类名::new
范例:Student::new
引用构造方法一般是为了创建对象。
练习:
集合里面存储姓名和年龄,比如:张无忌,15
要求:将数据封装成Student对象并收集到List集合中
代码如下:
public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 此方法用于匹配流里的map方法实现体* @param str*/public Student(String str){this.name = str.split(",")[0];this.age = Integer.valueOf(str.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 + "}";}
}
引用构造方法:
import java.util.ArrayList;
import java.util.Collections;public class FInvokeDemo4 {public static void main(String[] args) {// 创建对象并添加ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌,25","周芷若,31","赵敏,21","张强,18","张三丰,57");// 利用stream封装并打印list.stream().map(Student::new).forEach(student -> System.out.println(student));}
}
- 其他调用方式
- 使用类名引用成员方法(理解起来有点难度)
格式:类名::成员方法
范例:String::substring
方法引用的规则:
1.需要有函数式接口
2.被引用的方法必须已经存在
3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。
4.被引用方法的功能需要满足当前的需求
抽象方法形参的详解:
第一个参数:表示被引用方法的调用者,其决定了可以引用哪些类中的方法在Stream流当中,第一个参数一般都表示流里面的每一个数据。假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法
第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
练习:集合里面一些字符串,要求变成大写后进行输出
import java.util.ArrayList;
import java.util.Collections;public class FInvokeDemo5 {public static void main(String[] args) {/*方法引用(类名引用成员方法)格式类名::成员方法需求:集合里面一些字符串,要求变成大写后进行输出方法引用的规则:1.需要有函数式接口2.被引用的方法必须已经存在3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。4.被引用方法的功能需要满足当前的需求抽象方法形参的详解:第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法在Stream流当中,第一个参数一般都表示流里面的每一个数据。假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法*/// 创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "aaa", "bbb", "ccc");// 转换为大写并打印// 本例中的String::toUpperCaselist.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));}
}
- 引用数组的构造方法
格式:数据类型[]::new
范例:int[]::new
练习:集合中存储一些整数,收集到数组当中
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;public class FInvokeDemo6 {public static void main(String[] args) {//1.创建集合并添加元素ArrayList<Integer> list =new ArrayList<>();Collections.addAll(list,1,2,3,4,5);//2.收集到数组当中/*Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {@Overridepublic Integer[] apply(int value) {return new Integer[value];}});*/// 将以上代码改成方法引用:// 注意事项:数组的类型,需要跟流中数据的类型保持一致。Integer[] arr = list.stream().toArray(Integer[]::new);System.out.println(Arrays.toString(arr));}
}