15.JDK8新特性之Stream流

  1. 什么是 Stream
    Stream(流)是一个来自数据源的元素队列并支持聚合操作
    1)元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
    2)数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
    3)聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
    和以前的Collection操作不同, Stream操作还有两个基础的特征:
    1)Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
    2)内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

  2. 生成流
    在 Java 8 中, 集合接口有两个方法来生成流:
    1)stream() − 为集合创建串行流。
    2)parallelStream() − 为集合创建并行流。
    3)Stream.of()方法,有针对int,long的专用流IntStream,LongStream。

    List<Integer> list = Arrays.asList(1, 2, 3);
    list.stream().forEach(n -> System.out.println(n));//结果按顺序输出 123
    list.parallelStream().forEach(a -> System.out.println(a));//结果并不是按顺序输出
    

    :由上可知,串行流输出的结果是按顺序输出,而并行流并不是如此,并行流是使用的ForkJoinPool 分而治之的算法实现的,当在数据量比较大(计算量比较大)的时候使用并行流比较合适。

    public static void main(String[] args) {
            List<User> users = initList();
            //列出岁数大于30人
            users.stream().filter(t -> t.getAge() > 30).collect(Collectors.toList()).forEach(a -> System.out.println(a.getName()));
            System.out.println("---------------------------------------------------------------------------------------------------");
            //找到年纪最大的人
            String name = users.stream().max((a1, a2) -> a1.getAge() - a2.getAge()).get().getName();
            System.out.println(name);
            System.out.println("---------------------------------------------------------------------------------------------------");
            //求所有人的年纪总和
            Integer integer = users.stream().map(User::getAge).reduce(Integer::sum).get();
            System.out.println(integer);
            System.out.println("---------------------------------------------------------------------------------------------------");
            //按年纪分组
            users = initList();
            users.stream().collect(Collectors.groupingBy(User::getAge)).forEach((key, value) -> {
                System.out.println(key+ ": " +value.toString());
            });
            System.out.println("---------------------------------------------------------------------------------------------------");
            users.stream().distinct().collect(Collectors.toList()).forEach(t -> System.out.println(t.toString()));
        }
    
        private static List<User> initList(){
            List<User> list = new ArrayList();
            list.add(new User("张三",15));
            list.add(new User("李四",45));
            list.add(new User("王五",76));
            list.add(new User("范六",5));
            list.add(new User("花七",67));
            list.add(new User("算法",25));
            list.add(new User("傲視",67));
            return list;
        }
    
  3. 缩减操作
    因为每个缩减操作都把一个流缩减为一个值,好比最大值,最小值。当然流API,把min()和max(),count(),reduce() 这些操作称为特例缩减。

    List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            list.add(5);
            list.add(6);
           // list.stream().sorted().forEachOrdered(a -> System.out.println(a));
            Optional<Integer> reduce = list.stream().reduce((a, b) -> a + b);
            //System.out.println(reduce.get());
            if (reduce.isPresent()) System.out.println(reduce.get());
            Integer reduce1 = list.stream().reduce(0, (a, b) -> a + b);
            System.out.println(reduce1);
    
            Optional<Integer> reduce2 = list.stream().reduce((a, b) -> a * b);
            if (reduce2.isPresent()) System.out.println(reduce2.get());
    
            Integer reduce3 = list.stream().reduce(1, (a, b) -> a * b);
            System.out.println(reduce3);
    
  4. 映射
    因为在很多时候,将一个流的元素映射到另一个流对我们是非常有帮助的。比如有一个包含有名字,手机号码和钱的数据库构成的流,可能你只想要映射钱这个字段到另一个流,这时候可能之前学到的知识就还不能解决,于是映射就站了出来了。
    另外,如果你希望对流中的元素应用一些转换,然后把转换的元素映射到一个新流里面,这时候也可以用映射。

            List<HeroPlayerGold> lists = new ArrayList<>();
    
        lists.add(new HeroPlayerGold("盖伦","RNG-Letme",100));
        lists.add(new HeroPlayerGold("诸葛亮","RNG-Xiaohu",300));
        lists.add(new HeroPlayerGold("露娜","RNG-MLXG",300));
        lists.add(new HeroPlayerGold("狄仁杰","RNG-UZI",500));
        lists.add(new HeroPlayerGold("牛头","RNG-Ming",600));
    
        //计算团队经济
        int reduce = lists.stream().map(player -> new Gold(player.getGold())).mapToInt(Gold::getGold).reduce(0, (a, b) -> a + b);
        System.out.println(reduce);
    
        double reduce1 = lists.stream().mapToInt(HeroPlayerGold::getGold).reduce(0, (a, b) -> a + b);
        System.out.println(reduce1);
    
            List<String> citys =Arrays.asList("GuangZhou ShangHai" ,"GuangZhou ShenZhen"  ,"ShangHai ShenZhen",
                    "BeiJing ShangHai","GuangZhou BeiJing" ,"ShenZhen BeiJing");
            citys.stream().map(mCitys -> Arrays.stream(mCitys.split(" "))).forEach(System.out :: println);//note1
            citys.stream()
                    .map(mCitys -> Arrays.stream(mCitys.split(" ")))
                    .forEach(cities -> cities.forEach(city -> System.out.println(city+" ")));//note2
            citys.stream().flatMap(mCitys -> Arrays.stream(mCitys.split(" "))).forEach(System.out :: println);//note3
    

    其中 //note1 处是无法打印元素的,使用map()打印元素的方式在 //note2 ,原因也在注释中交待了,但是使用了flatMap()方法后,直接就可以打印了 //note3

  5. 收集
    一个集合转成一个流,然后对流进行操作,其实这种操作是最多的,但有时候我们也是需要从流中收集起一些元素,并以集合的方式返回,我们把这种反向操作称为收集。
    流API中给我们提供了两种:

    <R, A> R collect(Collector<? super T, A, R> collector);
    <R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner);
    

    Collector接口位于 java.util.stream包中的声明。
    Collectors类是一个最终类,里面提供了大量的静态的收集器方法,借助他,我们基本可以实现各种复杂的功能了。
    我们来看一下toList和toSet方法:

    public static<T> Collector <T, ?, List<T>> toList()
    public static <T>  Collector <T, ?, Set <T>> toSet()
    

    其中 Collectors#toList()返回的收集器可以把流中元素收集到一个List中, Collectors#toSet()返回的收集器可以把流中的元素收集到一个Set中。比如:如果你想把元素收集到List中,你可以这样用, steam.collect(Collectors.toList)。

  6. Spliterator 迭代器
    Spliterator是Java8新增的一种迭代器,这种迭代器由Spliterator接口定义,Spliterator也有普通的遍历元素功能,这一点与刚才说的迭代器类似的,但是,但是Spliterator方法和使用迭代器的方法是不同的。

    List<HeroPlayerGold> lists = new ArrayList();
        lists. add(new HeroPlayerGold("盖伦","RNG-Letme",100));
        lists.add(new HeroPlayerGold("诸葛亮","RNG-Xiaohu", 300));
        lists.add(new HeroPlayerGold("露娜","RNG-MLXG", 300));
        lists.add(new HeroPlayerGold("狄仁杰","RNG-UZl", 500));
        lists.add(new HeroPlayerGold("牛头","RNG-Ming", 500));
        lists.stream().spliterator().forEachRemaining(hp -> {
            if (hp.getGold() >= 300) System.out.println(hp.getHero());
        });
        System.out.println("---------------------------");
        Spliterator<HeroPlayerGold> spliterator = lists.stream().spliterator();
        Spliterator<HeroPlayerGold> s = spliterator.trySplit();
        if (s != null ){
            s.forEachRemaining(System.out :: println);
        }
        System.out.println("---------------------------");
        spliterator.forEachRemaining(System.out  :: println);
    

    显示结果:

    诸葛亮
    露娜
    狄仁杰
    牛头
    ---------------------------
    HeroPlayerGold{hero='盖伦', player='RNG-Letme', gold=100}
    HeroPlayerGold{hero='诸葛亮', player='RNG-Xiaohu', gold=300}
    ---------------------------
    HeroPlayerGold{hero='露娜', player='RNG-MLXG', gold=300}
    HeroPlayerGold{hero='狄仁杰', player='RNG-UZl', gold=500}
    HeroPlayerGold{hero='牛头', player='RNG-Ming', gold=500}
    

    Spliterator的另一个值得注意的方法是trySplit(),它将被迭代的元素划分成了两部分,返回其中一部分的新Spliterator,另一部分则通过原来的Spliterator访问。

  7. 创建 Stream 的10方式
    1、Stream.of 可变参数

    Stream<String> stream1 = Stream.of("A", "B", "C");
    System.out.println("stream1:" + stream1.collect(joining()));
    

    程序输出:

    stream1:ABC

    2、Stream.of 数组

    String[] values = new String[]{"A", "B", "C"};
    Stream<String> stream2 = Stream.of(values);
    System.out.println("stream2:" + stream2.collect(joining()));
    

    程序输出:

    stream2:ABC

    看 Stream.of 源码,上面这两种方式其实就是第三种方式的包装版。

    public static<T> Stream<T> of(T... values) {
        return Arrays.stream(values);
    }
    

    我们直接使用源码中的方式也是一样的。

    3、Arrays.stream

    String[] values = new String[]{"A", "B", "C"};
    Stream<String> stream3 = Arrays.stream(values);
    System.out.println("stream3:" + stream3.collect(joining()));
    

    程序输出:

    stream3:ABC

    4、List

    List<String> list = Arrays.asList("A", "B", "C");
    Stream<String> stream4 = list.stream();
    System.out.println("stream4:" + stream4.collect(joining()));
    

    程序输出:

    stream4:ABC

    5、Set

    Set<String> set = new HashSet<>(Arrays.asList("A", "B", "C"));
    Stream<String> stream5 = set.stream();
    System.out.println("stream5:" + stream5.collect(joining()));
    

    程序输出:

    stream5:ABC

    6、Map

    Map<String, String> map = new HashMap<>();
    map.put("1", "A");
    map.put("2", "B");
    map.put("3", "C");
    Stream<String> stream6 = map.values().stream();
    System.out.println("stream6:" + stream6.collect(joining()));
    

    程序输出:

    stream6:ABC

    7、Stream.iterate

    Stream<String> stream7 = Stream.iterate("A", e -> String.valueOf((char) (e.charAt(0) + 1))).limit(3);
    System.out.println("stream7:" + stream7.collect(joining()));
    

    程序输出:

    stream7:ABC

    8、Pattern

    String value = "A B C";
    Stream<String> stream8 = Pattern.compile("\\W").splitAsStream(value);
    System.out.println("stream8:" + stream8.collect(joining()));
    

    程序输出:

    stream8:ABC

    9、Files.lines

    try {
        Stream<String> stream9 = Files.lines(Paths.get("d:/data.txt"));
        System.out.println("stream9:" + stream9.collect(joining()));
    } catch (IOException e) {
        e.printStackTrace();
    }
    data.txt文件内容如下:
    
    A
    B
    C
    

    程序输出:

    stream9:ABC

    10、Stream.generate

    Stream<String> stream10 = Stream.generate(() -> "A").limit(3);
    System.out.println("stream10:" + stream10.collect(joining()));
    

    程序输出:

    stream10:AAA

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值