场景
Java8新特性-Stream对集合进行操作的常用API:
Java8新特性-Stream对集合进行操作的常用API_霸道流氓气质的博客-CSDN博客_streamapi对集合修改
前面讲Stream的常用api。下面讲比较器和收集器的常用示例。
Java 8 为 java.util.Comparator 接口新增了多种静态和默认方法,使排序操作变得更为简单。
现在,只需通过一系列库调用,就能根据一个属性对 POJO 集合进行排序。
Java 8 还引入了一个新的工具类java.util.stream.Collectors,它提供将流转换回各类集合所需的静态方法。
此外,收集器也可以在“下游”使用,利用它们对分组(grouping)或分区(partitioning)操作进行后期处理
注:
博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
实现
利用比较器实现排序
根据字典顺序(自然顺序)对字符串集合排序
List<String> sampleStrings = Arrays.asList("a","d","eee","fff","b");
List<String> collect = sampleStrings
.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(collect);//[a, b, d, eee, fff]
根据长度对字符串集合进行排序
List<String> sampleStrings1 = Arrays.asList("a","dd","eee","fffg","bgggg");
List<String> collect1 = sampleStrings1
.stream()
.sorted(Comparator.comparingInt(String::length))
.collect(Collectors.toList());
System.out.println(collect1);//[a, dd, eee, fffg, bgggg]
根据长度和字母顺序对字符串集合进行排序,如果长度相同则按照字母顺序排序
List<String> stringList = Arrays.asList("a","ddd","bb","cc");
List<String> collect2 = stringList
.stream()
.sorted(Comparator.comparingInt(String::length).thenComparing(Comparator.naturalOrder()))
.collect(Collectors.toList());
System.out.println(collect2);//[a, bb, cc, ddd]
将流转换为集合
转换为list
List<String> collect = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi")
.collect(Collectors.toList());
转换为LinkedList
LinkedList<String> collect2 = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi", "lisi")
.collect(Collectors.toCollection(LinkedList::new));
转换为set
Set<String> collect1 = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi","lisi")
.collect(Collectors.toSet());
System.out.println(collect1);//[lisi, zhouqi, zhaoliu, zhangsan, wangwu]
转换为Array
String[] strings = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi")
.toArray(String[]::new);
转换为Map
List<User> userList = new ArrayList<>();
userList.add(new User("霸道",30));
userList.add(new User("的",40));
userList.add(new User("程序猿",50));
userList.add(new User("张三",60));
userList.add(new User("李四",70));
Map<Integer, String> collect3 = userList.stream()
.collect(Collectors.toMap(User::getAge, User::getName));
System.out.println(collect3);//{50=程序猿, 70=李四, 40=的, 60=张三, 30=霸道}
转换为Map,键为对象属性,值为对象本身
方式一
Map<Integer, User> collect4 = userList1.stream()
.collect(Collectors.toMap(User::getId, b -> b));
System.out.println(collect4);
方式二
Map<Integer, User> collect5 = userList1.stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
System.out.println(collect5);
对Map排序与分组
根据键或值对Map排序
Stream<String> names = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi", "a", "a", "aa", "bbb", "ccc");
Map<Integer, List<String>> collect1 = names.collect(Collectors.groupingBy(String::length));
System.out.println(collect1);//{1=[a, a], 2=[aa], 3=[bbb, ccc], 4=[lisi], 6=[wangwu, zhouqi], 7=[zhaoliu], 8=[zhangsan]}
Collectors.groupingBy 方法传入 Function 作为第一个参数,表示分类器(classifier)。
在本例中,分类器是每个字符串的长度。如果 groupingBy 方法只传入一个参数,则结果为 Map,
其中键为分类器的值,值为匹配分类器的元素列表。
双参数形式的groupingBy方法传入另一个Collector,它称为下游收集器,用于对名字列表进行后期处理,这种情况下返回的是Map<Integer, Long>
Map<Integer, Long> collect = names1.collect(Collectors.groupingBy(String::length, Collectors.counting()));
System.out.println(collect);//{1=2, 2=1, 3=2, 4=1, 6=2, 7=1, 8=1}
上面按照名字长度的升序输出,如果希望按照降序,可以使用Map.Entry接口的comparingByKey方法
Stream<String> names2 = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi", "a", "a", "aa", "bbb", "ccc");
Map<Integer, Long> collect2 = names2.collect(Collectors.groupingBy(String::length, Collectors.counting()));
collect2
.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))
.forEach(e -> System.out.println(e.getKey() +" "+ e.getValue()));
comparingByKey 方法返回一个根据键进行排序的比较器。如果希望以键的相反顺序排序,
可以使用comparingByKey方法的重载形式,它传入比较器作为参数。
Stream.sorted 方法生成一个新的排序流,它不对源数据进行修改。换言之,原始 Map 不受影响。
分区
用户希望将元素集合分成若干个类别
假设存在一个字符串集合,可以通过partitioningBy方法将这些字符串按照偶数长度和奇数长度进行划分
List<String> stringList = Arrays.asList("a", "bbb", "cc", "ddddd", "eeee");
Map<Boolean, List<String>> collect = stringList.stream()
.collect(Collectors.partitioningBy(s -> s.length() % 2 == 0));
collect.forEach((key,value) -> System.out.printf("%5s: %s%n",key,value));
Collectors.partitioningBy 方法将元素拆分为满足Predicate 与不满足 Predicate 的两类。
输出结果:
//false: [a, bbb, ddddd]
// true: [cc, eeee]
如果对每个类别包含多少元素更感兴趣,可以使用partitioningBy方法的重载方法(第二个参数为Collector类型)
List<String> stringList1 = Arrays.asList("a", "bbb", "cc", "ddddd", "eeee");
Map<Boolean, Long> collect1 = stringList1.stream()
.collect(Collectors.partitioningBy(s -> s.length() % 2 == 0, Collectors.counting()));
collect1.forEach((k,v)->System.out.printf("%5s: %d%n",k,v));
输出结果:
//false: 3
// true: 2
查找最大值和最小值
用户希望确定流中的最大值或最小值
方法一:使用 BinaryOperator 接口定义的 maxBy 和 minBy 方法
List<User> userList1 = new ArrayList<>();
userList1.add(new User(1,"霸道",30));
userList1.add(new User(2,"的",40));
userList1.add(new User(3,"程序猿",50));
userList1.add(new User(4,"张三",60));
userList1.add(new User(5,"李四",70));
//默认用户-流为空时的默认值
User defaultUser = new User(0,"默认名字",0);
//实现方式1
//BinaryOperator 是 java.util.function 包定义的一种函数式接口,它继承自 BiFunction 接口,适合在函数和返回值的参数属于同一个类时使用。
Optional<User> reduce = userList1.stream()
.reduce(BinaryOperator.maxBy(Comparator.comparingInt(User::getAge)));
System.out.println("年龄最大的为:"+reduce.orElse(defaultUser).getName());
方法二:使用 Stream 接口定义的 max 和 min 方法
Optional<User> max = userList1.stream()
.max(Comparator.comparingInt(User::getAge));
如果直接获取年龄值
OptionalInt max1 = userList1.stream()
.mapToInt(User::getAge)
.max();
方法三:使用 Collectors 类定义的 maxBy 和 minBy 方法。
Optional<User> collect = userList1.stream()
.collect(Collectors.maxBy(Comparator.comparingInt(User::getAge)));
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/135835.html