一、stream基础方法使用
1.filter 过滤
filter方法用于通过设置条件过滤出满足条件的元素。以下代码片段使用filter方法过滤出空字符串。
List<String> list = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = list.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
2.sorted 排序
sorted方法用于对流进行排序。以下代码片段使用sorted方法对集合中的数字进行排序
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().sorted().forEach(System.out::println);
注意:
Stream<T> sorted(); //自然排序
空参的sorted函数默认调用集合元素的Comparable接口进行对比,如果是自定义类需要实现Comparable接口,重写compareTo(Object obj)
Stream<T> sorted(Comparator<? super T> comparator); //定制排序
带参的sorted函数需要传入Comparator的对象,重写compare(Object o1,object o2)方法
3.map 映射
map方法用于映射每个元素到对应的结果。以下代码片段使用map获取人的姓名
List<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
4.distinct 去重
distinct 方法用于去掉重复数据。以下代码片段使用filter方法过滤出空字符串并去重
List<String> list = Arrays.asList("abc", "", "bc", "efg", "abc","", "jkl");
List<String> filtered = list.stream().filter(string -> !string.isEmpty()).distinct().collect(Collectors.toList());
5.Match匹配
Stream 提供了多种匹配操作,允许检测指定的 Predicate 是否匹配整个 Stream。所有的匹配操作都是 最终操作 ,并返回一个 boolean 类型的值。
// 测试 Match (匹配)操作
List<String> stringList = Arrays.asList("abc", "", "bc", "efg", "abc","", "jkl");
// 部分匹配返回true
boolean anyStartsWithA =
stringList
.stream()
.anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
// 全部匹配返回true
boolean allStartsWithA =
stringList
.stream()
.allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false
// 全部不匹配返回true
boolean noneStartsWithZ =
stringList
.stream()
.noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true
6.Reduce 规约
这是一个 最终操作 ,允许通过指定的函数来将 stream 中的多个元素规约为一个元素,规约后的结果是通过 Optional 接口表示的:
//测试 Reduce (规约)操作
List<String> stringList = Arrays.asList("abc", "bc", "efg", "abc", "jkl");
Optional<String> reduced =
stringList
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);//abc#bc#efg#abc#jkl
// 字符串连接,concat = "ABCD"
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
// 求最小值,minValue = -3.0
double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
// 求和,sumValue = 10, 有起始值
int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
// 求和,sumValue = 10, 无起始值,返回Optional,通过get获取值
sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
// 过滤,字符串连接,concat = "ace"
concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。例如 Stream 的 sum 就相当于Integer sum = integers.reduce(0, (a, b) -> a+b);也有没有起始值的情况,这时会把 Stream 的前面两个元素组合起来,返回的是 Optional。
第一个参数(空白字符)即为起始值,第二个参数(String::concat)为 BinaryOperator。这类有起始值的 reduce() 都返回具体的对象。而对于第五个示例没有起始值的 reduce(),由于可能没有足够的元素,返回的是 Optional,请留意这个区别。更多内容查看:IBM:Java 8 中的 Streams API 详解
7.count 计数
count 方法用于统计集合内对象的数量,以下代码片段使用filter方法过滤出空字符串并计数
List<String> list = Arrays.asList("abc", "", "bc", "efg", "abc","", "jkl");
long count = list.stream().filter(string -> !string.isEmpty()).count();
8.Collectors
Collectors类实现了很多归约操作,例如将流转换成集合和聚合元素。
Collectors可用于返回列表或字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("原列表筛选后列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
二、List根据对象属性分组
底层代码:
1. public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier) {
return groupingBy(classifier, toList());
}
2. public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {
return groupingBy(classifier, HashMap::new, downstream);
}
3. public static <T, K, D, A, M extends Map<K, D>>
Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream) {
Supplier<A> downstreamSupplier = downstream.supplier();
BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
downstreamAccumulator.accept(container, t);
};
BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
@SuppressWarnings("unchecked")
Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;
if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
}
else {
@SuppressWarnings("unchecked")
Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
Function<Map<K, A>, M> finisher = intermediate -> {
intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
@SuppressWarnings("unchecked")
M castResult = (M) intermediate;
return castResult;
};
return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
}
}
1.根据属性字段分组
Map<String, List<Person>> collect = list.stream().collect(Collectors.groupingBy(Person::getName));
2.解决Map不按list顺序问题
Map<String, List<Person>> collect = list.stream()
.collect(Collectors.groupingBy(Person::getName, LinkedHashMap::new,Collectors.toList()));
3.按照字段升序排序
分组的字段按照TreeMap的规则进行排序放入Map,底层是TreeMap
Map<String, List<Person>> collect = list.stream()
.collect(Collectors.groupingBy(Person::getAge, TreeMap::new, Collectors.toList())); //TreeMap默认以升序排序
4.多重分组
Map<String, Map<String, List<PlanOrg>>> planOrgMap = new HashMap<>();
planOrgList.stream().collect(Collectors.groupingBy(PlanOrg::getType)).
forEach((type, list2) -> {
Map<String, List<PlanOrg>> planOrgMap_tmp = list2.stream().collect(
Collectors.groupingBy(PlanOrg::getPlanOrgId)
);
planOrgMap.put(type, planOrgMap_tmp);
});
三、List 集合统计操作:求和、求最大值、求最小值、求平均值
1.统计数量
long count = Persons.stream().filter(a -> a.getAge() > 5).count();
System.out.println("age > 5的人数 = " + count);
2.求和
int sumAge = persons.stream().mapToInt(Person::getAge).sum();
3.求最大值
int maxAge = persons.stream().mapToInt(Person::getAge).max().getAsInt();
4.求最小值
int minAge = persons.stream().mapToInt(Person::getAge).min().getAsInt();
5.求平均值
double avgAge = persons.stream().mapToInt(Person::getAge).average().getAsDouble();
6.summaryStatistics统计
流用一次就不能用第二次,可以一次性获取一个流的所有统计信息。
IntSummaryStatistics statistics = persons.stream().mapToInt(Person::getAge).summaryStatistics();
System.out.println("count = " + statistics.getCount());
System.out.println("sumAge = " + statistics.getSum());
System.out.println("maxAge = " + statistics.getMax());
System.out.println("minAge = " + statistics.getMin());
System.out.println("avgAge = " + statistics.getAverage());