2020-12-29
函数式接口
java中没有函数所以用它
函数:
1、都是处理问题的逻辑;
2、函数不属于任何一个类型或者对象;
3、在存储中函数一般存储在文件上;
4、在java中没有函数这样的概念。
弊端:只能通过方法来传递一些基础的数据,而无法传递解决问题的方案
处理的方法:使用接口将方法给包起来,这个接口的类型就比做是一个函数的类型。
具体的方法:就是将一个抽象方法包裹在一个接口中,那么这个接口将来的用途就是这个方法的实现。那么这个接口的实现类对象就可以看作是一个函数类型的引用。
这种实现的方式我们称之为函数式编程。
学习过的函数式编程:
1、之前学习的Collections(list,Compartor)
2、一个list是存储原始数据的容器
3、不光有存储数据的容器,还可以传递一个比较器的类型
4、这个类型就是一个函数式接口
5、传递之后要重写比较的策略,传递的参数就是一个实现类的对象
以上步骤就是函数式编程
jdk中提供的函数式接口
意义:我们自己在定义函数式接口然后使用起来比较麻烦,需要定义接口,需要实现类对象。需要对方法进行实现。
Java中给我们提供可以写非常常用的逻辑的函数式接口。这些接口分为不同的类型,用于解决不同的问题。
函数式接口罗列:
1、Consumer<T> 消费型的接口accept
2、Supplier<T> 供给型的接口get
3、Function<T,R> 函数型接口 将T类型,向R类型转换apply
4、Perdecita<T> 断言型接口(判断 test
消费型接口:
Consumer<T>
消费就是将数据进去之后,数据处理完毕就结束了,不需要在返回
T传递数据的类型 消费的类型
void accept(T t)
import java.util.function.Consumer;
public class Demo02_消费型接口 {
public static void main(String[] args) {
/*test(998,new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println("每次消费"+t+"非常开心");
}
});*/
//用lambda表达式
test(998,x->System.out.println("每次消费"+x+"非常开心"));
}
public static void test(int money,Consumer<Integer> con) {
for(int i=0;i<2;i++) {
con.accept(money);
}
}
}
总结:使用消费类型的接口不用定义接口直接使用,消费类型的接口的实现类的对象来进行传递具体的消费方案就可以了。
这就实现了类型作为参数可以进行传递
方法的引用
解释:一个lambda体中已经有了一个方法可以对这个lambda体进行了实现,那么就不需要在接收实现类的对象作为函数的类型,这个方法就可以直接作为实现类的对象,这个方法就可直接写在lambda体中即可,这个方法我们就可以把它看作是一个函数
方法作为实现类对象的格式:
1、普通方法 对象名称::方法名
2、静态方法 类名::方法名
3、构造方法实现转换的格式 类名::new(new Person()->Person::new)
总结:方法直接作为函数,直接作为实现类的对象
供给型接口
Supplier<T>
获取到T类型的数据:T get()
作用:调用这个get方法可以获取到t类型的产出
函数型接口
Function<T,R>
作用:
R Apply(T)将T类型的数据向R类型转换
函数型接口的默认方法
Function andThen(function fun)
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
public class Demo06_andThen {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
Collections.addAll(list, "1111","333","444","111","222");
Function<String, Integer> fun1 = Integer::parseInt;
//List<Integer> tranf = tranf(list,fun1);
Function<Integer, Integer> fun2 = x->x+1;
//List<Integer> num2Num = num2Num(tranf,fun2);
//System.out.println(num2Num);
Function<String, Integer> fun3 = fun1.andThen(fun2);
List<Integer> tranf = tranf(list,fun3);
System.out.println(tranf);
}
//将转换后的集合中的每个数字都加1在存储到一个新的集合中
//先将String类型转换为Integer类型,用Function接口
public static List<Integer> num2Num(List<Integer> list, Function<Integer, Integer> fun){
List<Integer> res = new ArrayList<Integer>();
for (Integer i : list) {
Integer apply = fun.apply(i);
res.add(apply);
}
return res;
}
public static List<Integer> tranf(List<String> list,Function<String, Integer> fun){
List<Integer> res = new ArrayList<Integer>();
for (String str : list) {
Integer apply = fun.apply(str);
res.add(apply);
}
return res;
}
}
作用:拿上一次转换后的结果调用这个方法,需要把第二次转换的方案作为参数传递。得到二次转换的结果
断言型接口
Perdecita<T>
概述:如果需要对一个数据进行判断,并且判断之后有一个布尔类型的返回值,这时就可以使用断言型接口
断言型接口就可以当作一个函数类型或者是一个实现类的对象直接来使用了
Boolean Test(T t)
断言型接口中的默认方法:
Perdicate<T>and(Perdicate<T>):and方法调用者是T类型的,函数参数是T类型的函数,返回值也是T类型的函数
Perdicate<T>or(Perdicate<T>):参数、调用者和返回值都是t类型的函数
streammingAPI
描述:jdk中给我们提供了一个Stream这样的类型,可以获取这样的流对象来操作数据
好处:
1、避免代码中反复的遍历
2、。。。。。。。。判断
Stream对象的获取
从数组中获取:Stream of(T...values)用于获取数组中的流对象
从单列集合中获取:Stream()直接获取
从双列集合中获取,不能直接获取,先要转成单列集合获取:
keySet().stream()键
values().stream()值
entrySet().stream()键值对
stream中的常用方法
stream作用就是提供了一些方法可以对数据进行:过滤、统计、汇总、输出等
说明:流对象一旦调用,就会返回一个流对象,这个新的流对象就是上一个流对象调用方法的产出,上一个对象就不能在使用了
方法的分类:
1、终结方法
调用了终结方法后,流对象就不再返回了。最典型的终结方法:foreach,count获取当前流对象的大小
2、延迟方法
调用了延迟方法之后 就会返回一个新的流对象可以使用这个流对象再去调用方法。
终结方法:
forEach()对流中的每个元素进行操作
long count()获取流中的元素的个数
延迟方法:
filter(Perdicate per)对流中元素过滤
Map(function fun)原数据转成新的数据,存储到流中
Limit(long l)只保留前几个元素
skip(long l)除了前几个元素,其余元素保留
sorted()对流中的元素进行自然顺序的排序(升序)
concat()将两个流对象拼接返回一个新的流对象
distinct()对流中的元素进行去重返回一个新流