Java8 stream流操作: 去重,排序,筛选,分组,聚合计算

Java8 stream流操作: 去重,排序,筛选,分组,聚合计算

流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算

一.List

  • 测试对象:
/**
 * @Description   :  stream流测试对象
 */
//允许链式set
@Accessors(chain = true)
@Data
public class StreamDto {

    private String name;
    private String addr;
    private Integer age;
    private Date birthDay;
    private BigDecimal money;

    public StreamDto(String name, String addr, Integer age, Date birthDay, BigDecimal money) {
        this.name = name;
        this.addr = addr;
        this.age = age;
        this.birthDay = birthDay;
        this.money = money;
    }

    public StreamDto() {
    }
}
  • 测试集合
    StreamDto d1 = new StreamDto();
    d1.setName("a").setAddr("北京").setAge(20)
            .setBirthDay(DateUtil.parse("2020-10-12")).setMoney(new BigDecimal(3));
    StreamDto d2 = new StreamDto();
    d2.setName("a").setAddr("南京").setAge(12)
            .setBirthDay(DateUtil.parse("2020-10-13")).setMoney(new BigDecimal(1));
    StreamDto d3 = new StreamDto();
    d3.setName("b").setAddr("北京").setAge(23)
            .setBirthDay(DateUtil.parse("2020-10-11")).setMoney(new BigDecimal(2));
    List<StreamDto> list = CollUtil.toList(d1,d2,d3);
    System.out.println("原始List=="+list.toString());

List排序(包含null字段)

  • 不用stream,对自身排序,不返回新List
  //age升序
  list.sort(Comparator.comparing(StreamDto::getAge));
  //age降序
  list.sort(Comparator.comparing(StreamDto::getAge).reversed());
  //正序排序,并将null放在最后(搭配reversed()就变成倒序):小->大->null
  list.sort(Comparator.comparing(StreamDto::getBirthday, 
                               Comparator.nullsLast(Date::compareTo)));
  //先正序排序,并将null放在最前,搭配reversed()翻转就变成倒序:大->小->null
  list.sort(Comparator.comparing(StreamDto::getBirthday, 
                               Comparator.nullsFirst(Date::compareTo)).reversed());
  //先后排序
  list.sort(Comparator.comparing(StreamDto::getAge).reversed()
            .thenComparing(Comparator.comparing(StreamDto::getName).reversed())
            .thenComparing(Comparator.comparing(StreamDto::getAddr).reversed()));
  • 使用stream
    //age升序
    List<StreamDto> l1 = list.stream().sorted(Comparator.comparing(StreamDto::getAge))
        					.collect(Collectors.toList());
    //age降序
    l1 = list.stream().sorted(Comparator.comparing(StreamDto::getAge).reversed())
        					.collect(Collectors.toList());
    //正序排序,并将null放在最后(搭配reversed()就变成倒序):小->大->null
    l2 = list.stream().sorted(Comparator.comparing(StreamDto::getBirthday, 
                               Comparator.nullsLast(Date::compareTo))).collect(Collectors.toList());
    //先正序排序,并将null放在最前,搭配reversed()翻转就变成倒序:大->小->null
    l3 = list.stream().sorted(Comparator.comparing(StreamDto::getBirthday, 
                               Comparator.nullsFirst(Date::compareTo)).reversed()).collect(Collectors.toList());

List聚合计算

//包含了: 计数,最大,最小,求和,平均数, 每种方式都有单独的方式实现
DoubleSummaryStatistics statistics = list.stream()
    .collect(Collectors.summarizingDouble(StreamDto::getAge));
System.out.println("count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",min=:" + statistics.getMin() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage());
//count:3,max:23.0,min=:12.0,sum:55.0,average:18.333333333333332

//计数:
long count = list.stream().count();//3
//如果想直接返回整型
Integer countInt = list.stream().collect(Collectors.summingInt(l -> 1));

//最大/最小,两种方式:
//sorted: 先按年龄降序排列后取第一个,同理最小则升序取第一
Integer max = list.stream().sorted(Comparator.comparing(StreamDto::getAge).reversed()).map(StreamDto::getAge).findFirst().get();
System.out.println("max = " + max);
//min/max
Integer min = list.stream().min(Comparator.comparing(StreamDto::getAge)).get().getAge();
System.out.println("min = " + min);

//求和
Integer sum1 = list.stream().collect(Collectors.summingInt(StreamDto::getAge));
Integer sum2 = list.stream().map(StreamDto::getAge).reduce(Integer::sum).get();

//平均数
Double collect2 = list.stream().collect(Collectors.averagingInt(StreamDto::getAge));
double asDouble = list.stream().mapToLong(StreamDto::getAge).average().getAsDouble();
double asDouble1 = list.stream().mapToInt(StreamDto::getAge).average().getAsDouble();
//...

List条件筛选

    List<StreamDto> l1 = null;
    //条件筛选
    l1 = list.stream().filter(b -> b.getAge() > 15).collect(Collectors.toList());
    //多条件
    l1 = list.stream()
        .filter(b -> DateUtil.compare(new Date(),b.getBirthDay()) > 0
                && b.getAge() < 15 )
        .collect(Collectors.toList());
    l1 = list.stream()
        .filter(b -> b.getMoney().compareTo(new BigDecimal(2)) > -1).collect(Collectors.toList());

List分组

    //name分组
    Map<String,List<StreamDto>> map = list.stream().collect(Collectors.groupingBy(StreamDto::getName));
    //二级分组
    Map<String,Map<Integer,List<StreamDto>>> map1 = list.stream().collect(Collectors.groupingBy(StreamDto::getName,Collectors.groupingBy(StreamDto::getAge)));
    //二级分组,统计数量
    Map<String,Map<Integer,Long>> map2 = list.stream().collect(Collectors.groupingBy(StreamDto::getName,Collectors.groupingBy(StreamDto::getAge,Collectors.counting())));
    //多条件分组
    map = list.stream().collect(Collectors.groupingBy(b -> b.getName() + "-" + b.getAge()));
    //分组后又对集合进行处理,方式1
    Map<String,List<String>> map3 = list.stream().collect(Collectors.groupingBy(StreamDto::getName,Collectors.groupingBy(StreamDto::getAge,Collectors.mapping(StreamDto::getAddr, Collectors.toList()))));
    //方式2,只是拓展,不推荐
    map3 = list.stream().collect(Collectors.groupingBy(StreamDto::getName)).entrySet().stream().collect(Collectors.toMap(b -> b.getKey(), b -> CollUtil.map(b.getValue(), StreamDto::getAddr, true)));

List去重

    //根据Addr去重
    List<StreamDto> list1 = list.stream()
            .collect(Collectors.collectingAndThen(Collectors.toCollection(
                    () -> new TreeSet<>(Comparator.comparing(StreamDto::getAddr))
            ), ArrayList::new));
    //简单去重
    list1 = list.stream().distinct().collect(Collectors.toList());

List转Map

   Map<String, Date> m = list.stream().collect(Collectors.toMap(b -> b.getName(), b -> b.getBirthDay()));
   Map<String, StreamDto> collect3 = list.stream().collect(Collectors.toMap(b -> b.getName(), b -> b));

返回自封装的List实现类

//封装的List实现,用于链式添加:addObj()和addObjs()
ArrayListProxy<String> allPlatNames = new ArrayListProxy<>();
allPlatNames.addObjs(bidSecPlats).addObjs(projPlats);
//去重,这里要返回ArrayListProxy必须自己实现,collect(Collectors.toList())只能返回List,allPlatNames接收不了
allPlatNames = allPlatNames.stream().distinct().collect(ArrayListProxy::new, (r, x) -> {
                r.addObj(x);
            }, List::addAll);

集合合并返回新集合

List<String> list1 = CollUtil.toList("1");
List<String> list2 = CollUtil.toList("2");
List<List<String>> all = CollUtil.toList(list1, list2);

/**
*	第一种方式
*/
ArrayList<String> collect = all.stream().collect(ArrayList::new, (list, value) -> list.addAll(value), List::addAll);
//或者
//串行流:第一个元素时会通过ArrayList::new获得一个初始化容器a,容器a执行ArrayList::addAll方法操作流中的每一个元素,最后返回容器a,最后容器a就只有一个,所以不会用到List::addAll
ArrayList<String> collect = all.stream().collect(ArrayList::new, ArrayList::addAll, List::addAll);
//并行流:将all中的元素分片处理,每片中第一个元素时会通过ArrayList::new获得一个初始化容器a,
//容器a执行ArrayList::addAll方法操作流中的每一个元素,每片最后会返回容器a,最后多个容器a通过List::addAll方法合并后输出
ArrayList<String> collect = all.parallelStream().collect(ArrayList::new, ArrayList::addAll, List::addAll);

/**
*	第二种方式
* 	reduce
*/
//new ArrayList<>() 作为初始值加入计算
List<String> reduce = all.stream().reduce(CollUtil.toList("3"), (b, c) -> {
            b.addAll(c);
            return b;
        });//返回["3","1","2"]
//不添加初始值计算
Optional<List<String>> reduce = all.stream().reduce((b, c) -> {
            b.addAll(c);
            return b;
        });//返回["1","2"]

二.Map

Map转换

//假设有数据
Map<String, List<StreamDto>> map = new HashMap<>();
//取出key和集合中第一个对象的时间参数
Map<String, Date> m = map.entrySet().stream()
   .collect(Collectors.toMap(b -> b.getKey(), b -> b.getValue().get(0).getBirthDay()));

Map排序

//前5名
Map<String, Long> top5Names = new LinkedHashMap<>();
//假设有数据
List<String> mainQ = new ArrayList<>();
//分组后统计数量
Map<String, Long> countMap = mainQ.stream()
    .collect(Collectors.groupingBy(b -> b, Collectors.counting()));
//value排序,然后取出前5名
countMap.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed()).forEachOrdered(b -> {
    if (top5Names.size() < 6) {
        top5Names.put(b.getKey(), b.getValue());
    }
});
//取出全部
Map<String, Long> allMap = countMap.entrySet().stream()
    .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
    .collect(Collectors.toMap(
        Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> newValue, 		      					LinkedHashMap::new
    ));
//key排序
countMap.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByKey().reversed());

如果是Map<String,List>这种类型的数据目前不知道如何对value进行排序, 知道的朋友可以留言指点一下!

Map过滤

//假设有数据
List<String> mainQ = new ArrayList<>();
Map<String, Long> countMap = mainQ.stream()
        .collect(Collectors.groupingBy(b -> b, Collectors.counting()));
//map过滤
countMap.entrySet().stream().filter(b -> b.getKey() != "").collect(HashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), HashMap::putAll);

Map合并

/**
 * @Description: 合并两个map,如果key相同,那么选取时间靠后的value 
 */
public static Map<String, Date> concatMap(Map<String, Date> map1, Map<String, Date> map2) {
    Map<String, Date> result = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream())
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (value1, value2) -> {
                if (DateUtil.compare(value1, value2) >= 0) {
                    return value1;
                } else {
                    return value2;
                }
            }));
    return result;
}

Map遍历

/**
 * 遍历Map的方式
 */
Map<String,List<ResOrgUserDto>> map =new HashMap<>();
//1.通过Map.keySet遍历key和value
for (String key : map.keySet()) {
    System.out.println(map.get(key));
}
//Java8
map.keySet().forEach(k -> {
    System.out.println(map.get(k));
});

//2.通过Map.entrySet使用Iterator遍历key和value
while (map.entrySet().iterator().hasNext()){
    Map.Entry<String,List<ResOrgUserDto>> entry = map.entrySet().iterator().next();
    System.out.println(entry.getValue());
}
//Java8
map.entrySet().iterator().forEachRemaining(m -> System.out.println(m.getValue()));

//3.通过Map.entrySet遍历key和value,在大容量时推荐使用
for (Map.Entry<String, List<ResOrgUserDto>> entry : map.entrySet()) {
    System.out.println(entry.getValue());
}
//Java8
map.entrySet().forEach(entry -> {
    System.out.println(entry.getValue());
});

//4.通过Map.values()遍历所有的value,但不能遍历key
for (List<ResOrgUserDto> values : map.values()) {
    System.out.println(values);
}
//Java8
map.values().forEach(v -> {
    System.out.println(v);
});

//5.通过k,v遍历,Java8独有的
map.forEach((k,v) -> {
    System.out.println(v);
});

List,Map综合

//前5名名称
List<String> names = top5Names.entrySet().stream().map(b -> b.getKey()).collect(Collectors.toList());
//获取各表前五名平台的最后数据接收时间
Map<String, Date> bidSecLasts = bidSecQ.stream().filter(b -> names.contains(b.getTradeplat()))//筛选出前5的数据
        .sorted(Comparator.comparing(BusBidsection::getSubmittimestamp).reversed())//先排序
        .collect(Collectors.groupingBy(BusBidsection::getTradeplat))//在分组
        //最后取出key和最后数据接收时间
        .entrySet().stream().collect(Collectors.toMap(b -> b.getKey(), b -> b.getValue().get(0).getSubmittimestamp()));
  • 10
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值