02-stream

1. Stream

stream流,关注《做什么》,而不是《怎么做》

  1. 特点:
    1. 专注于对容器对象的聚合操作
    2. 提供串行/并行两种模式
      • 使用Fork/Join框架拆分任务
  2. 使用步骤
    • 获取流 -> 中间操作 -> 终结操作
    1. 中间操作,intermediate operation(Lazy)

      map (mapToInt, flatMap 等)、filter、distinct、sorted、peek、limit、skip、parallel、sequential、unordered、concat

    2. 终结操作,关闭流,terminal operation

      forEach、forEachOrdered、toArray、reduce、collect、min、max、count、iterator

    3. 短路操作,short-circuiting

      anyMatch、allMatch、noneMatch、findFirst、findAny

/*
 * JDK8 Stream API:
 *     https://docs.oracle.com/javase/8/docs/api/index.html
 * 意义:1. 性能高,发挥多核cpu优势
 */
public class T1_Stream {

    static List<String> list = new ArrayList<>();

    static {
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
    }

    /**
     * 筛选姓张、长度为3的人名
     */
    @Test
    public void T1_tradition() {
        // 以张开头的元素
        List<String> listA = new ArrayList<>();
        for (String s : list) {
            if (s.startsWith("张")) {
                listA.add(s);
            }
        }

        // 姓名长度为3的人
        List<String> listB = new ArrayList<>();
        for (String s : listA) {
            if (s.length() == 3) {
                listB.add(s);
            }
        }

        // 遍历listB集合
        for (String s : listB) {
            System.out.println(s);
        }
    }

    /*
     * stream流
     * 关注《做什么》,而不是《怎么做》
     *
     * 1. 特点:
     *      1. 专注于对容器对象的聚合操作
     *      2. 提供串行/并行两种模式
     *          使用Fork/Join框架拆分任务
     * 2. 使用步骤
     *  获取流 -> 中间操作 -> 终结操作
     *      1. 中间操作,intermediate operation(Lazy)。
     *          map (mapToInt, flatMap 等)、filter、distinct、sorted、peek、limit、skip、parallel、sequential、unordered、concat
     *      2. 终结操作,关闭流,terminal operation。
     *          forEach、forEachOrdered、toArray、reduce、collect、min、max、count、iterator
     *      3. 短路操作,short-circuiting。
     *          anyMatch、allMatch、noneMatch、findFirst、findAny
     */
    @Test
    public void T2_stream() {
        /*
         * Collection<E> 集合的顶层接口
         * default Stream<E> stream() {
         *      return StreamSupport.stream(spliterator(), false);
         *  }
         */
        Stream<String> stream = list.stream();
        stream.filter(name -> name.startsWith("张")) // 返回新的stream对象
                .filter(name -> name.length() == 3)
                .forEach(System.out::println);

        // 终结操作后的操作
        // java.lang.IllegalStateException: stream has already been operated upon or closed
        stream.limit(1);
    }

}






































































 
 
 







2. GetStream

获取流

  1. Collection集合。stream默认方法获取流
    • default Stream<E> stream()
  2. 数组。Stream接口的静态方法Stream.of()
    • static <T> Stream<T> of(T... values)
/*
 * java.util.stream.Stream<T>是Java 8新加入的最常用的流接口(这并不是一个函数式接口)
 * 获取流
 *      1. Collection集合。stream默认方法获取流
 *         default Stream<E> stream()
 *      2. 数组。Stream接口的静态方法Stream.of()
 *         static <T> Stream<T> of(T... values)
 */
public class T2_GetStream {

    @Test
    public void T1_list() {
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
    }

    @Test
    public void T2_set() {
        Set<String> set = new HashSet<>();
        Stream<String> stream = set.stream();
    }

    @Test
    public void T3_map() {
        Map<String, String> map = new HashMap<>();

        // 获取键,存储到一个Set集合中
        Set<String> keySet = map.keySet();
        Stream<String> streamKey = keySet.stream();

        // 获取值,存储到一个Collection集合中
        Collection<String> values = map.values();
        Stream<String> streamValue = values.stream();

        // 获取键值对(键与值的映射关系 entrySet)
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Stream<Map.Entry<String, String>> streamEntry = entries.stream();
    }

    @Test
    public void T4_array() {
        Integer[] arrInt = {1, 2, 3, 4, 5};
        String[] arrStr = {"a", "bb", "ccc"};
        Stream<Integer> streamInt = Stream.of(arrInt);
        Stream<String> streamStr = Stream.of(arrStr);
    }

}













 





 








 



 



 






 
 



3. API

public class T3_API {

    @Test
    public void T1_forEach() {
        Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六", "田七");

        // terminal operation
        // void forEach(Consumer<? super T> action);
        // void accept(T t);
        stream.forEach(System.out::println);
    }

    @Test
    public void T2_filter() {
        Stream<String> stream = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");

        // intermediate operation.
        // Stream<T> filter(Predicate<? super T> predicate);
        // boolean test(T t);
        Stream<String> stream2 = stream.filter(name -> name.startsWith("张"));

        stream2.forEach(System.out::println);

        // Stream属于管道流,只能被消费(使用)一次
        // IllegalStateException: stream has already been operated upon or closed
        stream.forEach(System.out::println);
    }

    @Test
    public void T3_map() {
        Stream<String> stream = Stream.of("1", "2", "3", "4");

        // 使用map方法,把字符串类型的整数,转换(映射)为Integer类型的整数

        // intermediate operation.
        // <R> Stream<R> map(Function<? super T, ? extends R> mapper);
        // R apply(T t);
        stream.map(s -> Integer.parseInt(s) + 1)
                .forEach(System.out::println);
    }

    @Test
    public void T4_count() {
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7);

        // terminal operation.
        // long count();
        long count = stream.count();
        System.out.println(count);
    }

    @Test
    public void T5_collect() {
        // 1. List:名字长度3个字,存到新list中
        List<String> list = CollUtil.newArrayList("林青霞", "张曼玉", "王祖贤", "柳岩");

        List<String> names = list.stream()
                .filter(s -> s.length() == 3)
                .collect(Collectors.toList());

        names.forEach(System.out::println);

        // 2. Set:年龄大于25,存到新set中
        Set<Integer> set = CollUtil.newHashSet(10, 20, 30, 33, 35);

        Set<Integer> ages = set.stream()
                .filter(age -> age > 25)
                .collect(Collectors.toSet());

        ages.forEach(System.out::println);


        // 3. Map:年龄数据大于28,存入map中
        String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33", "柳岩,25"};

        Stream<String> arrayStream = Stream.of(strArray)
                .filter(s -> Integer.parseInt(s.split(",")[1]) > 28);


        // 姓名作key,年龄作value
        Map<String, Integer> map = arrayStream.collect(
                Collectors.toMap(
                        s -> s.split(",")[0],
                        s -> Integer.parseInt(s.split(",")[1])
                )
        );

        map.forEach((k, v) -> System.out.println(k + ",," + v));
    }

    @Test
    public void T6_skip() {
        String[] arr = {"美羊羊", "喜洋洋", "懒洋洋", "灰太狼", "红太狼"};
        Stream<String> stream = Stream.of(arr);

        // 跳过元素,得到新stream
        // Stream<T> skip(long n);
        stream.skip(3)
                .forEach(System.out::println);
    }

    @Test
    public void T7_concat() {
        Stream<String> stream1 = Stream.of("1", "2", "3", "4", "5");
        Stream<String> stream2 = Stream.of("7", "8", "9");

        // 合并流
        Stream.concat(stream1, stream2)
                .forEach(System.out::println);
    }

    @Test
    public void T8_generate_iterate() {
        // 随机10个UUID
        List<String> list = Stream.generate(IdUtil::simpleUUID)
                .limit(10)
                .collect(Collectors.toList());

        list.forEach(System.out::println);

        // 10个从0开始偶数
        List<Integer> ints = Stream.iterate(0, x -> x + 2)
                .limit(10)
                .collect(Collectors.toList());

        ints.forEach(System.out::println);

        // < 10,从0开始偶数
        List<Integer> lts = Stream.iterate(0, x -> x < 10, x -> x + 2)
                .collect(Collectors.toList());

        lts.forEach(System.out::println);
    }

}









 









 

















 









 










 








 













 
 
 
 












 









 






 
 
 




 






 






4. MenuTree

public class T4_MenuTree {

    @Test
    public void test() {
        // 模拟从DB查询出来
        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)
        );

        // 获取父节点
        List<Menu> collect = menus.stream()
                .filter(m -> m.getPId() == 0)
                .peek((m) -> m.setChildren(getChildren(m, menus)))
                .collect(Collectors.toList());

        System.out.println(JSONUtil.toJsonPrettyStr(collect));
    }

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

}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class Menu {

    public Integer id;
    public String name;
    public Integer pId;
    public List<Menu> children;


    public Menu(Integer id, String name, Integer pId) {
        this.id = id;
        this.name = name;
        this.pId = pId;
    }
}