java8 stream List集合的常用流操作

一、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());

猜你喜欢

转载自blog.csdn.net/weixin_44863237/article/details/129790703