Lambda表达式

简介:

Lambda简介

Lambda表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。 
函数式接口:接口中有且只有一个抽象方法并且在类上增加了@FunctionalInterface 注解,则表示该类是接口函数.只要接口只包含一个方法的接口,虚拟机会自动判断,不过最好在接口上使用注解 @FunctionalInterface 进行声明。 
语法:

  • (参数...)->执行内容 
    执行内容可以是多行,多行则需要{}括起来,如函数接口有返回值则需要手动return
  • 双冒号(::) 
    双冒号(::)操作符是 Java 中的方法引用。 当们使用一个方法的引用时,目标引用放在 :: 之前,目标引用提供的方法名称放在 :: 之后,即 目标引用::方法. 
    通常对应了Function T为目标对象,R为返回结果 
    使用了lambda表达式后可以简化绝大多数接口函数类型的操作代码,例如事件处理,线程初始化

Stream简介

Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。 
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。 
而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。

Stream的操作

当我们使用一个流的时候,通常包括三个基本步骤:获取数据源->数据转换->获取结果/产生影响

获取数据源

  1. 从 Collection 和数组 Collection.stream(),Collection.parallelStream(),Arrays.stream(T array) or Stream.of()
  2. BufferedReader java.io.BufferedReader.lines()
  3. 静态工厂 java.util.stream.IntStream.range() ,java.nio.file.Files.walk()
  4. 自己构建 ,实现java.util.Spliterator
  5. 其它 Random.ints(),BitSet.stream(),Pattern.splitAsStream(java.lang.CharSequence), JarFile.stream()

数据操作/获得结果:

Intermediate:中间操作

操作完之后会返回一个新的流,需注意的是这些操作都是lazy的,只有执行重点操作时才会将所有操作整合一起执行. 
注意:

  • 已下示例没有终点操作,所以不会改变流内容仅做示例,不能执行.
  • 方法对应的大多都为函数接口,可以抽离出来反复使用
  • 中间操作都会返回流,而不是具体的结果
方法 简介 示例 说明
map等 将流内容映射为另外一种类型 List output = wordList.stream().map(String::toUpperCase) 将字符串内容全部转换为大写
flatMap 将处理后的stream聚合为一个stream Stream.of("one","two").flatMap(s->s.stream()) 将流内容变为onetwo
filter 过滤流 List output = wordList.stream().filter(n -> n.startsWith("a")) 仅保留已a开始的字符串
distinct 字面意思理解即可 List output = wordList.stream().distinct() 去重
sorted 对流内容排序 List output = userList.stream().sorted((p1, p2) -> p1.getName().compareTo(p2.getName())) 可以在此处实现Comparator接口,或对象本身实现了Comparator接口
peek 将流内容循环自定处理但不是终点操作, List output = wordList.stream().peek(System.out::plintln) 注1
limit/skip 取流中前n个数据,去除前n个数据 List output = wordList.stream().limit(2) 取前2个对象组装为一个新的流
parallel/sequential 将流转换为并行流/将流转换为串行流 List output = wordList.stream().parallel 并行流多线程处理数据,对多核cpu性能显著提升
  • 注1:peek没有返回值如改变的是对象则会改变对象内容,如果改变的是原始数据类型则不会产生效果,示例
  List<StringBuffer> sbs = new ArrayList<>();
  sbs.add(new StringBuffer("one"));
  sbs.add(new StringBuffer("two"));
  sbs.stream().peek(s -> s.append("-MeiJM ")).forEach(System.out::print);
//打印内容为one-MeiJM tow-MeiJM
Stream.of("one", "two").peek(s ->s+"-MeiJM ").forEach(System.out::print);
//打印内容为one two

Terminal:终点操作,

一个流只能有一个终点操作,只有当执行终点操作时才会真正执行所有中间操作并产生一个结果,或者对数据产生影响.

方法 简介 示例 说明
forEach/forEachOrdered 并行处理流数据/串行处理流数据 List output = wordList.stream().forEach(System.out::print) 循环打印内容,多线程处理结果无序,使用forEachOrdered则是有序处理
toArray 将流转换为数组对象 Integer[] arr =Stream.of(1, 2).toArray(Integer[]::new) 数值类型的流转换为数组对象,其他类型
reduce(T identity, BinaryOperator accumulator) 已identity为初始值进行操作,并将操作的结果返回 Integer sum = integers.reduce(100, Integer::sum); 返回的是integers的sum+100
reduce(BinaryOperator accumulator) 没有初始值进行操作 Optional temp = Stream.of(1, 2,3,4).reduce((a,b)->a-b); 返回的是integers累减结果-8
reduce(U identity,BiFunction accumulator,BinaryOperator combiner); 并发操作,我也不理解,可以参考一下后面的资料 ... 详情1详情2
collect 将结果聚合并进行处理将处理后的结果返回 Stream.of(1, 2, 3, 4).collect(Collectors.toList()) 将流转换为List注2
min/max 取最小值最大值 Stream.of(1, 2, 3, 4).min() 取最小值,此处可手动实现Comparator接口
count 将流中元素计数 Stream.of(1, 2, 3, 4).count() 输出为4
allMatch Stream 中全部元素符合传入的 predicate,返回 true Stream.of(1, 2, 3, 4).allMatch(i -> i>0) Stream中所有元素都大于0则返回true
anyMatch Stream 中有元素符合传入的 predicate,返回 true Stream.of(1, 2, 3, 4).anyMatch(i -> i>3) Stream中有元素大于3则返回true
noneMatch Stream 中没有元素符合传入的 predicate,返回 true Stream.of(1, 2, 3, 4).noneMatch(i -> i>5) Stream中没有元素大50则返回true
findFirst 返回Stream中第一个元素 Stream.of(1,2).findFirst() 返回1
findAny 配合parallel使用,返回任意一个流内容 Stream.of(1,2).parallel().findFirst() 返回随机一个值
iterator 将流内容映射为Iterator Stream.of(1,2).iterator() 将流转换为Iterator
  • 注2:Collectors中封装了常用的处理方法,常用的方法:
    • Collectors.toMap(a -> a.getCatalogNumber(), a -> a) 结果映射为map类型,类似的还有toList,toSet
    • Collectors.groupingBy(Person::getAge) 结果使用age分组并返回Map
    • Collectors.partitioningBy(o -> o.startsWith("a")) 结果封装为Map符合条件的为一组不符合条件的为另一组

Short-circuiting:

可以理解为限制入口或者限制出口,其中包含了Intermediate,也包含了Terminal. 
对应的操作:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

使用问题记录

  • 按照多个属性进行分组,Collectors.groupingBy(x -> Arrays.asList(x.getA(),x.getB()))stackoverflow

日常学习记录,欢迎交流。

参考资料 
https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/index.html 
https://segmentfault.com/a/1190000009186509 
https://blog.csdn.net/u011001723/article/details/52794455 
https://segmentfault.com/q/1010000004944450 
https://segmentfault.com/a/1190000008184585 
https://blog.csdn.net/io_field/article/details/54971608 
https://www.cnblogs.com/GYoungBean/p/4301557.html

目录
相关文章
|
5月前
|
Java
Lambda表达式
Lambda表达式是JDK8后的一种新语法形式 Lambda表达式只能简化函数式接口的匿名内部类的写法形式 演示:先创建应该抽象类 使用Lambda表达式抽象简化匿名内部类,转换类型必须是接口 把Animal类改成接口 此时已经编译正常,并且对对象a进行了简化 首先必须是接口,其次接口中只能有一个抽象方法函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是 Lambda,所以函数式接口就是可以适用于Lambda使用的接口 总结 有时我们需要在程序的某处使用
33 1
|
16天前
|
编译器 C语言 C++
C++ lambda表达式
C++ lambda表达式
|
18天前
|
Java
lambda表达式详解
lambda表达式详解
|
7月前
|
Java 编译器 C#
C#中的Lambda表达式
C#中的Lambda表达式
44 0
|
3月前
|
算法 编译器
C++11(lambda表达式)
C++11(lambda表达式)
30 0
|
8月前
|
编译器 C++
【C++】Lambda表达式的使用
【C++】Lambda表达式的使用
61 0
|
6月前
|
算法 编译器
C++11 lambda表达式(下)
C++11 lambda表达式(下)
61 2
|
6月前
|
算法 搜索推荐 编译器
C++11:lambda表达式
C++11:lambda表达式
25 0
|
10月前
|
存储 算法 编译器
lambda表达式的介绍
lambda表达式的介绍
80 0
|
10月前
|
Java
浅谈lambda表达式
浅谈lambda表达式
38 0