函数式接口和Stream流
1.函数式接口
1.1函数式接口概述
◆概念
有且仅有一个抽象方法的接口
如何检测一个接口是不是函数式接口
◆@FunctionalInterface
放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败
◆注意事项
我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上该注解
1.2常用函数式接口之Supplier
◆Supplier接口
Supplier接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。
常用方法
◆只有一个无参的方法
方法名 | 说明 |
---|---|
T get() | 按照某种实现逻辑(由Lambda表达式实现)返回一个数据 |
◆函数式接口作为方法的返回值
Supplier 变量名=()->{方法体};
T 变量名1= 变量名.get();
例如:获取一个比较字符串长度的方法体
//创建一个Supplier接口实现类的对象
Supplier<Comparator<String>> s=()-> (s1,s2)-> s1.length()-s2.length();
用实现类对象调用get()方法获取Comparator接口的实现类对象
Comparator<String> com = s.get();
◆函数式接口作为方法的参数
例如:利用Supplier开辟一条新的线程
//创建一个Supplier接口实现类的对象
Supplier<Runnable> s1 =()-> ()-> System.out.println("线程方法被启用");
//用实现类对象调用get()方法获取Runnable接口的实现类对象
Runnable run = s1.get();
//开一条新的线程
new Thread(run).start();
1.3常用的函数式接口之Consumer
◆Consumer接口
Consumer接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
◆常用方法
Consumer:包含两个方法
方法名 | 说明 |
---|---|
void accept(T t) | 对给定的参数执行此操作 |
default Consumer andThen(Consumer after) | 返回一个组合的Consumer,依次执行此操作,然后执行 after操作 |
Consumer<String> c=ss-> System.out.println(ss);
c.accept("悦悦");
1.4常用的函数式接口之Predicate
◆Predicate接口
Predicate接口通常用于判断参数是否满足指定的条件
◆常用方法
方法名 | 说明 |
---|---|
boolean test(T t) | 对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值 |
default Predicate negate() | 返回一个逻辑的否定,对应逻辑非 |
default Predicate and(Predicate other) | 返回一个组合判断,对应短路与 |
default Predicate or(Predicate other) | 返回一个组合判断,对应短路或 |
1.5常见函数式接口之Function
◆Function接口
Function<T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值
◆常用方法
方法名 | 说明 |
---|---|
R apply(T t) | 将此函数应用于给定的参数 |
default Function andThen(Function after) | 返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果 |
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.function.Function;
/*
使用lambda表达式分别将以下功能封装到Function对象中:
1、将Map<String, Integer>中所有的值存到ArrayList<Integer>中
2、求存储元素为Integer类型的ArrayList中所有元素的平均数 已知,学生成绩如下:
张三 85
李四 80
王五 90
赵六 95
田七 70
请以学生姓名为key,成绩为value创建集合并存储数据。
然后分别使用步骤1和2中所创建的Function对象求出学生的平均成绩。
*/
public class Demo6 {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("张三", 85);
map.put("李四", 80);
map.put("王五", 90);
map.put("赵六", 95);
map.put("田七", 70);
getScore(map, hashmap -> {
ArrayList<Integer> array = new ArrayList<>();
array.addAll(0, hashmap.values());
return array;
}, arr -> {
int sum = 0;
for (Integer integer : arr) {
sum += integer;
}
return sum * 1.0 / arr.size();
});
}
private static void getScore(HashMap<String, Integer> map, Function<HashMap<String, Integer>, ArrayList<Integer>> f1, Function<ArrayList<Integer>, Double> f2) {
Double i = f1.andThen(f2).apply(map);
System.out.println(i);
}
}
2.工具Stream流(操作元素的流)
2.1Stream流的常见生成方式
生成Stream流的方式:
①Collection体系集合
使用默认方法stream()生成流, default Stream stream()
②Map体系集合
把Map转成Set集合,间接的生成流
③数组
通过Stream接口的静态方法of(T… values)生成流
2.2Stream流中间操作方法
◆概念
中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作。
◆常见方法
方法名 | 说明 |
---|---|
Stream filter(Predicate predicate) | 用于对流中的数据进行过滤 |
Stream limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
Stream skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
static Stream concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
Stream distinct() | 返回由该流的不同元素(根据Object.equals(Object) )组成的流 |
Stream sorted() | 返回由此流的元素组成的流,根据自然顺序排序 |
Stream sorted(Comparator comparator) | 返回由该流的元素组成的流,根据提供的Comparator进行排序 |
Stream map(Function mapper) | 返回由给定函数应用于此流的元素的结果组成的流 |
IntStream mapToInt(ToIntFunction mapper) | 返回一个IntStream其中包含将给定函数应用于此流的元素的结果 |
2.3Stream流中介操作方法
◆概念
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作。
◆常见方法
方法名 | 说明 |
---|---|
void forEach(Consumer action) | 对此流的每个元素执行操作 |
long count() | 返回此流中的元素数 |
◆注意
Stream<String> stream = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
stream.skip(2).filter(name -> name.startsWith("张"));
System.out.println(stream.count());
注意:Stream流在使用的过程当中,该对象只能被使用一次。上面的stream对象,第一次调用了skip方法,第二次调用了count方法,被用到2次,所以运行出错。