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的操作
当我们使用一个流的时候,通常包括三个基本步骤:获取数据源->数据转换->获取结果/产生影响
获取数据源
- 从 Collection 和数组 Collection.stream(),Collection.parallelStream(),Arrays.stream(T array) or Stream.of()
- BufferedReader java.io.BufferedReader.lines()
- 静态工厂 java.util.stream.IntStream.range() ,java.nio.file.Files.walk()
- 自己构建 ,实现java.util.Spliterator
- 其它 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