JDK8 Stream详解

323 阅读4分钟

Stream是JDK8 API的新成员,它允许以声明性方式处理数据集合.

1 特点:

1 代码简洁: 函数式编程写出的代码简洁且意图明确,使用Stream接口让你从此告别for循环

2 多核友好: java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下方法.

2 流程:

第一步: 把集合转为stram流

第二步: 操作stream流

stream流在管道中经过中间操作,(intermediate operation) 的处理,最终操作(terminal operation)得到前面处理的结果

3 操作符

两种:中间操作符,终止操作符

4 详情

1 生成流

  • stream() − 为集合创建串行流
  • parallelStream() − 为集合创建并行流
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

2 中间操作符

filter 过滤集合中不符合条件的元素

    /**
     * filter过滤集合中不符合条件的元素
     */
    @Test
    public void filter() {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        //集合转成流
        //方式一  list.stream
        List<String> filter = strings.stream().filter(str -> str.contains("f")).collect(Collectors.toList());

        System.out.println(filter);

    }

distinct 去重集合中元素

    /**
     * 去重集合中元素
     */
    @Test
    public void distinct() {

        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "abc", "bc");
        System.out.println(strings);

        //去重元素
        List<String> filter = strings.stream().distinct().collect(Collectors.toList());
        System.out.println(filter);

        //------------------------------------------------
        去重对象  对象的地址不一样,即使内容一样,也不能去重.   
            
        解决:    需要重写对象的equals和hashcode方法
    }

limit 获取流中前几个元素

    /**
     * 获取流中前几个元素
     */
    @Test
    public void limit() {

        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        //集合转成流
        List<String> filter = strings.stream().limit(2).collect(Collectors.toList());

        System.out.println(filter);

    }

skip 获取流中除去前n个元素

    /**
     * 获取流中除去前n个元素
     */
    @Test
    public void skip() {

        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        //集合转成流
        List<String> filter = strings.stream().skip(2).collect(Collectors.toList());

        System.out.println(filter);

    }

map 对流中所有元素统一处理

    /**
     * 对流中所有元素统一处理
     */
    @Test
    public void map() {

        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        //集合转成流
        List<String> filter = strings.stream().map(str -> str.concat("11")).collect(Collectors.toList());

        System.out.println(filter);

    }

flatmap 对流中所有元素,进行扁平化处理

    /**
     * 对流中所有元素  进行扁平化处理
     */
    @Test
    public void flatmap() {

        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        //集合转成流
        /**
         * 解析flatmap
         * 1 [a,b,c] [b,c]
         * 2 扁平化操作 [a,b,c,b,c]
         */

        List<Character> list = strings.stream().flatMap(str -> demo.getCharacterByStrinng(str)).collect(Collectors.toList());
        System.out.println(list);

    }

    /**
     * 字符串转换为字符流
     *
     * @param str
     * @return
     */
    public static Stream<Character> getCharacterByStrinng(String str) {
        List<Character> characterList = new ArrayList<>();

        for (Character user : str.toCharArray()) {
            characterList.add(user);
        }

        return characterList.stream();
    }

sorted 排序

    /**
     * 排序
     */
    @Test
    public void sorted() {

        // List<String> strings = new ArrayList<>();
        List<String> strings = Arrays.asList("abc", "b", "bc", "efg", "abcd");

        //集合转成流
        //默认排序 按照字符排序
        List<String> list = strings.stream().sorted().collect(Collectors.toList());
        System.out.println(list);

        //-----------------数字排序---------------------
        List<Integer> list1 = Arrays.asList(12, 1, 23, 234, 24);
        list1.stream().sorted().collect(Collectors.toList()).forEach(s -> System.out.println(s));

        //-------------------汉字排序-------------------
        //需要添加jar包
         //  <!--apache集合操作工具包-->
         // <dependency>
         //   <groupId>org.apache.commons</groupId>
         //   <artifactId>commons-collections4</artifactId>
         //   <version>4.3</version>
         // </dependency>
        
        
        List<String> list2 = Arrays.asList("张三", "赵柳", "王五", "李四", "李哥");

        list2.stream().sorted(Collator.getInstance(Locale.CANADA)).collect(Collectors.toList()).forEach(System.out::println);


    }

3终止操作符

anyMatch

    /**
     * 集合中是否有一个元素满足条件
     */
    @Test
    public void anyMatch() {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        boolean a = strings.stream().anyMatch(s -> s.contains("a"));
        System.out.println(a);

    }

allMatch

    /**
     * 集合中是否都满足条件
     */
    @Test
    public void allMatch() {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        boolean a = strings.stream().allMatch(s -> s.contains("a"));
        System.out.println(a);

    }

noneMatch

    /**
     * 集合中是否都不满足条件
     */
    @Test
    public void noneMatch() {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        boolean a = strings.stream().noneMatch(s -> s.contains("a"));
        System.out.println(a);

    }

findAll

    /**
     * 返回集合中任意元素
     */
    @Test
    public void findAll() {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        Optional<String> any = strings.stream().findAny();
        if (any.isPresent()) System.out.println(any.get());

    }

findFirst

    /**
     * 返回集合中第一个元素
     */
    @Test
    public void findFirst() {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        Optional<String> any = strings.stream().findFirst();
        if (any.isPresent()) System.out.println(any.get());


    }

forEach

    /**
     * 遍历 循环
     */
    @Test
    public void forEach() {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd");

        strings.stream().forEach(s -> System.out.println(s));
        
    }

collect

    /**
     * 收集器,将流转换为其他形式
     */
    @Test
    public void collect() {
        List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd");

        //list set map
        Set<String> collect = strings.stream().collect(Collectors.toSet());

        System.out.println(collect);

        //-----------------------------map------------------
        //下面方式 集合中允许有重复的元素
        Map<String, String> collect1 = strings.stream().collect(Collectors.toMap(v -> "pro_" + v, v -> v, (oldvalue, newvalue) -> newvalue));

        //下面方式 集合中不能有重复的元素
        // Map<String, String> collect1 = strings.stream().collect(Collectors.toMap(v -> "pro_"+v, v -> v));
        System.out.println(collect1);

    }

reduce

    /**
     * 将流中数据反复结合起来得到一个结果
     */
    @Test
    public void reduce() {
        List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd");

        Optional<String> reduce = strings.stream().reduce((acc, item) -> {
            //反复结合起来得到结果
            // return acc+item;

            //将结果进行处理 如去掉里面a字符串
            return (acc + item).replace("a", "");
        });

        if (reduce.isPresent())
            System.out.println(reduce.get());


    }

count

    /**
     * 返回集合中元素数量
     */
    @Test
    public void count() {
        List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd");

        long count = strings.stream().count();
        System.out.println(count);


    }

5 经典案列

需求: 父子部门的封装

    @Test
    public void testtree(){
        //模拟从数据库查询出来
        List<Menu> menus = Arrays.asList(
                new Menu(1,"根节点",0),
                new Menu(2,"子节点1",1),
                new Menu(3,"子节点1.1",2),
                new Menu(4,"子节点1.2",2),
                new Menu(5,"根节点1.3",2),
                new Menu(6,"根节点2",1),
                new Menu(7,"根节点2.1",6),
                new Menu(8,"根节点2.2",6),
                new Menu(9,"根节点2.2.1",7),
                new Menu(10,"根节点2.2.2",7),
                new Menu(11,"根节点3",1),
                new Menu(12,"根节点3.1",11),
                new Menu(12,"根节点3.1",11)
        );

        //得到所有的id
        //此处有问题, 如果想得到一个父节点下所有子节点,则该方法不行
        List<Integer> collect1 = menus.stream()
                .distinct()
                .map(str -> str.getId())
                .collect(Collectors.toList());
        System.out.println(collect1);



        System.out.println("====================================");


        System.out.println(JSON.toJSON(menus));
        System.out.println("====================================");

        //获取父节点
        List<Menu> collect = menus.stream().filter(m -> m.getParentId() == 0).map(
                (m) -> {
                    m.setChildList(getChildrens(m, menus));
                    return m;
                }
        ).collect(Collectors.toList());
        System.out.println("-------转json输出结果-------");
        System.out.println(JSON.toJSON(collect));
    }

    /**
     * 递归查询子节点
     * @param root  根节点
     * @param all   所有节点
     * @return 根节点信息
     */
    private List<Menu> getChildrens(Menu root, List<Menu> all) {
        List<Menu> children = all.stream().filter(m -> {
            return Objects.equals(m.getParentId(), root.getId());
        }).map(
                (m) -> {
                    m.setChildList(getChildrens(m, all));
                    return m;
                }
        ).collect(Collectors.toList());
        return children;
    }