collect流收集器详解 java8(附代码)

🍰 个人主页:_小白不加班__
🍞文章有不合理的地方请各位大佬指正。
🍉文章不定期持续更新,如果我的文章对你有帮助➡️ 关注🙏🏻 点赞👍 收藏⭐️

一、收集器常用api

在这里插入图片描述
在这里插入图片描述

二、收集器常用静态方法的代码举例

使用上述收集解决一下问题:

使用收集器静态方法收集如下数据:

  1. 所有商品名称的集合
  2. 获取所有商品类型
  3. 在"水果"分类中有几种商品
  4. "水果"分类平均价格
  5. 求所有商品 总库存量
  6. 将所有水果名称 连起来,中间用逗号隔开
  7. 库存最多的商品
  8. 库存最少的商品
  9. 按类别分组,相同类别的商品存放到同一个集合中
    求出每个类别各有多少种商品
    求出每个类别 拥有最大库存数的商品
  10. 按谓词分组,筛选库存量 大于350和 小于于等于350 分为两组

1. toList()

所有商品名称的集合

/**
* 所有商品名称的集合
*/
@Test
public void streamDemo110() {
   List<Product> products = new ArrayList<>();
   // id  name description price stockQuantity category
   products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
   products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
   products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
   products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
   List<String> names = products.stream().map(Product::getName).collect(toList());
   System.out.println(names);// [苹果, 香蕉, 帽子, 上衣]
}

2. toSet()

获取所有产品类型名称

 /**
 * 获取所有产品类型
 */
@Test
public void streamDemo111() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    Set<String> category = products.stream().map(Product::getCategory).collect(toSet());
    System.out.println(category);// [水果, 衣服]
}

3. counting()

求有几种水果

/**
 * 求有几种水果
 */
@Test
public void streamDemo112() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    Long num = products.stream()
            .filter(p -> "水果".equals(p.getCategory()))
            .collect(counting());
    System.out.println("有" + num+"种水果");//有2种水果
}

4. averagingDouble()

水果平均价格

 /**
 * 求"水果"的评价价格
 */
@Test
public void streamDemo114() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    Double avg = products.stream()
            .filter(p -> "水果".equals(p.getCategory()))
            .collect(averagingDouble(Product::getPrice));
    System.out.println("水果平均价格:"+avg);//水果平均价格:75.0
}

5. summingInt()

求所有商品 总库存量

 /**
 * 求所有商品 总库存量
 */
@Test
public void streamDemo113() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    Integer stock2 = products.stream().collect(summingInt(Product::getStockQuantity));
    System.out.println("库存量:" + stock2);// 库存量:1000
}

6. joining()

将所有水果名称 连起来

 /**
 * 将所有水果名称 连起来
 */
@Test
public void streamDemo115() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    String names = products.stream()
            .filter(p -> "水果".equals(p.getCategory()))
            .map(Product::getName).collect(joining(","));
    System.out.println(names);// 苹果,香蕉
}

7. maxBy()

库存最多的商品

 /**
 * 获取商品集合中 最大库存数
 */
@Test
public void streamDemo116() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    Optional<Product> collect = products.stream()
            .collect(maxBy(comparing(Product::getStockQuantity)));
    System.out.println("库存最多的商品:"+collect.get().getName());
    //库存最多的商品:上衣
}

8. minBy()

库存最少的商品

 /**
 * 获取商品集合中 最大库存数
 */
@Test
public void streamDemo116() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    Optional<Product> collect = products.stream()
            .collect(minBy(comparing(Product::getStockQuantity)));
    System.out.println("库存最少的商品:"+collect.get().getName());
    //库存最少的商品:苹果
}

9. groupingBy()

按属性分组
按类别分组,相同类别的商品存放到同一个集合中

/**
 *  按类别分组,相同类别的商品存放到同一个集合中
*/
@Test
public void streamDemo181() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    Map<String,List<Product>> map = products.stream().collect(groupingBy(Product::getCategory));

    map.forEach((k,v)->{
        System.out.println(k+"====="+v);
    });
    /*
    水果=====[Product(id=1, name=苹果, description=好吃的苹果, price=100.0, stockQuantity=100, category=水果),
     Product(id=2, name=香蕉, description=好吃的香蕉, price=50.0, stockQuantity=200, category=水果)]
    衣服=====[Product(id=3, name=帽子, description=帽子, price=80.0, stockQuantity=300, category=衣服),
     Product(id=4, name=上衣, description=上衣, price=60.0, stockQuantity=400, category=衣服)]
    * */
}
groupingBy()拓展使用
  1. groupingBy(Function, Collector)
  2. 第二个参数可以接受上面任意一个收集器静态方法

求出每个类别各有多少种商品
求出每个类别 拥有最大库存数的商品

/**
 * 求出每个类别各有多少种商品
 * 求出每个类别 拥有最大库存数的商品
 */

@Test
public void streamDemo21() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    // 求出每个类别各有多少种商品
    Map<String, Long> map = products.stream().collect(groupingBy(Product::getCategory, counting()));
    map.forEach((k, v) -> {
        System.out.println(k + "有" + v+"种商品");
        // 水果有2种商品
        // 衣服有2种商品
    });
    // 求出每个类别 拥有最大库存数的商品
    Map<String,Optional <Product>> map1 = products.stream().collect(groupingBy(Product::getCategory, maxBy(comparingInt(Product::getStockQuantity))));
    map1.forEach((k,v)->{
        System.out.println("【"+k+"】库存最多的商品:"+v.get().getName()+",库存量:"+v.get().getStockQuantity());
        //【水果】库存最多的商品:香蕉,库存量:200
        //【衣服】库存最多的商品:上衣,库存量:400
});

10. partitioningBy()

分区:按谓词分组,筛选库存量 大于350和 小于于等于350 分为两组

/**
 * 按谓词分组,筛选库存量 大于350和 小于于等于350 分为两组
 */
@Test
public void streamDemo1181() {
    List<Product> products = new ArrayList<>();
    products.add(new Product(1L, "苹果", "好吃的苹果", 100.0, 100, "水果"));
    products.add(new Product(2L, "香蕉", "好吃的香蕉", 50.0, 200, "水果"));
    products.add(new Product(3L, "帽子", "帽子", 80.0, 300, "衣服"));
    products.add(new Product(4L, "上衣", "上衣", 60.0, 400, "衣服"));
    Map<Boolean, List<Product>> map = products.stream().collect(partitioningBy(p -> stockGt350(p)));
    map.forEach((k, v) -> {
        System.out.println(k + "=====" + v);
    });
    /**
     * false=====[Product(id=1, name=苹果, description=好吃的苹果, price=100.0, stockQuantity=100, category=水果),Product(id=2, name=香蕉, description=好吃的香蕉, price=50.0, stockQuantity=200, category=水果), Product(id=3, name=帽子, description=帽子, price=80.0, stockQuantity=300, category=衣服)]
     * true=====[Product(id=4, name=上衣, description=上衣, price=60.0, stockQuantity=400, category=衣服)]
     */
}
public boolean stockGt350(Product product) {
    return product.getStockQuantity() > 350;
}

三、广义归约Collectors.reducing 在收集器中的使用场景和案例

上一篇文章《reduce归约:深入理解java8中的归约reduce》提到了reduce中间操作的使用规则,这次reducing是作为终端操作,在搜集器中使用。

收集器常用api都是Collectors.reducing的特殊情况

1. reducing(BinaryOperator)

流中的前两个元素进行累积计算

/**
 * 工资最高人的姓名
 */
@Test
public void streamDemo1081() {
    List<Worker> workers = new ArrayList<>();
    workers.add(new Worker("张三", 1000, 20, Arrays.asList(1, 2, 45, 23, 22)));
    workers.add(new Worker("李四", 2000, 30, Arrays.asList(10, 20, 450, 230, 220)));
    Optional<Worker> worker = workers.stream()
            .collect(reducing((w1, w2) -> w1.getSalary() > w2.getSalary() ? w1 : w2));
    System.out.println("工资最高:"+worker.get().getName());//工资最高:李四
}
2. reducing(Object, BinaryOperator)
  1. 此方法接受一个初始值(T)和一个二元操作符(BinaryOperator<T>)
  2. 首先使用初始值作为累积器的初始值,然后将流中的元素依次与累积器的当前值进行累积计算。

//计算整数流中所有偶数元素的和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenSums = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.reducing(0, Integer::sum));
System.out.println("Even sums: " + evenSums); // 输出:Even sums: [6]
3. reducing(Object, Function, BinaryOperator)
  1. 此方法接受一个初始值(U)、一个映射函数(Function<U, ? super T, U>)和一个二元操作符(BinaryOperator<U>)
  2. 首先使用初始值作为累积器的初始值,然后将流中的元素依次应用映射函数,并将映射函数的结果与累积器的当前值进行累积计算。
/**
 * 发放工资总和
 */
@Test
public void streamDemo1081() {
    List<Worker> workers = new ArrayList<>();
    workers.add(new Worker("张三", 1000, 20, Arrays.asList(1, 2, 45, 23, 22)));
    workers.add(new Worker("李四", 2000, 30, Arrays.asList(10, 20, 450, 230, 220)));
    Integer countSalary = workers.stream()
            .collect(reducing(0, Worker::getSalary, (x, y) -> x + y));
    System.out.println("总发放:" + countSalary + "元");// 总发放:3000元
    // 等价于 workers.stream().collect(summingInt(Worker::getSalary)); 
}

参考:《java8 实战》

🍉文章不定期持续更新,如果我的文章对你有帮助➡️ 关注🙏🏻 点赞👍 收藏⭐️

评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值