Lambda Expression

  今天,朋友发了一张截图,将80多行的代码优化为5行,看着超级清爽,而且也很清晰,而对于我来说,好像没用过这么多函数连续调用,因此写这篇博客增加一点自己的认知。

 

  Lambda Expression( λ表达式 / 匿名函数 )

    目前java 12 都出来了,而我竟然连java 8 中的东西没使用完全,有点尴尬呀...    唉,都是不努力造成的结果呀,继续学吧,毕竟按java目前的更新速度,应该是学不动了,更尴尬呀,有木有!!!

 

  Java 8 是继 Java 5 之后的最重要的发布版本,包含了很多特性,简化开发,编译函数式接口代替匿名类,使代码更具可读性。其中最终要的一点就是lambda expression

  lambda expression 是自 Java 添加 泛型(Generics) 和 注解(annotation) 以来最大的变化。

 

  lambda可以看作为一个简洁可传递的匿名函数,属于“语法糖”系列,不属于特定的类,但是具备参数列表、函数主体、返回类型、甚至可以抛异常等,其次它是匿名的,没有具体的函数名称,可以像参数一样传递,简化代码的编写(参考lambda表达式)。

  注:语法糖指的是方便开发,提升效率的的,对现有语法进行的封装,如 Java 中有自动拆装箱、泛型、变长参数、增强for循环、内部类、枚举、lambda式等。

  其隐含了return关键字,具体格式定义为如下:

    ①、参数列表 -> 表达式;        ②、参数列表 -> { 表达式集合 }

  

   好了,以上介绍就先到这儿,接下来就是见证 lambda 真正强大的地方了,也就是如何使用呐?不然还说个毛线呀...

 

   Lambda表达式应用

   1、stream介绍

      使用 lambda 表达式,首先要将其转换为流(Stream / 与文件流一点关系都没有),是一种声明式的数据处理方式,以直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

    这种处理方式需要将处理数据集合看作一种流, 流是数据演变序列,其在管道中传输, 并且可以在管道的节点上进行处理数据源(集合/数组)生成的序列,其计算处理动作有筛选, 排序,聚合等。

    可以说"    集合讲的是数据,流讲的是计算   "

    元素流在管道中经过 中间操作(intermediate operation)的处理,最后由 最终操作(terminal operation)得到前面处理的结果。(参考Java 8 Stream

   
    流介绍:

      不同于文件传输方面的 IO 流,此处的流(Stream)是指将数据进行包装后,使用 懒(Lazy)运算 与 链式语法 进行得到函数执行后的最终结果,包含诸多高阶函数语法,如filter、map、match、sorted等。

     Stream的特性:    · 不会存储数据         ·  类似于subList,不会改变源数据         ·  延迟执行

     通常情况下,都是在数组 / 集合的基础上常见Stream,且Stream不会存储数据,也不影响源数据,且对Stream的集合、消费、收集操作只进行一次,再次操作会异常(java.lang.IllegalStateException: Stream has already been operated or closed)。

   需要注意的是,对于基本数值型,目前有三种对应的包装类型 Stream:
    IntStream、LongStream、DoubleStream。当然我们也可以用 Stream<Integer>、Stream<Long> >、Stream<Double>,但是 boxing 和 unboxing 会很耗时,所以特别为这三种基本数值型提供了对应的 Stream。

    彩蛋: ...   ...

    一篇写到五一了,也是没谁了,反正五一去玩了,跟几个朋友去舟山桃花岛,怎么说呢?一路的行程有点无奈,反正是遇到各种坑,嘻嘻嘻~~~,没事,一个正宗的北方汉子,本次也是看见大海了,挺好玩的的,照片么,就不传了,五一快乐!

   2、创建Stream

    a. 创建空的流

      Stream<Integer> stream = Stream.empty();

    b. 数组创建流

      Object[] arr = new Object[] { "A", 66, 0.01, 'a' };

      Stream<Object> stream1 = Arrays.stream(arr);

      Stream<Object> stream2 = Stream.of(arr);

    c. 集合创建流

      List<Object> list = Arrays.asList( "A", 66, 0.01, 'a' );

      Stream<Object> stream1  = list.stream();      //  创建普通流

      Stream<Object> stream2  = strs.parallelStream();  // 创建并行流

    d. 创建无限流

      // 迭代

        Stream<Integer> stream = Stream.iterate(0,(x) -> x+ 2);
        Stream.limit(10).forEach(System.out::println)
      // 生成
        Stream.generate(()->Math.random()).forEach(System.out::println);

    e. 基本数据类型相关流

       java8提供了一些特殊种类的流,用于处理基本数据类型int,long,double。分别为IntStream,LongStream,DoubleStream

 

    前四种方式创建的数据流称为“对象数据流”,第五种方式创建的流称为“基本数据流”,基本数据流和对象数据流用法相似,但有一些不同,基本数据流使用的是特殊的lambda表达式,如:IntFunction而不是Function,IntPredicate而不是Predicate。同时基本数据流还支持一些额外的聚合终止操作sum()和average()等。有些时候需要进行对象数据流和基本数据流的转换,如mapToInt、MapToObj ...

 

  3、中间衔接

    由于Stream的 延迟执行/惰性求值 特性,因此中间衔接操作除非遇到终止操作指令之前,是不会执行任何处理动作,若遇到终止操作指令时,才一次性全部处理完成达到结果。

     a. 筛选与切片

      filter:过滤流,过滤排除掉流中的某些元素

        Arrays.stream( new int[] { 1,3,5,7,8,9 } ).filter( i-> i > 3 && i < 8 ).forEach( System.out::println );

      distinct:筛选,通过流所生成元素的hashCode()和equals()去除重复元素

        Arrays.stream( new int[] { 1,3,3,7,7,9 } ).distinct().forEach( System.out::println );

      limit:截取前几条记录

        Arrays.stream( new int[] { 1,3,3,7,7,9 } ).limit( 3 ).forEach( System.out::println );

      skip:跳过前几条记录    

         Arrays.stream( new int[] { 1,3,3,7,7,9 } ).skip( 4 ).forEach( System.out::println );

    b. 映射

       map:将元素转换成其他形式或提取信息。也可以接收一个函数操作参数,该函数会应用到每个元素上,并将其映射成一个新的元素。

        Arrays.stream( new int[] { 1,3,3,7,7,9 } ).map( i -> i * i ).forEach( System.out::println );
      flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流链接成一个流,即扁平化,将高纬度转换为低纬度

        Arrays.stream( new int[] { { 1,3,3,7,7,9 }{ 2,4,0 }{ 5,6,7,8 } } ).flatmap( Arrays::stream ).forEach( System.out::println );

    c. 排序

       sorted():无参为自然排序,有参可自定义排序方式

        Arrays.stream( new int[] { 8,3,1,7,6,0 } ).sorted().forEach( System.out::println );

        Arrays.stream( new Integer[] { 8,3,1,7,6,0 } ).sorted(Comparator.comparing(Integer::byteValue).reversed()).forEach( System.out::println );

  4、终止操作

    a. 查找与匹配  

      max/min:流中的最大/小值

        Arrays.stream( new int[] { 8,3,1,7,6,0 } ).max();

      count:流中元素的总个数

        Arrays.stream( new int[] { 8,3,1,7,6,0 } ).count();

      findFirst/findAny:流中元素的首个/任意元素

         Arrays.stream( new int[] { 8,3,1,7,6,0 } ).findFirst(); 

      allMatch/anyMatch/noneMatch:完全/部分/不 匹配元素

        ... ...

    b. 结果收集

      collect:将流转换为其他形式。

              接收一个Collector接口的实现,用于给Stream中元素做汇总的方法,将流中的元素存放在不同类型的结果中。Java8通过内置的 Collectors 类支持多种内置的收集器。

        Arrays.stream( new int[] { 1,3,3,7,7,9 } ).collect( Collectors.toList() )

    c. 规约:这类的结果会将流归为一个值,用函数式编程语言的术语来说,这称为折叠(fold)

       ruduce(T identity,BinaryOperator) / ruduce(BinaryOperator):可以将流中元素反复结合起来,组合为单一结果。

         Arrays.stream( new int[] { 1,3,3,7,7,9 } ).reduce(0, Integer::sum);

  实际使用

    待补充...

 

  参考文档链接:

    https://blog.csdn.net/lidai352710967/article/details/82496783

    https://blog.csdn.net/zhwyj1019/article/details/80585245

    https://blog.csdn.net/qmqm011/article/details/82964876

 

 

   (愿你的每一行代码,都有让世界进步的力量    ------   fn)

posted @ 2019-04-19 21:29  fn-f  阅读(228)  评论(0编辑  收藏  举报