了解和剖析
一、什么是Stream流式计算
首先要知道,当今的大数据,无非就是两步操作,存储数据和计算数据
1、存储数据可以使用Map、Set等集合框架或者是MySQL等数据库
2、计算数据则是交给Stream流来做
Java8的Stream流使用的式函数式编程模式,它可以被用来对集合或数组进行链状流式的操作。可以方便的让我们对集合或数组进行操作
二、使用原理
每一个集合他的父类Collection类中有一个stream方法,会返回一个Stream流对象,泛型为集合的类型,我们一般都是将这个对象转换成Stream对象,进行相关的操作,比如过滤filter
二、Stream流计算使用的方法
样例见代码,当然这个Stream流的计算方法很多,逐步完善
/**题目
* 现在有5个用户,进行筛选
* 1、ID必须是偶数
* 2、年龄必须大于23岁
* 3、用户名转为大写字母
* 4、用户名字母倒着排序
* 5、只输出一个用户
*/
public class Test01 {
public static void main(String[] args) {
User u1 = new User(1, "a", 21);
User u2 = new User(2, "b", 28);
User u3 = new User(3, "c", 25);
User u4 = new User(4, "d", 56);
User u5 = new User(5, "e", 25);
//把这些对象存储进一个集合中
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
//链式编程,计算交给Stream流,把集合转换成一个Stream流对象
list.stream().filter((u)->{return u.getId()%2 == 0;})
.filter((u)->{return u.getAge() > 23;})
.map((u)->{return u.getName().toUpperCase();}) //转大写
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);}) //倒序
.limit(1)
.forEach(System.out::println);
}
}
创建流
流的创建,分成了单列和双列类型,创建流的方式如下
//单列集合创建流
List<Map<String, Object>> birthdayData = null;
Stream<Map<String, Object>> stream = birthdayData.stream();
//单列数组创建流(两种方法)
Integer[] arr = {1,2,3};
Stream<Integer> stream1 = Arrays.stream(arr);
Stream<Integer> stream2 = Stream.of(arr);
//双列Map集合创建流(Map集合不能直接创建Stream流,需要先转换成单列集合)
Map<Object, Object> hashMap = new HashMap<>();
hashMap.put("start_date", nowDateStr);
hashMap.put("end_date", nowDateStr);
hashMap.put("calendar_search", searchText);
Set<Map.Entry<Object, Object>> entrySet = hashMap.entrySet();
Stream<Map.Entry<Object, Object>> mapStream = entrySet.stream();
中间操作
filter
一、作用
可以对流中的元素进行条件过滤,复核过滤条件的才能继续留在流中
二、示例
实现原理:会将List中的每个元素依次作为filter方法中的,断定行接口中的test方法的参数,我们可以自定义test方法的方法体(实现我们自定义的过滤规则),符合条件的将被留在stream流中,如果为false则被剔除这个List
map
一、作用
可以把对流中的元素进行计算或转换
二、原理
这个方法的参数一个function函数型接口,重写里面的apply方法,通过遍历这个集合或者数组,拿到集合中某个对象的某个属性
三、示例
(一)转换
1、内部类方式(简化前)
//初始化数据
CalendarFuzzyVo vo1 = new CalendarFuzzyVo();
CalendarFuzzyVo vo2 = new CalendarFuzzyVo();
CalendarFuzzyVo vo3 = new CalendarFuzzyVo();
List<CalendarFuzzyVo> list = new ArrayList<>();
list.add(vo1);
list.add(vo2);
list.add(vo3);
list.stream()
.map(new Function<CalendarFuzzyVo, String>() {
@Override
public String apply(CalendarFuzzyVo calendarFuzzyVo) {
//拿到对象中的日程ID并返回
return calendarFuzzyVo.getSchedule_id();
}
})
.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
2、Lambda表达式方式(简化后)
//初始化数据
CalendarFuzzyVo vo1 = new CalendarFuzzyVo();
CalendarFuzzyVo vo2 = new CalendarFuzzyVo();
CalendarFuzzyVo vo3 = new CalendarFuzzyVo();
List<CalendarFuzzyVo> list = new ArrayList<>();
list.add(vo1);
list.add(vo2);
list.add(vo3);
list.stream()
.map(calendarFuzzyVo -> calendarFuzzyVo.getSchedule_id())
.forEach(s -> System.out.println(s));
(二)计算
distinct
一、作用
可以去除流中重复的元素
二、实现原理
distinct方法是依赖Object中的equals方法来判断是否是相同的对象,所以需要重写对象中的equals方法!
三、示例
数据初始化
使用流来去重
sorted
一、作用
可以对流中的元素进行排序
二、实现原理
Java的Stream类中有两个sorted重载方法
1、如果想调用无参数的sorted方法,被排序的对象,需要实现Comparable接口,重写cpmpareTo方法
这个方法的方法体中只需要传入需要比较的属性,两个属性相减,如果为前面的大,就是正的;如果前面的小,就是负的;如果为0,则说明两个对象的年龄是相等的(注意:无需记忆该方法是升序还是降序,只需要根据需求调换减号两边参数的位置)
2、如果调用带参的sorted方法,直接在调该方法的时候,使用匿名内部类的方式进行重写compare方法
limit
一、作用
可以设置流的最大长度,超出的部分将被抛弃
二、实现原理
类似与SQL中的limit功能
注意:如果我们设置的流的长度大于了流中元素的个数,不会报错,就是不会出现截取的情况
三、示例
代码:
控制台:打印出1个元素
skip
一、作用
跳过流中的前n个元素,返回剩下的元素
二、示例
flatMap
一、作用
map只能把一个对象转换成另一个对象来作为流中的元素,而flatMap可以把一个对象转换成多个对象作为流中的元素
二、实现原理
调用这个方法,可以将对象中的集合,再转换成Stream流,那么这个新的Stream流中的泛型就成了原来对象中集合的泛型
三、示例
peek
一、作用
在Stream中提供调试的功能,他虽然传入了一个消费型接口,但是并不是真正的去消费数据,供开发人员调试用
二、使用示例
终结操作
forEach
一、作用
对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的元素进行什么具体的操作
二、示例
去之前的中间操作的示例中查看
count
一、作用
可以用来获取当前流中元素的个数
二、示例
min&max
一、作用
可以用来获取流中的最值
二、示例
collect
一、作用
把当前的流转换成一个集合
二、使用方法
1、将Stream<String>类型的作者名称转换成一个List集合
调用Collectors.toList方法
2、获取所有书名的Set集合
调用Collectors.toSet方法
3、获取一个Map集合
这里需要注意,map集合的key是不能重复的,所以在调用collect方法之前需要先进行去重!
4、根据单一字段分组
查找与匹配anyMatch
一、作用
可以用来判断是否有任意符合匹配条件的元素,结果为布尔类型
二、示例
查找与匹配allMatch
一、作用
可以用来判断是否都符合匹配的条件,结果为布尔类型。如果都符合则为true,否则为false
二、示例
查找与匹配noneMatch
一、作用
可以判断流中的元素是否都不符合匹配的条件。如果都不符合结果为true,否则则为false
二、示例
查找与匹配findAny
一、作用
获取流中的任意一个元素,该方法没有办法保证获取的一定是流中的第一个元素
二、示例
这里需要注意的是,可能通过过滤的工作后,压根就不存在符合条件的作家对象,那么这个时候需要调用Optional的ifPresent方法,避免出现空指针的情况
查找与匹配findFirst
一、作用
获取流中的第一个元素
二、示例
reduce
一、作用
对流中的数据(多个)按照你指定的计算方式,计算出一个结果(缩减操作)
二、工作原理
其中identity就是我们可以通过方法参数传入的初始值,accumlator的apply具体进行什么计算就要看方法体中怎么写
该方法会把stream中的元素组合起来,可以传入一个初始值,他会按照我们的计算方式依次拿流中的元素和在初始化值的基础上进行计算,计算结果再和后面的元素计算
三、常见使用方法
(一)两个参数情况
1、求和
需要注意的是,如果我们想求一个对象中Integer类型数据的和,那么首先需要通过map将流的泛型转换成Integer类型,才能调用reduce方法,赋予Integer类型的初始值(identity)
示例:
identity是初始化值
后面的是要执行的操作
2、求最大值
3、求最小值
(二)一个参数情况
区别于上面的两个参数,需要给计算的结果首先赋初始值,这个重载方法则是只传一个参数
底层代码:
是把第一个数据作为初始化值,与后面的数据进行个性化计算
这个方法计算最大值最小值的时候,就不要初始化值了
下面是计算最小值的示例:
至此,关于Stream中常见的操作介绍完毕,内容比较多,建议收藏反复学习,后续还会持续更新,敬请期待~~~