Java JDK8—Stream流式计算
简介:流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列,Stream操作是延迟执行的,它不会改变源对象,返回的是新Stream。
1. 创建Stream
A. 创建流:
顺序流:default Stream<E> stream();
并行流:default Stream<E> parallelStream();
B. 由数组创建流:static <T> Stream<T> stream(T[] array);
C. 由值创建流:public static<T> Stream<T> of(T… values);
2. Stream对象的使用
Intermediate(中间操作):将原始的Stream转换为另外一个Stream;
方法 | 说明 | 举例 |
filter | 元素过滤,对Stream对象按照指定的Predicate进行过滤,返回的Strema对象中仅包含满足条件的元素 | |
map [mapToInt] [mapToLong] [mapToDouble] |
元素一对一转换,使用传入的Function对象对Stream中所有元素进行映射处理,返回的Stream对象中的元素为原元素处理后的结果 | |
flatMap (flatMapToInt) (flatMapToLong) (flatMapToDouble) |
元素一对多转换,对Stream对象中的所有元素进行操作,每个元素会有一个或多个结果,然后将所有的元素组合成一个统一的Stream并返回 | |
distinct | 元素去重,返回去重后的Stream对象 | |
sorted [sorted(Comparator<? super T> comparator)] |
元素排序,返回排序后的Stream对象 | |
limit | 元素截取,返回有限个元素组成新的Stream对象 | |
skip | 元素跳过,抛弃前指定个元素后,使用剩下的元素组成新的Stream对象返回 | |
peek |
生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数即引用的方法,当Stream每个元素被消费的时候都会先执行新Stream给定的方法
|
注意:
A. skip和limit组合可以替代list中subList方法或者实现分页;
B. Comparator比较器
reverseOrder/reversed:顺序反转;nullsFirst/nullsLast:将null值放在第一个/最后一个;comparing/comparingInt/comparingLong/comparingDouble:指定参数类型比较升序;
thenComparing/thenComparingInt/thenComparingLong/thenComparingDouble:多次比较,就是多条件排序
举例:先将businessName字段有值的排在最前面,然后将level字段值大的排在最前面
Terminal(终端操作):产生的是一个结果或者其他的复合操作;
方法 | 说明 |
forEach (forEachOrdered) |
对所有的元素进行迭代处理,无返回值 |
toArray | 返回所有元素的数组 |
min | 返回所有元素中最小的Optional对象 |
max | 返回所有元素中最大的Optional对象 |
anyMatch | 只要其中一个元素满足传入的Predicate对象时就返回true,否则返回false |
allMatch | 所有的元素均满足传入的Predicate对象时就返回true,否则返回false |
noneMatch | 所有的元素均不满足传入的Predicate对象时就返回true,否则返回false |
findFirst | 返回第一个元素的Optional对象 |
findAny | 返回任意一个元素的Optional对象 |
count | 所有元素个数 |
collect | 根据传入的参数作相关汇聚计算 |
reduce | 使用一个初始化的值,与Stream中的元素一一做传入的二合运算后返回最终的值。每与一个元素做运算后的结果,再与下一个元素做运算 |
3. Collectors收集器
A. 将流中的数据转成集合类型:toList、toSet、toMap、toCollection;
方法 | 返回类型 | 作用 |
toList | List<T> | 把流中元素收集到List中 |
toSet | Set<T> | 把流中元素收集到Set中 |
toMap | ||
toCollection | Collection<T> | 把流中元素收集到创建的集合 |
B. 将流中的数据(字符串)使用分隔符拼接在一起:joining;
方法 | 返回类型 | 作用 |
joining | String | 连接流中每个字符串 |
C. 对流中的数据求最大值maxBy、最小值minBy、求和summingInt、求平均值averagingInt;
方法 | 返回类型 | 作用 |
maxBy | Option<T> | 根据比较器选择最大值 |
minBy | Option<T> | 根据比较器选择最小值 |
summingInt (summingLong) (summingDouble) |
Integer (Long) (Double) |
对流中的元素的整数属性求和 |
averagingInt (averagingLong) (averagingDouble) |
Integer (Long) |
计算流中元素整数属性的平均值 |
summariningInt | IntSummaryStatistics | 计算流中元素整数属性的统计值 |
counting | Long | 计算流中元素的个数 |
D. 对流中的数据进行映射处理:mapping;
举例一:见groupingBy中举例一。
E. 对流中的数据分组:groupingBy、partitioningBy;
方法 | 返回类型 | 作用 |
groupingBy | Map<K, List<T>> | 根据某属性值对流进行分组,属性为K,结果为V |
partitioningBy | Map<Boolean, List<T>> | 根据true或false进行分区 |
举例一:对Map集合数据按照键值value进行分组,将键key变为集合List
public static void main(String[] args) { // 将人分成三队(姓名 - 队号) Map<String, Integer> map = new HashMap<>(4); map.put("zhangsan", 2); map.put("lisi", 3); map.put("wangwu", 1); map.put("xiaohei", 2); Map<Integer, List<String>> collect = map.entrySet().stream().collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList()))); System.out.println(collect.toString()); }
举例二:对List集合对象的名称进行分组,取对象值的最大的值为键值
public static void main(String[] args) { List<NameValuePair> list = new ArrayList<>(); list.add(new NameValuePair("A区", 2)); list.add(new NameValuePair("B区", 3)); list.add(new NameValuePair("A区", 1)); list.add(new NameValuePair("A区", 3)); list.add(new NameValuePair("B区", 2)); list.add(new NameValuePair("C区", 3)); Map<String, Integer> collect = list.stream().collect(Collectors.groupingBy(NameValuePair::getName, Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(nameValuePair -> (Integer) nameValuePair.getValue())), option -> (Integer) option.get().getValue()))); System.out.println(collect.toString()); }
F. 对流中的数据累计计算:reducing;
G. 对流中结果数据进行转换函数:collectingAndThen。
举例一:见groupingBy中举例二。
4. 实际应用中的实例模型
A. 合并Map,若键相同时键值求和,若键不同时就合并
public static void main(String[] args) { Map<String, Integer> map1 = new HashMap<>(4); map1.put("A", 2); map1.put("B", 3); map1.put("C", 4); Map<String, Integer> map2 = new HashMap<>(4); map2.put("A", 5); map2.put("B", 3); map2.put("C", 7); Map<String, Integer> map3 = new HashMap<>(4); map3.put("D", 5); map3.put("B", 6); map3.put("C", 9); Map<String, Integer> map4 = new HashMap<>(4); map4.put("D", 5); map4.put("B", 1); map4.put("E", 9); Map<String, Map<String, Integer>> map5 = new HashMap<>(3); map5.put("AA", map1); map5.put("BB", map2); Map<String, Map<String, Integer>> map6 = new HashMap<>(3); map6.put("AA", map3); map6.put("CC", map4); // Map中键相同时,键值求和;没有时,合并 Map<String, Map<String, Integer>> map7 = Stream.of(map5, map6).flatMap(map -> map.entrySet().stream()).collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> Stream.of(v1, v2).flatMap(map -> map.entrySet().stream()).collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v3, v4) -> v3 + v4 )) )); System.out.println(map7.toString()); }
B. 基于A条件,Map取键值最大的前三个并按逗号拼接成字符串
Map<String, String> map8 = map7.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> entry.getValue().entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue().reversed()) .limit(3).map(Map.Entry::getKey).collect(Collectors.joining(",")) )); System.out.println(map8.toString());
C. 对List集合进行条件分类,然后符合相应条件的进行求和
public static void main(String[] args) { User user1 = new User(); user1.setId(1L); user1.setRoleId(2L); User user2 = new User(); user2.setId(3L); user2.setRoleId(4L); User user3 = new User(); user3.setId(5L); user3.setRoleId(8L); User user4 = new User(); user4.setId(4L); user4.setRoleId(6L); List<User> list = new ArrayList<>(); list.add(user1); list.add(user2); list.add(user3); list.add(user4); Map<Integer, Long> map = list.stream().collect(Collectors.groupingBy(user -> { if (user.getId() < 2L) { return 1; } else if (user.getId() < 6L) { return 2; } else { return 3; } }, Collectors.summingLong(User::getRoleId))); System.out.println(map.toString()); }
D. 取Map集合中键最大的键
public static void main(String[] args) { Map<Integer, Long> map1 = new HashMap<>(3); map1.put(1, 2L); map1.put(2, 5L); Map<Integer, Long> map2 = new HashMap<>(3); map2.put(3, 4L); map2.put(2, 5L); Map<String, Map<Integer, Long>> map3 = new HashMap<>(3); map3.put("A", map1); map3.put("B", map2); Map<String, Integer> map = map3.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> entry.getValue().entrySet().stream().max(Map.Entry.comparingByKey()).get().getKey() )); System.out.println(map.toString()); }
E. 多个Map, 键值合并为对象
public static void main(String[] args) { Map<String, String> map1 = new HashMap<>(4); map1.put("A", "WE"); map1.put("B", "RT"); map1.put("C", "lo"); Map<String, Long> map2 = new HashMap<>(4); map2.put("D", 12L); map2.put("B", 34L); map2.put("C", 67L); Map<String, Long> map3 = new HashMap<>(4); map3.put("B", 11L); map3.put("E", 50L); map3.put("C", 87L); Map<String, UserDemo> map4 = Stream.of(map1, map2, map3).flatMap(map -> map.entrySet().stream()).collect(Collectors.toMap(Map.Entry::getKey, v -> new UserDemo(map1.getOrDefault(v.getKey(), null), map2.getOrDefault(v.getKey(), null), map3.getOrDefault(v.getKey(), null)), (v1, v2) -> new UserDemo(v1.getUsername(), v1.getRoleId(), v1.getPermissionId()) )); System.out.println(map4.toString()); }
F. 对Map集合及Map集合中键值Map进行过滤
public static void main(String[] args) { Map<String, Integer> map1 = new HashMap<>(3); map1.put("1", 4); map1.put("2", 3); Map<String, Integer> map2 = new HashMap<>(3); map2.put("2", 6); map2.put("3", 4); Map<String, Integer> map3 = new HashMap<>(4); map3.put("1", 7); map3.put("2", 9); map3.put("3", 4); Map<String, Map<String, Integer>> map = new HashMap<>(4); map.put("A", map1); map.put("B", map2); map.put("C", map3); Map<String, Map<String, Integer>> collect = map.entrySet().stream() .filter(entry -> entry.getValue().containsKey("1")) .collect(Collectors.toMap( Map.Entry::getKey, entry -> entry.getValue().entrySet().stream() .filter(entry1 -> "1".equals(entry1.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))); System.out.println(collect.toString()); }
F. List数据分批处理切割
public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); // 最大数量 int maxSize = 3; // 切分次数 int limit = (list.size() + maxSize - 1) / maxSize; List<List<Integer>> lists = Stream.iterate(0, n -> n + 1) .limit(limit) .map(a -> list.stream() .skip(a * maxSize) .limit(maxSize) .collect(Collectors.toList())) .collect(Collectors.toList()); lists.forEach(list1 -> { System.out.println("个数:" + list1.size()); list1.forEach(System.out::println); System.out.println("遍历完毕"); }); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗