• 使用Stream快速对List进行一些操作


    首先定义一个 Apple 类,示例如下:

    public class Apple {
        private Integer id;
        private String name;
        private BigDecimal money;
        private Integer num;
        public Apple(Integer id, String name, BigDecimal money, Integer num) {
            this.id = id;
            this.name = name;
            this.money = money;
            this.num = num;
        }
    }

    然后添加一些测试数据:

    List<Apple> appleList = new ArrayList<>();  //存放apple对象集合
     
    Apple apple1 =  new Apple(1,"苹果1",new BigDecimal("3.25"),10);
    Apple apple12 = new Apple(1,"苹果2",new BigDecimal("1.35"),20);
    Apple apple2 =  new Apple(2,"香蕉",new BigDecimal("2.89"),30);
    Apple apple3 =  new Apple(3,"荔枝",new BigDecimal("9.99"),40);
     
    appleList.add(apple1);
    appleList.add(apple12);
    appleList.add(apple2);
    appleList.add(apple3);

    1. 排序

    可以使用 sort 方法对对象中的单字段或者多字段进行排序:

    //排序
    //单字段排序,根据id排序
    appleList.sort(Comparator.comparing(Apple::getId));
    
    //多字段排序,根据id,数量排序
    appleList.sort(Comparator.comparing(Apple::getId).thenComparing(User::getNum));

    2. 分组

    可快速对 List 中的对象元素以对象的某一属性进行分类,比如以 ID 进行分组,将 ID 相同的对象放在一起,那么可以直接这么做:

    //List 以ID分组 Map<Integer,List<Apple>>
    Map<Integer, List<Apple>> groupBy = appleList.stream().collect(Collectors.groupingBy(Apple::getId));
     
    System.out.println("groupBy:" + groupBy);
    {1=[Apple{id=1, name='苹果1', money=3.25, num=10}, Apple{id=1, name='苹果2', money=1.35, num=20}], 2=[Apple{id=2, name='香蕉', money=2.89, num=30}], 3=[Apple{id=3, name='荔枝', money=9.99, num=40}]}

    3. List 转 Map

    这是一个会用到的常用操作,比如 List 中存放的 Apple 对象,现在要转换成 ID 为键,对象为值的 Map,那么可以直接这么操作:

    /**
     * List -> Map
     * 需要注意的是:
     * toMap 如果集合对象有重复的key,会报错 Duplicate key ....
     *  apple1,apple12的id都为 1。
     *  可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
     */
    Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));

    然后我们打印 Map 结果:

    {1=Apple{id=1, name='苹果1', money=3.25, num=10}, 2=Apple{id=2, name='香蕉', money=2.89, num=30}, 3=Apple{id=3, name='荔枝', money=9.99, num=40}}

    4. 过滤查找元素

    这个也使用的比较频繁,比如我们要从 List 中找到名称为香蕉的对象,那么可以这么操作:

    //过滤出符合条件的数据
    List<Apple> filterList = appleList.stream().filter(a -> a.getName().equals("香蕉")).collect(Collectors.toList());
     
    System.out.println("filterList:"+filterList);
    [Apple{id=2, name='香蕉', money=2.89, num=30}]

    5. 求和

    将集合中的数据按照某个属性求和,如果是基本类型,可以使用 mapToInt 然后调用 sum 方法,如果是大树则使用 reduce 并调用 BigDecimal::add 方法。

    //计算 总金额
    
    //基本类型
    int total = appleList.stream().mapToInt(Apple::getMoney).sum();
    
    //大数
    BigDecimal totalMoney = appleList.stream().map(Apple::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
    System.out.println("totalMoney:" + totalMoney);  //totalMoney:17.48

    注意,上面的求和不能过滤 BigDecimal 对象为 null 的情况,可能会报空指针,这种情况,我们可以用 filter 方法过滤,或者重写求和方法。

    6. 查找流中最大/小值

    利用 Collectors.maxBy 和 Collectors.minBy 来计算流中的最大或最小值。

    Optional<Dish> maxDish = Dish.menu.stream().
          collect(Collectors.maxBy(Comparator.comparing(Dish::getCalories)));
    maxDish.ifPresent(System.out::println);
     
    Optional<Dish> minDish = Dish.menu.stream().
          collect(Collectors.minBy(Comparator.comparing(Dish::getCalories)));
    minDish.ifPresent(System.out::println);

    7. 根据属性去重

    import static java.util.Comparator.comparingLong;
    import static java.util.stream.Collectors.collectingAndThen;
    import static java.util.stream.Collectors.toCollection;
     
    // 根据id去重
    List<Person> unique = appleList.stream().collect(
                collectingAndThen(
                    toCollection(() -> new TreeSet<>(comparingLong(Apple::getId))), ArrayList::new)
            );

    8. 获取交集/并集/差集/去重并集

    import static java.util.stream.Collectors.toList;
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
    
        public static void main(String[] args) {
            List<String> list1 = new ArrayList();
            list1.add("1111");
            list1.add("2222");
            list1.add("3333");
    
            List<String> list2 = new ArrayList();
            list2.add("3333");
            list2.add("4444");
            list2.add("5555");
    
            // 交集     拓展:list2里面如果是对象,则需要提取每个对象的某一属性组成新的list,多个条件则为多个list
            List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(Collectors.toList());
            System.out.println("---得到交集 intersection---");
            intersection.parallelStream().forEach(System.out :: println);
    
            // 差集 (list1 - list2)    同上拓展
            List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(Collectors.toList());
            System.out.println("---得到差集 reduce1 (list1 - list2)---");
            reduce1.parallelStream().forEach(System.out :: println);
    
            // 差集 (list2 - list1)
            List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(Collectors.toList());
            System.out.println("---得到差集 reduce2 (list2 - list1)---");
            reduce2.parallelStream().forEach(System.out :: println);
    
            // 并集
            List<String> listAll = list1.parallelStream().collect(toList());
            List<String> listAll2 = list2.parallelStream().collect(Collectors.toList());
            listAll.addAll(listAll2);
            System.out.println("---得到并集 listAll---");
            listAll.parallelStream().forEach(System.out :: println);
    
            // 去重并集
            List<String> listAllDistinct = listAll.stream().distinct().collect(Collectors.toList());
            System.out.println("---得到去重并集 listAllDistinct---");
            listAllDistinct.parallelStream().forEach(System.out :: println);
    
            System.out.println("---原来的List1---");
            list1.parallelStream().forEach(System.out :: println);
            System.out.println("---原来的List2---");
            list2.parallelStream().forEach(System.out :: println);
    
            // 一般有filter 操作时,不用并行流parallelStream ,如果用的话可能会导致线程安全问题
    
        }
    }

     9.根据list里的对象去重操作

    1、根据对象中某个属性去重

    1.1、创建提取方法

    private <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> concurrentHashMap = new ConcurrentHashMap<>();
        return t -> concurrentHashMap.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    1.2、利用filter

    List<TestCommodity> codeDistinctList = testCommodityList
                .stream()
                .filter(distinctByKey(TestCommodity::getCode))
                .collect(Collectors.toList());

    2、根据对象中多个个属性去重,利用collectingAndThen

    List<TestCommodity> cbList = testCommodityList
                .stream()
                .collect(
                        Collectors.collectingAndThen(
                                Collectors.toCollection(
                                () -> new TreeSet<>(
                                        Comparator.comparing(
                                                tc -> tc.getCode() + ";" + tc.getBarCode()))), ArrayList::new));

    摘自:https://bestzuo.cn/posts/stream-list.html#1-%E6%8E%92%E5%BA%8F

  • 相关阅读:
    HttpClient
    spring入门
    morphia进阶
    morphia基本API方法
    mangodb数据库框架morphia注解
    学与思
    解决vscode执行yarn启动项目报错
    使用swiper+动画实现轮播图自动播放
    vue中使用el-tree实现一行显示多条数据
    使用git命令提交部分修改代码
  • 原文地址:https://www.cnblogs.com/lyh233/p/14690774.html
Copyright © 2020-2023  润新知