zoukankan      html  css  js  c++  java
  • jdk8新特性-stream

    一、什么是流stream

    1.可理解为高级版本的 Iterator

      不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的。

    2.单向,不可往复

      数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。

    3.可并行化操作

      迭代器:只能命令式地、串行化操作。当使用串行方式去遍历时,每个 item 读完后再读下一个 item。和迭代器不同,stream使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。

    4.数据源本身可以是无限的

    二、流的构成 

    1.构成的三个步骤

    a.获取一个数据源(source)

    b.数据转换

    c.执行操作获取想要的结果。<每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道>。如下图所示:

    eg:Student<id, name>
    
      List<Student> students = Lists.newArrayList(new Student(1, "学生1"), new Student(2, "学生2"), new Student(3, "学生3"));  ---  Source
    
      Stream<Student> studentStream = students.stream();  ---  Stream
    
      Stream<Long> idStream = studentStream.map(student -> student.getId);  ---  Transforming
    
      List<Long> ids = idStream.collect(Collectors.toList());  ---  Operations

    三、流的常见3种方法

    • Collection.stream()
    • Collection.parallelStream()
    • Arrays.stream(T array) or Stream.of()
    • Stream.generate(Supplier<T> s)。<创建无限流,不常用>
    // 1. Individual values
    Stream stream = Stream.of("a", "b", "c");
    // 2. Arrays
    String [] strArray = new String[] {"a", "b", "c"};
    stream = Stream.of(strArray);
    stream = Arrays.stream(strArray);
    // 3. Collections
    List<String> list = Arrays.asList(strArray);
    stream = list.stream();

     四、基本类型的流的构造

    三种对应的包装类型 Stream。

    IntStream、LongStream、DoubleStream  

    或者   

    Stream<Integer>、Stream<Long>、Stream<Double>

    eg:
    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);

      

    五、流转换为其它数据结构

    // 1. Array
    String[] strArray1 = stream.toArray(String[]::new);
    // 2. Collection
    List<String> list1 = stream.collect(Collectors.toList());
    List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
    Set set1 = stream.collect(Collectors.toSet());
    Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
    // 3. String
    String str = stream.collect(Collectors.joining()).toString();

    六、流的操作

    • Intermediate:

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

    • Terminal:

    forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

    • Short-circuiting:

    anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

    七、典型用法

    
    

    1.map:

    map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。作用:对流中的每一个元素进行操作。

    1. 转换大写
    List<String> output = wordList.stream().
    map(String::toUpperCase).
    collect(Collectors.toList());
    说明:这段代码把每个单词转换为大写。

    2. 平方数
    List<Integer> nums = Arrays.asList(1, 2, 3, 4);
    List<Integer> squareNums = nums.stream().
    map(n -> n * n).
    collect(Collectors.toList());

    
    


    2.filter:
    注意:这里要注意的是“过滤出”,而不是“过滤”,这是两个不同的意思!
    1.留下偶数
    Integer[] sixNums = {1, 2, 3, 4, 5, 6};
    Integer[] evens = Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new);
    注意:stream也是可以foreach的,没必要一定要转化成集合再foreach

    3.forEach

    作用:对stream中的每一个元素做聚合操作。

      List<Integer> numbers = Lists.newArrayList(1, 2, 3, 4);

    System.out.println(numbers.stream().mapToInt(Integer::intValue).sum()); --输出10

    4.reduce

    作用:对stream中的每一个元素做聚合操作。
    Stream<Integer> reduceStream = Stream.of(1,2,3,4,5);
    Optional<Integer> sumOption = reduceStream.reduce((x,y)->x+y);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算(注意:如果stream为null的话,就会产生无效的结果,需要使用Optional接收)
    //Optional<Integer> sumOption = reduceStream.reduce(Integer::sum);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算
    Integer result = reduceStream.reduce(0, Integer::sum);//0为标识值,即计算:0+1+2+。。+5,如果整个stream为null,就返回标识值。
    System.out.println(result);
    注意:以上是reduce的简单形式,即内联函数是(T,T)->T,即返回值和参数类型是一样的,返回值和参数类型不同的场景需要自己编写函数(用的较少)


    5、Optional两种用法:
    ifPresent(xxx):存在的就执行xxx,不存在就什么都不执行
    orElse(xxx):存在就返回存在的值,不存在就返回xxx(可以理解为是默认值)
    Stream<String> optionalStream = Stream.of("java","python","basic");
    Optional<String> optionValue = optionalStream.filter(str->str.startsWith("p")).findFirst();
    optionValue.ifPresent(str->System.out.println(str));//if optionalValue为true,即str存在,则输出str,当然也可以使用如下
    String str = optionValue.orElse("xxx");//如果optionValue为false,即不存在以p开头的字符串时,使用"xxx"来替代
    System.out.println(str);
    5、limit skip contact1、limit(long size)作用:截取stream的前size个元素。
    Stream<String> streamSelf = Stream.of("python","basic","php");
    streamSelf.limit(2).forEach(System.out::println);//截取前两个
    2、skip(long size)作用:跳过stream的钱size个元素
    Stream<String> streamSelf = Stream.of("python","basic","php");
    streamSelf.skip(2).forEach(System.out::println);//跳过前两个
    3、contact(Stream<T>,Stream<T>)作用:拼接两个stream
    Stream<String> streamSelf = Stream.of("python","basic","php");
    Stream<String> streamSelf2 = Stream.of("python2","basic2","php2");
    Stream.concat(streamSelf, streamSelf2).forEach(System.out::println);


    6.聚合函数

    count max min findFirst findAny anyMatch allMatch noneMatch
    Stream<String> streamSelf = Stream.of("python","basic","php","b");
    System.out.println(streamSelf.count());//计算流中的元素个数
    Optional<String> largest = streamSelf.max(String::compareToIgnoreCase);//寻找最大值
    if(largest.isPresent()){
    System.out.println(largest.get());
    }
    说明:min函数也一样。注意:Optional的使用,上边的是最差的一种形式,见"六"。
    Optional<String> firstMatch = streamSelf.filter(str->str.startsWith("b")).findFirst();//寻找第一个符合条件的元素
    firstMatch.ifPresent(System.out::println);//这是Optional的第一种用法
    Optional<String> anyMatch = streamSelf.parallel().filter(str->str.startsWith("b")).findAny();//返回集合中符合条件的任意一个元素,对于并行处理非常好(因为多个线程只要有一个线程找到了,整个计算就会结束)
    if(anyMatch.isPresent()){
    System.out.println(anyMatch.get());//这里的结果可能是b,有可能是basic
    }

    boolean isAnyMatch = streamSelf.parallel().anyMatch(str->str.startsWith("c"));//集合中是否有一个满足条件
    System.out.println(isAnyMatch);
    Stream<String> streamSelf3 = Stream.of("basic","b");
    boolean isAllMatch = streamSelf3.parallel().allMatch(str->str.startsWith("b"));//集合中是否所有元素都满足条件
    System.out.println(isAllMatch);
    boolean isAllNotMatch = streamSelf.parallel().noneMatch(str->str.startsWith("p"));//集合中是否没有一个元素满足条件
    System.out.println(isAllNotMatch);
    注意:
    optional的最佳用法:ifPresent()-->如果有就输出,如果没有,什么都不做
    parallel():将stream转为并行流,并行流的使用一定要注意线程安全

     

     七、java8 :: 用法 (JDK8 双冒号用法)

     就是把方法当做参数传到stream内部,使stream的每个元素都传入到该方法里面执行一下。

    尽量用::去代替->,培养良好的代码习惯。

    双冒号运算就是Java中的[方法引用],[方法引用]的格式是:

    类名::方法名 
    注意,没有()号。

    案例:

    使用前:
    person -> person.getAge();
    使用双冒号后:
    Person::getAge
    
    使用前:
    new HashMap<>()
    使用双冒号后: 
    HsahMap :: new
    
    使用前:
     MyTest.printValur(x));
    使用双冒号后: 
    MyTest :: printValur 

    参考链接

    Streams API详解

    https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

    Stream API

    https://www.cnblogs.com/sunny3096/p/7159521.html

    菜鸟码农,喜欢和谦虚爱学习积极向上的同学做朋友,请留言多指教。
  • 相关阅读:
    170516、ActiveMQ 的安装与使用(单节点)
    170515、mybatis批量操作
    170512、java日志文件log4j.properties配置详解
    170511、Spring IOC和AOP 原理彻底搞懂
    170510、数据库默认隔离级别
    170509、文本编辑器编写的shell脚本在linux下无法执行的解决方法
    170508、忘记jenkins密码或者修改jenkins密码
    170505、MySQL的or/in/union与索引优化
    170504、MongoDB和MySQL对比(译)
    Jenkins Android 打包
  • 原文地址:https://www.cnblogs.com/luoliuniankk/p/9946567.html
Copyright © 2011-2022 走看看