【Stream流】收集stream流中的结果

收集Stream流中的结果

1. 将流中数据收集到集合中

Stream流提供 collect 方法,其参数需要一个 java.util.stream.Collector<T,A, R> 接口对象来指定收集到哪

种集合中。java.util.stream.Collectors 类提供一些方法,可以作为 Collector接口的实例:

public static <T> Collector<T, ?, List<T>> toList() :转换为 List 集合。
public static <T> Collector<T, ?, Set<T>> toSet() :转换为 Set 集合。

基本使用:

@Test
public void testStreamToCollection() {
    Stream<String> stream = Stream.of("aa", "bb", "cc", "bb");
    // 将流中数据收集到集合中
    List<String> list = stream.collect(Collectors.toList());
    System.out.println("list = " + list);

    Set<String> set = stream.collect(Collectors.toSet());
    System.out.println("set = " + set);

    // 收集到指定的集合中
    ArrayList<String> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
    System.out.println("arrayList = " + arrayList);

    HashSet<String> hashSet = stream.collect(Collectors.toCollection(HashSet::new));
    System.out.println("hashSet = " + hashSet);
}

2. 将流中的数据收集到数组中

Stream提供 toArray 方法来将结果放到一个数组中,返回值类型是Object[]的:

Object[] toArray();
<A> A[] toArray(IntFunction<A[]> generator);

// 其中,IntFunction接口有一个抽象方法R
R apply(int value);

基本使用:

@Test
public void testStreamToArray() {
    Stream<String> stream = Stream.of("aa", "bb", "cc");

    // 转成Object数组不方便
    // Object[] objects = stream.toArray();
    // for (Object o : objects) {
    //     System.out.println("o = " + o);
    // }
    // String[]
    String[] strings = stream.toArray(String[]::new);
    for (String string : strings) {
        System.out.println("string = " + string + ", 长度: " + string.length());
    }
}

// 输出结果:
string = aa, 长度: 2
string = bb, 长度: 2
string = cc, 长度: 2

3. 对流中数据进行聚合计算

当我们使用Stream流处理数据后,可以像数据库的聚合函数一样对某个字段进行操作。比如获取最大值,获取最小值,求总和,平均值,统计数量。

java.util.stream.Collectors 类提供一些方法,可以实现上述操作。

3.1 maxBy、minBy

通过Collectors中的maxBy和minBy方法,可以获取流中的数据的最大值和最小值,并将最后的结果返回。

public static <T> Collector<T, ?, Optional<T>>
    maxBy(Comparator<? super T> comparator) {
    return reducing(BinaryOperator.maxBy(comparator));
}

// 其中Comparator接口有一个抽象方法
int compare(T o1, T o2);

基本使用:

@Test
public void testStreamToOther() {
    Stream<Student> studentStream = Stream.of(
        new Student("赵丽颖", 58, 95),
        new Student("杨颖", 56, 88),
        new Student("迪丽热巴", 56, 99),
        new Student("柳岩", 52, 77));

    // 获取最大值
    Optional<Student> max = studentStream.collect(Collectors.maxBy((s1, s2) -> s1.getSocre() - s2.getSocre()));
    System.out.println("最大值: " + max.get());
    Optional<Student> min = studentStream.collect(Collectors.minBy((s1, s2) -> s1.getSocre() - s2.getSocre()));
    System.out.println("最小值: " + min.get());
}

// 输出结果:
最大值:99
最小值:77
3.2 summingInt

通过Collectors中的summingInt方法,可以获取流中的数据的总和,并将最后的结果返回。

public static <T> Collector<T, ?, Integer>
    summingInt(ToIntFunction<? super T> mapper) {
    return new CollectorImpl<>(
        () -> new int[1],
        (a, t) -> { a[0] += mapper.applyAsInt(t); },
        (a, b) -> { a[0] += b[0]; return a; },
        a -> a[0], CH_NOID);
}

// 其中,ToIntFunction接口中有一个抽象方法
int applyAsInt(T value);

基本使用:

@Test
public void testStreamToOther() {
    Stream<Student> studentStream = Stream.of(
        new Student("赵丽颖", 58, 95),
        new Student("杨颖", 56, 88),
        new Student("迪丽热巴", 56, 99),
        new Student("柳岩", 52, 77));
    // 求总和
    Integer sum = studentStream.collect(Collectors.summingInt(s -> s.getAge()));
    System.out.println("总和: " + sum);
}

// 输出结果
总和:222
3.3 averagingInt

通过Collectors中的averagingInt方法,可以获取流中的数据的平均值,并将最后的结果返回。

public static <T> Collector<T, ?, Double>
    averagingInt(ToIntFunction<? super T> mapper) {
    return new CollectorImpl<>(
        () -> new long[2],
        (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
        (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
        a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
}

// 其中,ToIntFunction有一个抽象方法
int applyAsInt(T value);

基本使用:

@Test
public void testStreamToOther() {
    Stream<Student> studentStream = Stream.of(
        new Student("赵丽颖", 58, 95),
        new Student("杨颖", 56, 88),
        new Student("迪丽热巴", 56, 99),
        new Student("柳岩", 52, 77));
    // 平均值
    Double avg = studentStream.collect(Collectors.averagingInt(Student::getSocre));
    System.out.println("平均值: " + avg);
}

// 输出结果:
平均值: 89.75
3.4 counting

通过Collectors中的counting方法,可以获取流中的数据的总数,并将最后的结果返回。

public static <T> Collector<T, ?, Long>
    counting() {
    return reducing(0L, e -> 1L, Long::sum);
}

基本使用:

@Test
public void testStreamToOther() {
    Stream<Student> studentStream = Stream.of(
        new Student("赵丽颖", 58, 95),
        new Student("杨颖", 56, 88),
        new Student("迪丽热巴", 56, 99),
        new Student("柳岩", 52, 77));
    // 统计数量
    Long count = studentStream.collect(Collectors.counting());
    System.out.println("统计数量: " + count);
}

// 输出结果:
统计数量: 4

4. 对流中数据进行分组

当我们使用Stream流处理数据后,可以根据某个属性将数据分组。

基本使用:

@Test
public void testGroup() {
    Stream<Student> studentStream = Stream.of(
        new Student("赵丽颖", 52, 95),
        new Student("杨颖", 56, 88),
        new Student("迪丽热巴", 56, 55),
        new Student("柳岩", 52, 33));

    // Map<Integer, List<Student>> map = studentStream.collect(Collectors.groupingBy(Student::getAge));
    // map.forEach((key, value) -> System.out.println(key + "--->" +value));
    
    // 将分数大于60的分为一组,小于60分成另一组
    Map<String, List<Student>> map = studentStream.collect(Collectors.groupingBy((s) -> {
        if (s.getSocre() > 60) {
            return "及格";
        } else {
            return "不及格";
        }
    }));

    map.forEach((k, v) -> {
        System.out.println(k + "::" + v);
    });
    
// 输出结果:
不及格::[Student{name='迪丽热巴', age=56, socre=55}, Student{name='柳岩', age=52, socre=33}]
及格::[Student{name='赵丽颖', age=52, socre=95}, Student{name='杨颖', age=56, socre=88}]

5. 对流中数据进行多级分组

还可以对数据进行多级分组。基本使用:

@Test
public void testCustomGroup() {
    Stream<Student> studentStream = Stream.of(
        new Student("赵丽颖", 52, 95),
        new Student("杨颖", 56, 88),
        new Student("迪丽热巴", 56, 55),
        new Student("柳岩", 52, 33));

    // 先根据年龄分组,每组中在根据成绩分组
    // groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)
    Map<Integer, Map<String, List<Student>>> map = studentStream.collect(Collectors.groupingBy(Student::getAge, Collectors.groupingBy((s) -> {
        if (s.getSocre() > 60) {
            return "及格";
        } else {
            return "不及格";
        }
    })));

    // 遍历
    map.forEach((k, v) -> {
        System.out.println(k);
        // v还是一个map,再次遍历
        v.forEach((k2, v2) -> {
            System.out.println("\t" + k2 + " == " + v2);
        });
    });
}


// 输出结果:
52
	不及格 == [Student{name='柳岩', age=52, socre=33}]
	及格 == [Student{name='赵丽颖', age=52, socre=95}]
56
	不及格 == [Student{name='迪丽热巴', age=56, socre=55}]
	及格 == [Student{name='杨颖', age=56, socre=88}]

6. 对流中的数据进行分区

Collectors.partitioningBy 会根据值是否为true,把集合分割为两个列表,一个true列表,一个false列表。基本使用:

@Test
public void testPartition() {
    Stream<Student> studentStream = Stream.of(
        new Student("赵丽颖", 52, 95),
        new Student("杨颖", 56, 88),
        new Student("迪丽热巴", 56, 55),
        new Student("柳岩", 52, 33));

    Map<Boolean, List<Student>> map = studentStream.collect(Collectors.partitioningBy(s -> {
        return s.getSocre() > 60;
    }));

    map.forEach((k, v) -> {
        System.out.println(k + " :: " + v);
    });
}

// 输出结果:
false :: [Student{name='迪丽热巴', age=56, socre=55}, Student{name='柳岩', age=52, socre=33}]
true :: [Student{name='赵丽颖', age=52, socre=95}, Student{name='杨颖', age=56, socre=88}]

7. 对流中的数据进行拼接

Collectors.joining 会根据指定的连接符,将所有元素连接成一个字符串。基本使用:

@Test
public void testJoining() {
    Stream<Student> studentStream = Stream.of(
        new Student("赵丽颖", 52, 95),
        new Student("杨颖", 56, 88),
        new Student("迪丽热巴", 56, 99),
        new Student("柳岩", 52, 77));

    // 根据一个字符串拼接: 赵丽颖__杨颖__迪丽热巴__柳岩
    String names = studentStream.map(Student::getName).collect(Collectors.joining("__"));

    // 根据三个字符串拼接
    //        String names = studentStream.map(Student::getName).collect(Collectors.joining("__", "^_^", "V_V"));
    System.out.println("names = " + names);
}

// 输出结果:
names = 赵丽颖__杨颖__迪丽热巴__柳岩
names = ^_^赵丽颖__杨颖__迪丽热巴__柳岩V_V
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值