在编程中,方法引用(Method Reference)是一种技术,它让你能够直接引用一个现有的函数或方法,而无需通过对象实例来调用。这种方法在函数式编程和高阶函数中非常有用,因为它提供了简洁的方式来传递函数行为,使代码更加灵活和可复用。
以下是方法引用的一些特点和用法:
- 直接引用:你可以创建一个方法引用,它直接指向某个类的静态方法或实例方法。例如,
std::sort(myVector.begin(), myVector.end(), std::greater<int>())
中的std::greater<int>()
就是一个函数指针类型的引用,它直接指向greater
函数。 - 类型参数化:方法引用可以接收类型参数,如
[](const T& t) -> void { ... }
,这是一种通用的方法引用,适用于任何接受T
类型参数的函数。 - Lambda表达式:Java和C++11引入了lambda表达式,它们本质上就是方法引用的简化形式,可以直接定义并使用匿名函数。
- 作为函数参数或返回值:方法引用可以被用作其他函数的参数,或者作为函数的返回值,这样可以使接口设计更加简洁。
方法 :以前学习的方法
引用 :把已经有的反复拿过来用,当做函数式接口中的抽象方法的方法体
引用处必须是函数接口
被引用的方法必须是已经存在的
被应用的方法的形参和返回值必须要和抽象方法保持一致
被引用的方法的功能要满足当前需求
改写
import java.util.Arrays; import java.util.Comparator; public class Main { public static void main(String[] args) { Integer arr[]={3,3,4,5,6,7}; Arrays.sort(arr, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2-o1; } }); System.out.println(Arrays.toString(arr)); } }
只有函数式接口能用Lambda表达式简化
import java.util.Arrays; public class Main { public static void main(String[] args) { Integer arr[]={3,3,4,5,6,7}; Arrays.sort(arr, (Integer o1,Integer o2) -> { return o2-o1; }); System.out.println(Arrays.toString(arr)); } }
import java.util.Arrays; public class Main { public static void main(String[] args) { Integer arr[]={3,3,4,5,6,7}; Arrays.sort(arr, (o1,o2) -> o2-o1); System.out.println(Arrays.toString(arr)); } }
方法引用改写条件
1.引用处需要是函数式接口
2.被引用的方法需要已经存在
3.被引用的方法的形参各返回值需要和抽象方法的形参和返回值保持一致
4.被引用的方法的功能需要满足当前需求
import java.util.Arrays; public class Main { public static void main(String[] args) { Integer arr[]={3,3,4,5,6,7}; //表示引用Main类里的subtraction方法 //把这方法作为抽象方法的方法体 Arrays.sort(arr, Main::subtraction); System.out.println(Arrays.toString(arr)); } public static int subtraction(int num1,int num2){ return num2-num1; } }
小结
引用静态方法
格式
类名::静态方法
import java.util.ArrayList; import java.util.Collections; import java.util.Scanner; import java.util.function.Function; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"1","2","3","4","5","6"); //先写匿名内部类 //自动生成方法体 list.stream().map(new Function<String, Integer>() { @Override public Integer apply(String s) { int i=Integer.parseInt(s); return i; } }).forEach(s -> System.out.println(s)); } }
方法引用简化
import java.util.ArrayList; import java.util.Collections; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"1","2","3","4","5","6"); list.stream().map(Integer::parseInt).forEach(s -> System.out.println(s)); } }
引用成员方法
import java.util.ArrayList; import java.util.Collections; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"张三","张思锐","3","4","5","6"); list.stream().filter(s -> s.startsWith("张")).filter(s ->s.length()==3).forEach(s -> System.out.println(s)); } }
import java.util.ArrayList; import java.util.Collections; import java.util.function.Predicate; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"张三","张思锐","张三丰","多多","李四","王五"); list.stream().filter(new Predicate<String>() { @Override public boolean test(String s) { return s.startsWith("张")&&s.length()==3; } }).forEach(s -> System.out.println(s)); } }
方法引用
1.写在其他类当中
public class Judge { public boolean judge(String s){ return s.startsWith("张")&&s.length()==3; } }
import java.util.ArrayList; import java.util.Collections; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"张三","张思锐","3","4","5","6"); //普通的成员方法要对象来调用 //这里也可以先创建对象再去调用 list.stream().filter(new Judge()::judge).forEach(s-> System.out.println(s)); } }
2.写在本类当中
静态方法中是没有this关键字的
因为Main默认是静态的
所以要创建本类的对象
格式 对象::成员方法
import java.util.ArrayList; import java.util.Collections; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"张三","张思锐","3","4","5","6"); //普通的成员方法要对象来调用 //这里也可以先创建对象再去调用 list.stream().filter(new Judge()::judge).forEach(s-> System.out.println(s)); } public static boolean judge(String s){ return s.length()==3&&s.startsWith("张"); } }
引用处不能是静态方法
import java.util.ArrayList; import java.util.Collections; public class Main { public void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"张三","张思锐","3","4","5","6"); //普通的成员方法要对象来调用 //这里也可以先创建对象再去调用 list.stream().filter(this::judge).forEach(s-> System.out.println(s)); } public boolean judge(String s){ return s.length()==3&&s.startsWith("张"); } }
引用构造方法
为什么要引用构造方法
是为了创建对象
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"张三,12","李四,13","王五,15"); //封装成Student类对象,并且放到集合里面去、 List<Student>newlist=list.stream().map(new Function<String, Student>() { @Override public Student apply(String s) { String arr[]=s.split(","); return new Student(arr[0],Integer.parseInt(arr[1])); } }).collect(Collectors.toList()); System.out.println(newlist); } }
构造方法运行完后对象就已经有了
在javabean类里写方法
注意参数类型要和调用处一致(new处)
所以在javabean类里要写一个只有一个形参的方法
Student::new
表示使用了Student类里的构造方法并获得了对象
用类名引用成员方法
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"aaa","bbb","ccc","ddd"); list.stream().map(new Function<String, String>() { @Override public String apply(String s) { return s.toUpperCase(); } }).forEach(s -> System.out.println(s)); } }
用类名引用成员方法改写
import java.util.ArrayList; import java.util.Collections; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"aaa","bbb","ccc"); list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s)); } }
被引用方法的形参和返回值要和抽象方法中的形参和返回值一致
方法引用的规则 是类名引用成员方法独有的
需要有函数式接口
被引用的方法必须已经存在
被引用方法的形参需要和抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致
拿着流中的每一个数据去调用String类中的toUpperCase方法
方法的返回值就是转换之后的结果
局限性
不能引用所有类中的成员方法
是跟抽象方法的第一个参数(形参)有关,这个参数是什么类型的,就只能引用这个类中的方法
引用数组的构造方法
数组是没有构造方法的
但是有一个专门描述数组的类,有构造方法
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"张三","李四","王五"); String[] array = list.stream().toArray(String[]::new); for(String s:array)System.out.println(s); } }
总结