JAVA流式编程

       

        前言:

        java8中有两大最为重要的改变。第一个是Lambda 表达式;另外一个则是Stream API(java.util.stream.*)。Stream 是Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL 执行的数据库查询。也可以使用Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。如果你之前接触过scala语言及spark,或是其他的大数据计算引擎,那么理解java流式编程相容易,思路相同,但是java流程编程还不够完善,处理并行计算远没有spark那么成熟,如果你没接触过可能对流程编程理解相对困难一些。

 

目录

    一、什么是Stream

   二、Stream 操作三步骤

       2.1、创建Stream

    2.1.1、Java8 中的Collection 接口被扩展,提供了两个获取流的方法:

    2.1.2、由数组创建流

    2.1.3、由值创建流

    2.1.4、由函数创建流:创建无限流可以使用静态方法Stream.iterate() 和Stream.generate(), 创建无限流。

   2.2、Stream 的中间操作

   2.3、Stream 的终止操作

三、并行流与串行流

四、小结


    一、什么是Stream

       Stream是数据渠道,用于操作数据源(集合,数组,文件,正则表达式模式匹配器,伪随机数生成器和其他流等)所生成的元素序列,流中的数据元素可以是对象引用或基本类型。支持三种基本类型:int,long和double。并且有串行、并行两种执行模式,并行模式充分的利用了多核处理器的优势,使用fork/join框架进行了任务拆分,同时提高了执行速度。

      对fork/join框架有兴趣的请阅读https://blog.csdn.net/heijunwei/article/details/113176074

      集合是存储数据,而流是计算集合中的数据。

  • 特点:
  1. Stream自己不会存储元素。
  2. Stream的操作不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  3. Stream 操作是延迟执行的。它会等到需要结果的时候才执行。也就是执行终端操作的时候。

 

   二、Stream 操作三步骤

  •   创建Stream

          一个数据源(如:集合、数组),获取一个流

  •   中间操作

         一个中间操作链,对数据源的数据进行处理

  • 终止操作(终端操作)

        一个终止操作,执行中间操作链,并产生结果

    

   

       2.1、创建Stream

       2.1.1、Java8 中的Collection 接口被扩展,提供了两个获取流的方法:

  • default Stream<E> stream() : 返回一个顺序流;
  • default Stream<E> parallelStream() : 返回一个并行流;

       2.1.2、由数组创建流

      Java8 中的Arrays 的静态方法stream() 可以获取数组流:
      static <T> Stream<T> stream(T[] array): 返回一个流
      重载形式,能够处理对应基本类型的数组:

  •  public static IntStream stream(int[] array)
  •  public static LongStream stream(long[] array)
  •  public static DoubleStream stream(double[] array)

    2.1.3、由值创建流

    可以使用静态方法Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。
     public static<T> Stream<T> of(T... values) : 返回一个流

    2.1.4、由函数创建流:创建无限流可以使用静态方法Stream.iterate() 和Stream.generate(), 创建无限流。

  •   迭代:public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) 
  •   生成:public static<T> Stream<T> generate(Supplier<T> s) : 

   2.2、Stream 的中间操作

     多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

     

类别方法描述
筛选与切片filter(Predicatep)接收Lambda ,从流中排除某些元素。
distinct()筛选,通过流所生成元素的hashCode
除重复元素
limit(long maxSize)截断流,使其元素不超过给定数量。
skip(long n)跳过元素,返回一个扔掉了前n 个元素的流。若流中元素
不足n 个,则返回一个空流。与limit(n) 互补
映射map(Functionf)接收一个函数作为参数,该函数会被应用到每个元
素上,并将其映射成一个新的元素。
mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每素上,产生一个新的DoubleStream。
mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。
mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream。
flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
排序sorted()产生一个新流,其中按自然顺序排序
sorted(Comparatorcomp)产生一个新流,其中按比较器顺序排序

   2.3、Stream 的终止操作

      终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void 。

       

类别方法描述
查找与匹配allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicatep)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素总数
max(Comparatorc)返回流中最大值
min(Comparatorc)返回流中最小值
forEach(Consumerc)内部迭代(使用Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
归约reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来得到一个值。                                           返回T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。
返回Optional<T>
收集collect(Collector c)将流转换为其他形式。接收一个Collector接口的
实现,用于给Stream中元素做汇总的方法,Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例
 toList把流中元素收集到List 。返回List<T> 
                                                            List<Employee>emps=list.stream().collect(Collectors.toList());
 toSet把流中元素收集到Set。返回Set<T>
 Set<Employee>emps=list.stream().collect(Collectors.toSet());
 toCollection把流中元素收集到创建的集合。返回Collection<T>
 Collection<Employee>emps=list.stream().collect(Collectors.toCollection(ArrayList::new));
 counting计算流中元素的个数。返回 Long
 long count=list.stream().collect(Collectors.counting());
 summingInt对流中元素的整数属性求和。返回 nteger
 int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
 averagingInt计算流中元素Integer属性的平均值。返回Double
 double avg=list.stream().collect(Collectors.averagingInt(Employee::getSalary));
 summarizingInt收集流中Integer属性的统计值。如:平均值。                                    返回类型IntSummaryStatistics
 IntSummaryStatisticsiss=list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
 joining连接流中每个字符串,返回String
 Stringstr=list.stream().map(Employee::getName).collect(Collectors.joining());
 maxBy根据比较器选择最大值 。返回Optional<T>
 Optional<Emp>max=list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
 minBy根据比较器选择最小值。返回Optional<T>
 Optional<Emp>min=list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
 reducing 从一个作为累加器的初始值开始,利用BinaryOperator与
流中元素逐个结合,从而归约成单个值。返回归约产生的类型
 int total=list.stream().collect(Collectors.reducing(0,Employee::getSalar,Integer::sum));
 collectingAndThen包裹另一个收集器,对其结果转换函数。返回转换函数返回的类型
 int how=list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size));
 groupingBy根据某属性值对流分组,属性为K,结果为V。返回Map<K,List<T>>
 Map<Emp.Status, List<Emp>> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));
 partitioningBy根据true或false进行分区 。返回Map<Boolean,List<T>>
 Map<Boolean,List<Emp>>vd=list.stream().collect(Collectors.partitioningBy(Employee::getManage));

三、并行流与串行流

        并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过parallel() 与sequential() 在并行流与顺序流之间进行切换。

 

四、小结

  • 有些任务最好使用流来完成,有些任务最好使用迭代来完成。将这两种方法结合起来,可以最好地完成许多任务。对于选择使用哪种方法进行任务,没有硬性规定,但是有一些有用的启发式方法。在许多情况下,使用哪种方法将是清楚的;在某些情况下,则不会很清楚。如果不确定一个任务是通过流还是迭代更好地完成,那么尝试这两种方法,看看哪一种效果更好。
  • 编程流管道的本质是无副作用的函数对象。这适用于传递给流和相关对象的所有许多函数对象。终结操作forEach仅应用于报告流执行的计算结果,而不是用于执行计算。为了正确使用流,必须了解收集器。最重要的收集器工厂是toList,toSet,toMap,groupingBy和join。
  • 在编写返回元素序列的方法时,请记住,某些用户可能希望将它们作为流处理,而其他用户可能希望迭代方式来处理它们。尽量适应两个群体。如果返回集合是可行的,请执行此操作。如果已经拥有集合中的元素,或者序列中的元素数量足够小,可以创建一个新的元素,那么返回一个标准集合,比如ArrayList。否则,请考虑实现自定义集合,就像我们为幂集程序里所做的那样。如果返回集合是不可行的,则返回流或可迭代的,无论哪个看起来更自然。如果在将来的Java版本中,Stream接口声明被修改为继承Iterable,那么应该随意返回流,因为它们将允许流和迭代处理。
  • 甚至不要尝试并行化流管道,除非你有充分的理由相信它将保持计算的正确性并提高其速度。不恰当地并行化流的代价可能是程序失败或性能灾难。如果您认为并行性是合理的,那么请确保您的代码在并行运行时保持正确,并在实际情况下进行仔细的性能度量。如果您的代码是正确的,并且这些实验证实了您对性能提高的怀疑,那么并且只有这样才能在生产代码中并行化流。

  

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值