【Java】 Stream流求和、排序、分组
List、Set集合通过Stream流求和
一、泛型为Integer、Long、Double、BigDecimal求和
Integer sum = scores.stream().reduce(Integer::sum).orElse(0); Long sum = scores.stream().reduce(Long::sum).orElse(0L); Double sum = scores.stream().reduce(Double::sum).orElse(0.00); BigDecimal sum = scores.stream().reduce(BigDecimal::add).orElse(new BigDecimal(0.00));
二、泛型为实体类
对单个属性求和
Integer sum = sales.stream().mapToInt(Sale::getOrderNum).sum(); Long sum = sales.stream().mapToLong(Sale::getOrderNum).sum(); Double sum = sales.stream().mapToDouble(Sale::getOrderNum).sum(); BigDecimal sum = sales.stream().map(Sale::getAppleSale).reduce(BigDecimal.ZERO, BigDecimal::add);
对多个属性分别分组求和 并返回聚合后的对象
// 类型为BigDecimal Sale result = sales.stream().reduce((x, y) -> newSale(x.getAppleSale().add(y.getAppleSale()),x.getBananaSale().add(y.getBananaSale()),x.getGrapeSale().add(y.getGrapeSale())))
.orElse(new Sale(BigDecimal.ZERO, BigDecimal.ZERO,BigDecimal.ZERO)); // 类型为Integer、Long、Double(注:orElse中需输入对应类型初始值) Sale sale = sales.stream().reduce((x, y) -> new Sale(x.getAppleSale() + y.getAppleSale(), x.getBananaSale() + y.getBananaSale(), x.getGrapeSale() + y.getGrapeSale())) .orElse(new Sale(0.00, 0.00,0.00));
多字段乘积求和(基本数据类型)
int prices = list.stream().mapToInt(x-> x.getprice * x.getTotal).sum();
多字段乘积求和(BigDecimal)
BigDecimal prices = list.stream().map(x-> x.getPrice().multiply(new BigDecimal(x.getTotal()))).reduce(BigDecimal.ZERO, BigDecimal::add);
对对象中的多个字段求和时 如果对象中属性非常非常多 还像上边一样写不现实
解决办法“转为map 遍历赋值 下边json处理使用的事hutool 的json处理
//构造返回结果 SafeJwggaqhhsetj one = new SafeJwggaqhhsetj(); //把结果转为map方便赋值 Map<String, Object> resMap = JSONUtil.toBean(JSONUtil.toJsonStr(one), Map.class); //要求和的对象的list集合 List<SafeJwggaqhhsetj> list = this.list(queryWrapper); //将对象list转为json数组 JSONArray array = JSONUtil.parseArray(JSONUtil.toJsonStr(list)); //将对象list转为map数组 List<Map> dataMap = JSONUtil.toList(array, Map.class); //遍历变量名集合 keylist可能是 Arrays.asList(new String[] {"personAmountChinese", "personManhoursChinese", }) for (String s : keylist) { //求和 resMap.put(s, dataMap.stream().mapToInt(o -> { AtomicReference<Integer> d = new AtomicReference<>(); Optional.ofNullable(o.get(s)) .map(p -> { d.set((Integer) p); return p; }) .orElseGet(() -> { d.set(0); return 0; }); return d.get(); }).sum()); } one = JSONUtil.toBean(JSONUtil.toJsonStr(resMap), SafeJwggaqhhsetj.class);
对对象集合中的属性求和
单个bigdecimal属性的话直接 用map get 出来求和即可
例如 :
BigDecimal result2 = userList.stream() // 将user对象的mongey取出来map为Bigdecimal .map(User::getMoney) // 使用reduce聚合函数,实现累加器 .reduce(BigDecimal.ZERO,BigDecimal::add);
此处为 将每个对象中多个属性求乘积以后再求和
p.getSkuCount() * p.getVolumeLength().multiply(p.getVolumeHeight()).multiply(p.getVolumeWidth()).intValue()
并且此处需要返回的count 是integer类型 如果是bigdecimal 参考 对单个属性求和 中的bigdecimal 即
可
public static void main(String[] args) { List<ExtSkuLocationParam> locationAllSku = new ArrayList<>(); for (int i = 1; i < 3; i++) { ExtSkuLocationParam a = new ExtSkuLocationParam(); a.setSkuCount(i); a.setVolumeLength(new BigDecimal(i * 10)); a.setVolumeWidth(new BigDecimal(i * 10)); a.setVolumeHeight(new BigDecimal(i * 10)); locationAllSku.add(a); } Integer reduce = locationAllSku.stream().reduce(0, (sum, p) -> sum += p.getSkuCount() * p.getVolumeLength().multiply(p.getVolumeHeight()).multiply(p.getVolumeWidth()).intValue(), Integer::sum); System.out.println(reduce); }
只查找集合中符合条件的第一个元素并且返回
Map matchMap = nodeMapList.stream().filter(o -> o.get("id").equals(node.get("id"))).findFirst().get();
排序
直接排序数值
List<Integer> step = stepOrign.sorted().collect(Collectors.toList())
获取对象数组某个属性最小值那条记
bookList.stream().min(Comparator.comparing(Book::getSort)).get();
根据对象数组某个属性排序
ProjectApprovalGroup.get(id).stream().sorted(Comparator.comparing(ProjectApproval::getProcessStep)).collect(Collectors.toList());
排序List 的集合 集合内容是String 类型的数字
childrenArgList={"1","2","3"} childrenArgList = childrenArgList.stream().sorted(Comparator.comparing(o-> Integer.parseInt((String) o)).reversed()).collect(Collectors.toList()); //此为按倒序排序 结果为{"3","2","1"}
多字段排序
public class User { //学生id private Integer userId; //学生姓名 private String userName; //学生年龄 private Integer age; //学生班级 private Integer classNo; } List<User> userList = new ArrayList<>(); userList.add(new User(1, "shy01", 20, 1)); userList.add(new User(2, "shy02", 18, 3)); userList.add(new User(3, "shy03", 20, 4)); userList.add(new User(4, "shy04", 19, 2)); userList.add(new User(5, "shy05", 17, 5)); userList.add(new User(6, "shy06", 16, 4)); userList.add(new User(7, "shy07", 18, 9)); userList.add(new User(8, "shy08", 19, 8)); userList.add(new User(9, "shy09", 21, 7));
单个字段排序
根据年龄升序排序
userList = userList.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
userList.forEach(System.out::println);
根据年龄降序排序
//方法1:先对年龄进行升序,结果进行反转 userList = userList.stream().sorted(Comparator.comparing(User::getAge).reversed()).collect(Collectors.toList()); //方法2:直接对年龄进行降序 userList = userList.stream().sorted(Comparator.comparing(User::getAge, Comparator.reverseOrder())).collect(Collectors.toList()); userList.forEach(System.out::println);
多个字段排序
年龄升序,班级升序
userList = userList.stream().sorted(Comparator.comparing(User::getAge).thenComparing(User::getClassNo)).collect(Collectors.toList());
年龄降序,班级升序
//方法1:先对年龄进行升序,升序结果进行反转,再进行班级升序 userList = userList.stream().sorted(Comparator.comparing(User::getAge).reversed().thenComparing(User::getClassNo)).collect(Collectors.toList()); //方法2:直接对年龄进行降序,再对班级进行升序 userList = userList.stream().sorted(Comparator.comparing(User::getAge,Comparator.reverseOrder()).thenComparing(User::getClassNo)).collect(Collectors.toList());
年龄降序,班级降序
//方法1:先对年龄进行升序,升序结果进行反转,再对班级进行降序 userList = userList.stream().sorted(Comparator.comparing(User::getAge).reversed().thenComparing(User::getClassNo, Comparator.reverseOrder())).collect(Collectors.toList()); //方法2:直接对年龄进行降序,再对班级进行降序 userList = userList.stream().sorted(Comparator.comparing(User::getAge,Comparator.reverseOrder()).thenComparing(User::getClassNo,Comparator.reverseOrder())).collect(Collectors.toList()); //方式3:先对年龄进行升序,再对班级进行升序,最后对结果进行反转 userList = userList.stream().sorted(Comparator.comparing(User::getAge).thenComparing(User::getClassNo).reversed()).collect(Collectors.toList());
年龄升序,班级降序
//方法1:先对年龄进行升序,升序结果进行反转,再进行班级升序,结果进行反转(有点绕,年龄被排了三次升-降-升) userList = userList.stream().sorted(Comparator.comparing(User::getAge).reversed().thenComparing(User::getClassNo).reversed()).collect(Collectors.toList()); //方法2:直接对年龄进行升序,再对班级进行降序 userList = userList.stream().sorted(Comparator.comparing(User::getAge).thenComparing(User::getClassNo, Comparator.reverseOrder())).collect(Collectors.toList());
分组
多字段分组
自定义分组规则 u.getCity() + "|" + u.getSex()
public class Demo2 { public static void main(String[] args) { DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss"); // data list List<User> userList = Arrays.asList( User.builder().id(123456).name("Zhang,San").city("ShangHai").sex("man").birthDay(LocalDateTime.parse("2022-07-0112:00:00", df)).build(), User.builder().id(777777).name("Zhang,San").city("ShangHai").sex("woman").birthDay(LocalDateTime.parse("2022-07-0112:00:00", df)).build(), User.builder().id(888888).name("Li,Si").city("ShangHai").sex("man").birthDay(LocalDateTime.parse("2022-07-0112:00:00", df)).build(), User.builder().id(999999).name("Zhan,San").city("HangZhou").sex("woman").birthDay(LocalDateTime.parse("2022-07-0112:00:00", df)).build(), User.builder().id(555555).name("Li,Si").city("NaJin").sex("man").birthDay(LocalDateTime.parse("2022-07-0112:00:00", df)).build() ); Map<String, List<User>> groupMap = userList.stream().collect(Collectors.groupingBy(u -> u.getCity() + "|" +u.getSex())); groupMap.forEach((k, v) -> { System.out.println(k); System.out.println(v); }); } }
格式化时间 分组
list.stream().collect(Collectors.groupingBy(item -> new SimpleDateFormat("yyyy-MM-dd HH").format(item.getCreateTime())));
stream对list进行分组,并对分组后的数据进行map操作 获取其中的某一项属性值
Map<String, List> map = list.stream().collect(Collectors.groupingBy(CourseTeacherDTO::getCourseId, Collectors.mapping(CourseTeacherDTO::getName, Collectors.toList())));
Java List集合Stream流按条件分组获取每组最大值
先根据时间分组,然后根据时间排序取最大
Map<String, ProjectReport> collect = a.stream().collect(Collectors.groupingBy( item->
new SimpleDateFormat("yyyy-MM").format(item.getCreateTime()),
Collectors.collectingAndThen(Collectors.reducing((c1,c2) -> c1.getCreateTime().compareTo(c2.getCreateTime())>0 ? c1 : c2), Optional::get))); //此时map中每个键 只有 一个值 再将map 转为list集合 并按照时间倒序排序 List<ProjectReport> endepot = new ArrayList<>(collect.values()).stream().sorted(Comparator.comparing(ProjectReport::getCreateTime).reversed()).collect(Collectors.toList());
Java List集合Stream流按条件分组获取每组中第一个对象
如果要获取某个属性值 就value.get(0).getxxx
Map<Integer, Coupon> resultList = couponList.stream().collect(Collectors.groupingBy(Coupon::getCouponId, Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))));
理论
- 分区:将 stream 按条件分为两个 Map ,比如员工按薪资是否高于8000分为两部分。
- 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。
案例:将员工按薪资是否高于8000分为两部分;将员工按性别和地区分组
public class StreamTest { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, "male", "New York")); personList.add(new Person("Jack", 7000, "male", "Washington")); personList.add(new Person("Lily", 7800, "female", "Washington")); personList.add(new Person("Anni", 8200, "female", "New York")); personList.add(new Person("Owen", 9500, "male", "New York")); personList.add(new Person("Alisa", 7900, "female", "New York")); // 将员工按薪资是否高于8000分组 Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000)); // 将员工按性别分组 Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex)); // 将员工先按性别分组,再按地区分组 Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea))); System.out.println("员工按薪资是否大于8000分组情况:" + part); System.out.println("员工按性别分组情况:" + group); System.out.println("员工按性别、地区:" + group2); } }
输出结果:
员工按薪资是否大于8000分组情况:{false=[mutest.Person@2d98a335, mutest.Person@16b98e56, mutest.Person@7ef20235], true=[mutest.Person@27d6c5e0, mutest.Person@4f3f5b24, mutest.Person@15aeb7ab]} 员工按性别分组情况:{female=[mutest.Person@16b98e56, mutest.Person@4f3f5b24, mutest.Person@7ef20235], male=[mutest.Person@27d6c5e0, mutest.Person@2d98a335, mutest.Person@15aeb7ab]} 员工按性别、地区:{female={New York=[mutest.Person@4f3f5b24, mutest.Person@7ef20235], Washington=[mutest.Person@16b98e56]}, male={New York=[mutest.Person@27d6c5e0, mutest.Person@15aeb7ab], Washington=[mutest.Person@2d98a335]}}