zoukankan      html  css  js  c++  java
  • Java 8 新特性-Stream更优雅的处理集合入门

    Java 8 新特性之——Stream

    一. 简单介绍

    Stream是Java 8提出了的一种新的对集合对象功能的增强。它集合Lambda表达式,对集合提供了一些非常便利,高效的操作,使得代码具有非常高的可读性,优雅性!!举个例子来说,它就像一个流水线操作,对输入流水线的东西(水果)进行一系列加工处理,最后获取到我们需要的某种特殊的水果(没有洗过的苹果)。

    1. Stream提供了对集合的便捷化处理方式
    2. 声明式编程的思想
    3. 代码更加优雅,简洁,不信往下看→_→

    来个例子来看看Stream风格

    上海从今年7月1号开始,进行了史无前例的垃圾分类,先看个图图,下图是上海最近流行的挎包(捂脸笑哭),怕不怕,哈哈。

    上海流行挎包(捂脸笑)

    闲话不多说,进入正题,现在需要将一堆垃圾List<Garbage> garbages分类处理。

    • 使用了Stream的代码风格
    //有一堆没分类的垃圾
    List<Garbage> garbage = new ArrayList<>();
    //通过 Java 8 提供的流优雅的处理下,瞧好喽
    List<Garbage> 干垃圾 = garbage.stream()         //1. 垃圾倒出来,放到流水线
                    .filter(x -> "挑出有害垃圾")     //2. 挑出有害垃圾 
                    .filter(x -> "挑出可回收垃圾")   //3. 挑出可回收垃圾
                    .filter(x -> "挑出有害垃圾")     //4. 挑出有害垃圾
                    .collect(Collectors.toList());  //5. 把剩下的干垃圾装到干垃圾桶
    /** 上面是不是非常优雅呢 **/
    

    二. Stream 的操作流程

    Stream的所有操作分为三个阶段,【创建】>> 【中间操作】>> 【终端操作】

    1. Stream 的【创建】

    • 方式一

      list.stream()

      //通过List集合创建
      List<String> list = Arrays.asList("1", "2", "3");
      //list.stream()
      Stream<String> stream = list.stream();
      
    • 方式二

      Stream.of()

      //直接通过指定的元素创建
      Stream<String> stream = Stream.of("1", "2", "3");
      //通过数组Array
      String[] arrays = {"a", "b", "c"};
      Stream<String> stream = Stream.of(arrays);
      //和上面区别不大
      Stream<String> stream1 = Arrays.stream(arrays);
      
    • 其他

    • 数值流的操作
      对于基本数值型,目前有三种对应的包装类型 Stream:

    IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
    IntStream.range(1, 3).forEach(System.out::println);
    IntStream.rangeClosed(1, 3).forEach(System.out::println);
    

    2. Stream的流水线操作【中间操作】

    下面式常用的中间操作

    Stream Operation Goal Input
    filter filter 方法用于通过设置的条件过滤出元素。 条件(返回布尔值)Predicate
    map map 方法用于映射每个元素到对应的结果 可以是一个功能 Function
    limit limit 方法用于获取指定数量的流 int值
    sorted sorted 方法用于对流进行排序 Comparator
    distinct 去除重复 --
    parallel parallelStream 是流并行处理程序的代替方法 --
    • filter统计空字符串的个数
    List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
    // 获取空字符串的数量
    int count = strings.stream().filter(string -> string.isEmpty()).count()
    
    • map 使用 map 输出了元素对应的平方数
    List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
    // 获取对应的平方数
    List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
    
    • limit使用 limit 方法打印出 10 条数据
    Random random = new Random();
    random.ints().limit(10).forEach(System.out::println);
    
    • sorted使用 sorted 方法对输出的 10 个随机数进行排序
    Random random = new Random();
    random.ints().limit(10).sorted().forEach(System.out::println);
    
    • distinct使用 distinct 对元素进行去重
    List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
    numbers.stream().distinct().forEach(System.out::println);
    
    • parallel 使用 parallelStream 来输出空字符串的数量
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
    // 获取空字符串的数量
    int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
    

    3. 【终端操作】

    Stream Operation Goal Input Or Output
    forEach 遍历元素 其他操作
    count 统计元素个数 --
    collect 聚合操作 --
    • forEach遍历打印
    Stream.of("a", "b", "c").forEach(System.out::println);
    
    • count统计'a'的数量
    long count = Stream.of("a", "b", "c", "a").filter(x -> "a".equals(x)).count();//2
    
    • collect聚合
    // 1. 聚合转成List
    List<String> list1 = stream.collect(Collectors.toList());
    List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
    // 2. 聚合转成Set
    Set set1 = stream.collect(Collectors.toSet());
    Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
    // 3. 聚合转成String
    String str = stream.collect(Collectors.joining()).toString();
    // 4. ···其他
    

    1. 循环list中的所有元素然后删除重复

        /**
         * 循环list中的所有元素然后删除重复
         *
         * @param list 待去重的list
         * @return 去重后的list
         */
         public static List<StaffResponse> removeDuplicate(List<StaffResponse> list) {
            for (int i = 0; i < list.size() - 1; i++) {
                for (int j = list.size() - 1; j > i; j--) {
                    if (list.get(j).getStaffNo().equals(list.get(i).getStaffNo())) {
                        list.remove(j);
                    }
                }
            }
            return list;
        }
    
    

    2. 利用java8新特性去重参考原文链接

    //list集合中根据userName去重
    List<User> lists = lists.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(User::getUsrName))), ArrayList::new));
    

    3. 排序 参考原文链接

    List<PromotionForHomeDto> list = promotionBasicDao.
    list(new WherePrams().orderBy("create_time desc"));
    list = list.stream().sorted(Comparator.comparing(PromotionForHomeDto::getCreateTime))
                    .collect(Collectors.toList());
    

    4. 分组

    把一个集合分组(原来集合里的数据顺序会打乱重排列)会默认使用HashMap

    List<Students> stus...;
    Map<Integer, List<Student>> group = stus.stream().collect(Collectors.groupingBy(Student::getStudentNo));
    

    解决办法,使用LinkedHashMap分组按之前List的顺序

    List<Students> stus...;
    Map<Integer, List<Student>> group = stus.stream().collect(Collectors.groupingBy(Student::getStudentNo, LinkedHashMap::new, Collectors.toList()));
    

    实测例子:

    public static void main(String[] args) {
        List<String> lists = new ArrayList<>();
        lists.add("A");
        lists.add("D");
        lists.add("C");
        lists.add("B");
        lists.add("A");
        System.out.println("原始列表数据 :" + lists);
        
        Map<String, List<String>> collect1 = lists.stream().collect(Collectors.groupingBy(x -> x));
        System.out.println("JAVA Stream分组处理完,默认处理:" + collect1);
        Map<String, List<String>> collect = lists.stream().collect(Collectors.groupingBy(x -> x, LinkedHashMap::new, Collectors.toList()));
        System.out.println("JAVA Stream分组处理完,LinkedHashMap:" + collect);
    }
    

    4. List转Map

    /*
    * List -> Map
    * 需要注意的是:
    * toMap 如果集合对象有重复的key,会报错Duplicate key ....
    *  apple1,apple12的id都为1。
    *  可以用 (o1,o2)->o1 来设置,如果有重复的key,则保留key1,舍弃key2
    */
    Map<String, String> collect2 = lists.stream().collect(Collectors.toMap(String::toLowerCase, x -> x + "测试", (o1, x2) -> o1));
    System.out.println("List转Map:" + collect2);
    

    三. 简单说下声明式编程

    小故事:早上刚上班,经理找到大胖说:“大胖啊,咱们下去去聚餐,软件园旁边有好几家不错的餐馆,如巫山烤鱼、海底捞、大鸭梨,你到大众点评调查一下,也问问去过的同事,看看哪家的口碑好。我们有14个人,预定一张大桌子,然后用滴滴约4辆车,每辆车坐3~4人,我们会在11点半出发”。
    如果经理是程序员,大胖是计算机,这就是典型的命令式编程
    实际上,现实中一般是经理对大胖说:“大胖啊,我给你交代一件事,咱们下午要聚餐,你在软件园旁边找一家合适的餐馆,我们有14个人,11点半出发”。这种就是声明式编程

    1. 声明式编程最知名的就是我们都熟悉的SQL

    SELECT stu.id, stu.name, ss.score
      FROM student stu, student_score ss
     WHERE stu.id = ss.id
       AND ss.score > 80
    

    2. 用Java也来举个例子

    有一个学生列表,计算出年龄小于18岁的学生数量

    传统命令式编程

    //声明一个计数器,遍历学生集合,如果学生年龄小于18岁,计数器+1
    int count = 0;
    Iterator<Student> iter = students.iterator();
    
    while(iter.hasNext()) {
        Student s = iter.next();
        if (s.getAge < 18) {
            count++;
        }
    }
    

    声明式编程

    //过滤学生构成的流(Stream),只把年龄小于18岁的留下,然后做个统计。
    int count = students.stream()
            .filter(s -> s.getAge() < 18)
            .count();
    

    声明式编程也是一种高度的抽象,我只告诉你我要干什么,至于怎么干,我Don't care

    参考资料书-刘欣·码农翻身

    参考资料1

    参考资料2

  • 相关阅读:
    浅析Go中的MPG模式(一)
    panic: assignment to entry in nil map
    Golang 新手可能会踩的 50 个坑
    小刘的go面试题
    go 单元测试整理
    go test 测试单个文件和测试单个函数
    mac pro锁屏后没有声音了怎么处理
    go json返回时间字符串处理time.Time类型
    php求一个字符串中不重复的最长子串
    业务订单号生成算法,每秒50W左右,不同机器保证不重复,包含日期可读性好
  • 原文地址:https://www.cnblogs.com/baijinqiang/p/11137199.html
Copyright © 2011-2022 走看看