函数式接口
1、 函数式接口概念及基本使用
1、函数式接口:有且仅有一个抽象方法的接口,函数式接口就是Lambda表达式使用的前提
2、 Java中的函数式编程体现的就是Lambda表达式,所以函数式接口就是可以适用于Lambda使用的接口,
只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导
注:@FunctionalInterface 在接口上加上这个注解就表达该接口是函数式接口
public class MyInterfaceDemo {
public static void main(String[] args) {
//函数式接口做为局部变量时,可以把Lambda表达式赋值给它
MyInterFace my = ()-> System.out.println("函数式接口");
my.show();
}
}
//加上这个注解,就表示它是函数式接口,在到里面添加一个抽象方法,注解就会报错
@FunctionalInterface
public interface MyInterFace {
void show();
}
2、函数式接口做为方法参数
需求:
1. 定义一个类(RunnableDemo),在类中提供两个方法
2. 一个方法是:startThread(Runnable r),方法参数Runnable是一个函数式接口
3. 一个方法是主方法,在主方法中调用startThread方法
4. 如果方法的参数是一个函数式接口,我们可以使用Lambda表达式作为参数传递
例如:StartThread(() -> System.out.println(Thread.currentThread().getName()+”线程启动了”))
public class RunnableDemo {
public static void main(String[] args) {
//第一种:匿名内部类的方式
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程启动了!");
}
});
//第二种:Lambda表达式
startThread(()->{
System.out.println(Thread.currentThread().getName()+"线程启动了!");
});
}
//Runnable为函数式接口,Ctrl+B可以查看源码
public static void startThread(Runnable r){
new Thread(r).start();//开启一个线程
}
}
3、 函数式接口作为方法的返回值
如果方法的返回值是一个函数式接口,可以使用Lambda表达式作为结果返回
例如:private static Comparator<String> getComparator(){
Return(s1,s2) -> s1.length() - s2.length();
}
/*需求:
1.定义一个类ComparatorDemo,在类中提供两个方法
2.一个方法是:Comparator<String> getComparator()方法返回值Comparator是一个函数式接口
3.一个方法是主方法,在主方法中调用getComparator()方法
* */
public class ComparatorDemo {
public static void main(String[] args) {
//构造使用场景
//定义集合,存储字符串元素
ArrayList<String> arr = new ArrayList<String>();
arr.add("aaaaa");
arr.add("ccc");
arr.add("bbbbbb");
arr.add("ddd");
System.out.println("排序前"+arr);
//Collections.sort(arr);//r如果只是传递arr这个集合参数,就是按照自然顺序进行排序
//System.out.println("排序后"+arr);
//使用Comparator<String>比较器排序
Collections.sort(arr,getComparator());//按照字母顺序,及字符长度进行排序
System.out.println("排序后"+arr);
}
//Comparator<String>比较器排序类的接口,返回的是该接口的实现类对象
private static Comparator<String> getComparator(){
//第一种:匿名内部类的方式(原始方式)
/*Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length()-s2.length();
}
};*/
//第一种:匿名内部类的方式(改进方式)
/*return new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length()-s2.length();
}
};*/
//第二种:Lambda表达式
return(String s1,String s2)->{
return s1.length()-s2.length();
};
}
}
4、 常用的函数式接口(Supplier接口)
Java8在java.util.function包下预定义了大量的函数式接口提供给我们使用
重点学习下面4个接口:Supplier接口、Consumer接口、Predicate接口、Function接口
Supplier<T>包含一个无参的方法:
1、T get() :获得结果
2、该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
3、Supplier<T>接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用
//Supplier接口基本使用
public class SupplierDemo {
public static void main(String[] args) {
//Lambda表达式方式,获取一个字符串数据
String s = getString(()->{
return "中国北京";
});
System.out.println(s);
//Lambda表达式方式,获取一个整数数据
Integer i = getInter(()->{
return 30;
});
System.out.println(i);
}
//定义一个方法,返回一个字符串数据
private static String getString(Supplier<String> sup){
return sup.get();
}
//定义一个方法,返回一个整数数据
private static Integer getInter(Supplier<Integer> sup){
return sup.get();
}
}
5、Supplier小练习
/*练习:
1、定义一个类SupplierTest,在类中提供两个方法
2、一个方法是:int getMax(Supplier<Integer> sup),用于返回一个int数组中的最大值
3、一个方法是主方法,在主方法中调用getMax方法
* */
public class SupplierTest {
public static void main(String[] args) {
//定义一个数组
int[] arr = {12,23,21,34,54,65};
//Lambda表达式的方式,返回值是一个int类型
int maxValue = getMax(()->{
int max =0;
for(int x=1;x<arr.length;x++){
if(arr[x] > max){
max = arr[x];
}
}
return max;
});
System.out.println(maxValue);
}
//用于返回一个int数组中的最大值
private static int getMax(Supplier<Integer> sup){
return sup.get();
}
}
6、常用的函数式接口(Consumer接口)
//Consumer接口基本操作
public class ConsumerDemo {
public static void main(String[] args) {
//第一种:Lambda表达式
operatorString("中国北京",(String s)->{
System.out.println(s);
});
/*第二种:方法引用
operatorString("中国北京",System.out::println);*/
//第三种方式:对字符串反转后再转成字符串进行输出
operatorString("中国北京",(String s)->{
System.out.println(new StringBuilder(s).reverse().toString());
});
System.out.println("------------------------");
//调用2次消费的方法
operatorString("中国北京",(String s)->
System.out.println(s),(String s) ->System.out.println(new StringBuilder(s).reverse().toString())
);
}
//定义一个方法,消费一个字符串数据
private static void operatorString(String name, Consumer<String> con){
con.accept(name);
}
//定义一个方法,用不同的方式消费一个字符串数据两次
private static void operatorString(String name, Consumer<String> con1,Consumer<String> con2){
/*con1.accept(name);
con2.accept(name);*/
//对上面两句改进优化
con1.andThen(con2).accept(name);
}
}
7、Consumer接口小练习
//Consumer小练习
public class ConsumerDemo2 {
public static void main(String[] args) {
String[] strArray = {"浙江杭州,20","江苏南京,30","广东深圳,40"};
pringtInfo(strArray,(String str)->{
String name = str.split(",")[0];
System.out.print("姓名"+name);
},(String str)->{
int age = Integer.parseInt(str.split(",")[1]);
System.out.println(",年龄"+age);
} );
}
private static void pringtInfo(String[] strArray, Consumer<String> con1,Consumer<String> con2){
for(String str: strArray){
con1.andThen(con2).accept(str);
}
}
}
8、常用的函数式接口(Predicate接口)
//Predicate接口test、negate方法
public class PrediccateDemo1 {
public static void main(String[] args) {
//判断hello这个字符串的长度是否大于8
boolean b1 = checkString("hello",(String s)->{
return s.length()>8;
});
System.out.println(b1);
}
//判断给定的字符串是否满足要求
private static boolean checkString(String s, Predicate<String> pre){
//return pre.test(s);
return pre.negate().test(s); //对结果取反
}
}
//Predicate接口的add、or方法
public class PredicateDemo2 {
public static void main(String[] args) {
boolean b3 = checkString("hello",(String s)->s.length()>8,s -> s.length()<15);
System.out.println(b3);
}
//同一个字符串给出两个不同的判断条件,最后把这两个判断的结果做逻辑与运算的结果作为最终的结果
private static boolean checkString(String s, Predicate<String> pre1,Predicate<String> pre2){
/*boolean b1 = pre1.test(s);
boolean b2 = pre2.test(s);
boolean b = b1 && b2;
return b;*/
//add方法对上面的代码进行优化
//return pre1.and(pre2).test(s);
//or方法
return pre1.or(pre2).test(s);
}
}
9、Predicate接口小练习
//Predicate小练习
public class PredicateDemo3 {
public static void main(String[] args) {
String[] arrString = {"浙江杭州,30","西安,31","深圳,33","四川成都,34"};
ArrayList<String> array = myFilter(arrString,s->s.split(",")[0].length()>2,
s->Integer.parseInt(s.split(",")[1])>33);
for(String str: array){
System.out.println(str);
}
}
//通过Predicate接口拼装,将符合要求的字符串筛选到集合中
private static ArrayList<String> myFilter(String[] strArray, Predicate<String> pre1, Predicate<String> pre2){
//定义一个集合
ArrayList<String> array = new ArrayList<String>();
//遍历数组
for(String str:strArray){
if(pre1.and(pre2).test(str)){
array.add(str);
}
}
return array;
}
}
10、常用的函数式接口(Function接口)
//Function接口的2个方法的基本使用
public class FunctionDemo {
public static void main(String[] args) {
//第一种:Lambda表达式调用第一个方法
convery("100",(String s)->{
return Integer.parseInt(s);
});
//第二种:方法引用调用第一个方法
convery("100",Integer::parseInt);
//Lambda表达式调用第二个方法
convery1(100,(Integer i)->{
return String.valueOf(i+500);
});
//Lambda表达式调用第三个方法
convery2("100",(String s)->{
return Integer.parseInt(s);
},(Integer i)->{
return String.valueOf(i+500);
});
}
//定义一个方法,把字符串转换为int类型,在控制台输出
private static void convery(String s, Function<String,Integer> fun){
//Integer i = fun.apply(s);
int i = fun.apply(s); //Integer和int类型接收都可以
System.out.println(i);
}
//把一个int类型的数据加上一个整数过后,转换为字符串在控制台输出
private static void convery1(Integer i,Function<Integer,String> fun){
String s = fun.apply(i);
System.out.println(s);
}
//把一个字符串转换为int类型,把int类型加上一个整数过后,转换为字符串在控制台输出
private static void convery2(String s,Function<String,Integer> fun1,Function<Integer,String> fun2){
/*Integer i = fun1.apply(s);
String ss = fun2.apply(i);
System.out.println(ss);*/
//对上面代码进行优化
String ss = fun1.andThen(fun2).apply(s);
System.out.println(ss);
}
}
11、Function接口小练习
//Function接口小练习
public class FunctionDemo1 {
public static void main(String[] args) {
String s = "中国北京,30";
/*convert(s,(String ss)->{
return s.split(",")[1];
},(String ss)->{
return Integer.parseInt(ss);
},(Integer i)->{
return i+70;
});*/
//对上面代码进行优化
convert(s,ss->s.split(",")[1],ss->Integer.parseInt(ss),i->i+70);
}
private static void convert(String s, Function<String,String> fun1, Function<String,Integer> fun2,Function<Integer,Integer> fun3){
Integer i = fun1.andThen(fun2).andThen(fun3).apply(s);
System.out.println(i);
}
}