把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体
方法引用必须满足以下几个条件:
1.引用处必须是函数式接口
2,被引用的方法必须已经存在
3,被引用方法的形参和返回值
需要跟抽象方法保持一致
4.被引用方法的功能要满足当前需求
比如,使用Arrays.sort方法时我们需要实现一个Comparator接口的匿名类,使用方法引用后,可以使用已定义的满足上述条件的方法进行实现。
Arrays.sort(arr,new Comparator(){@override
public 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() {
@Override
public 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 list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "4", "5");
// 使用stream和匿名内部类
List iList = list.stream().map(new Function() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
}).collect(Collectors.toList());
//System.out.println(iList);
// 使用stream和lambda
// 引用方法时比lambda更简洁
List 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 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 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 list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc");
// 转换为大写并打印
// 本例中的String::toUpperCase
list.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 list =new ArrayList<>();
Collections.addAll(list,1,2,3,4,5);
//2.收集到数组当中
/*
Integer[] arr = list.stream().toArray(new IntFunction() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
*/
// 将以上代码改成方法引用:
// 注意事项:数组的类型,需要跟流中数据的类型保持一致。
Integer[] arr = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr));
}
}