java8实战学习

[toc]
java8实战学习 1. lambda表达式
1.1 什么是lambda表达式 1.2 什么样的场景能使用lambda表达式 1.3 lambda表达式实现一个接口的四种写法 2. 函数式编程
2.1 什么是函数式编程 2.2 什么是命令式编程 2.3 什么是函数式接口 FunctionalInterface 2.4 什么是 default 方法 2.5 default方法的意义 2.6 java8内置的常用函数式接口 (1). Predicate 断言 -> 输入T, 输出 boolean
(2). Consumer 消费一个输入 -> 输入T, 不输出(void)
(3). Supplier 生产一个输出 -> 不输入, 输出T
(4). Function 输入T, 输出R的函数
(5). UnaryOperator 一元函数: 输入1个输出 1个: 类型都是T
(6). BinaryOperatior 二元函数: 输入2个输出1个: 类型都是T
(7). BiFunction 输入两个输出一个: 输入 T, U 输出 R, 常用于 reduce/sort等操作,
2.7 方法引用 (1). 静态方法的方法引用 (2). 实例方法的方法引用 (3). 构造方法的方法引用 2.8. 变量引用和隐式final 为何内部类使用外部变量要是final的 3. stream流式编程
3.1. 外部迭代和内部迭代 (1). 什么是外部迭代 (2). 什么是内部迭代 3.2. 中间操作/终止操作/惰性求值 (1). 什么是中间操作? 返回还是流stream的操作, 就是中间操作, 例如 map操作
map flatMap distinct limit skip filter peek sorted (1.1) 有状态操作 有前后顺序依赖关系的操作, 比如
distinct(前后不能相同)
sorted(前后顺序要求)
limit/skip(截取前面的/跳过前面的)
(1.2) 无状态操作 无前后依赖关系的操作:
map/mapToInt/flatMap/flatMapToInt
filter
peek
(2). 什么是终止操作? 返回一个结果的(求和/汇总)等, 例如 sum/max/min/avg等
forEach collect reduce toArray min/max/count findAny findFirst allMatch anyMatch noneMatch (1.1) 短路操作 findFirst
findAny
allMatch
anyMatch
noneMatch
(1.2) 非短路操作 forEach
forEachOrdered 并行流中保证顺序的
collect
toArray
reduce 输入: BinaryOperator
min
max
count
(3). 什么是惰性求值? 如果没有终止操作, 中间的操作动作都不会实际执行, 这就是惰性求值;
3.3 stream流的创建 (1) 集合 collection.stream
collection.parallelStream
(2) 数组 array.stream
Stream.of
(3). 数字 IntStream IntStream.range
IntStream.rangeClosed
LongStream LongStream.range
LongStream.rangeClosed
Random Random.longs
Random.ints
Random.doubles
(4).自己创建 Stream.generate
Stream.iterate
3.4 并行流 (1). parallel() (2). 并行流默认使用的线程池 ForkJoinPool.commonPool
(3). 自定义线程池 如何自定义线程池, 并使用到流并行时?
3.5 收集器 collect (1). 收集对象的属性列表为一个新集合 collect(Collectors.toList())
(2). 统计信息汇总 IntSummaryStatistics ageSumStats = students.stream().collect(Collectors.summarizingInt(Student::getAge))
(3). 分块:使用断言(一分为二) Map genders = students.stream().collect(Collectors.partitioningBy(s->s.getGender() == Gender.MALE))
(4). 分组:使用属性(一分为N, 类似sql groupby) Map grades = students.stream().collect(Collectors.groupingBy(Student::getGrade))
(5). 分组并汇总计数 Map gradeCount = students.stream().collect(Collectors.groupingBy(Student::getGrade, Collectors.counting()));
counting()可以替换为同类的max/min/avg等
(6). 小结 Collectors.toList() Collectors.toCollection() Collectors.summarizingInt(x) Collectors.partitioningBy(x) Collectors.groupingBy(x) Collectors.counting() 3.6 stream运行机制 (1). 链式调用 所有操作链式调用, 1个元素只迭代一次;
(2). 属性sourceStage 每一个中间操作返回一个新的stream流, 流内有一个属性: sourceStage; 指向同一个地方: 即 链表的头 Head
(3). Head -> nextStage -> nextStage -> null stream接口的实现类
java.util.stream.AbstractPipeline
java.util.stream.ReferencePipeline
属性: sourceStage --> ReferencePipeline$Head
java8实战学习
文章图片

(4). 无状态操作运行机制 完全链式调用: s1.a操作完->s1.b
(5). 有状态操作运行机制

public void testStream() { Random r = new Random(); Stream.generate(() -> r.nextInt()).limit(500) .peek(s -> System.out.println("peek: " + s)) // 1 .filter(s -> {// 2 System.out.println("filter: " + s); return s > 1000000; }) .sorted((i1, i2) -> { // 3. System.out.println("排序:" + i1 + ", " + i2); return i1.compareTo(i2); }) .peek(s -> System.out.println("peek2:" + s)) //4. .count(); }

1,2 都是无状态操作; 3是有状态操作; 4是无状态操作
3的有状态操作会截断 1, 2的无状态操作;
本来是1, 2的链式调用: s1.a->s1.b->s1.c 现在会变成: s1.a() ->s2.a() -> s1.b() ->s2.b()
output: 无sorted: 可以看到纯无状态操作是纯链式: peek->filter->peek2
peek: 2047843427 filter: 2047843427 peek2:2047843427 peek: -1210662664 filter: -1210662664 peek: 835825054 filter: 835825054 peek2:835825054 peek: 2068471207 filter: 2068471207 peek2:2068471207 peek: -1139851578 filter: -1139851578 peek: -885776051 filter: -885776051 peek: 481902862 filter: 481902862 peek2:481902862 peek: 684461691 filter: 684461691 peek2:684461691 peek: 1417449012 filter: 1417449012 peek2:1417449012 peek: -40633821 filter: -40633821

output: 有sorted: 可以看到后面的无状态操作peek2被有状态的sorted打断, 变成: peek->filter... peek->filter 排序all, peek2 all
peek: -607778068 filter: -607778068 peek: 50926402 filter: 50926402 peek: -774310924 filter: -774310924 peek: 342023904 filter: 342023904 peek: 26606322 filter: 26606322 peek: 693727663 filter: 693727663 peek: -334751306 filter: -334751306 peek: -960784614 filter: -960784614 peek: 522967780 filter: 522967780 peek: -2144851449 filter: -2144851449 排序:342023904, 50926402 排序:26606322, 342023904 排序:26606322, 342023904 排序:26606322, 50926402 排序:693727663, 50926402 排序:693727663, 342023904 排序:522967780, 342023904 排序:522967780, 693727663 peek2:26606322 peek2:50926402 peek2:342023904 peek2:522967780 peek2:693727663

1, 2还是链式调用; 中间的3执行完后, 隔断了4, 所以4不会和1,2承续链式调用, 而是单独执行;
(6) 并行操作: parallel() 在4后加5: parallel():
sorted() 有状态操作不会并行; 1,2,4都会使用 ForkJoinPool线程池并行执行:
@Test public void testStream() { Random r = new Random(); long count = Stream.generate(() -> r.nextInt()).limit(10) .peek(s -> System.out.println(Thread.currentThread().getName() + " peek: " + s)) // 1 .filter(s -> {// 2 System.out.println(Thread.currentThread().getName() + " filter: " + s); return s > 1000000; }) .sorted((i1, i2) -> { // 3. System.out.println(Thread.currentThread().getName() + " 排序:" + i1 + ", " + i2); return i1.compareTo(i2); }) .peek(s -> System.out.println(Thread.currentThread().getName() + " peek2:" + s)) //4. .parallel() .count(); System.out.println(count); }

ForkJoinPool.commonPool-worker-1 peek: -1644694686 ForkJoinPool.commonPool-worker-1 filter: -1644694686 ForkJoinPool.commonPool-worker-1 peek: 1524371421 ForkJoinPool.commonPool-worker-1 filter: 1524371421 ForkJoinPool.commonPool-worker-1 peek: -1937453784 ForkJoinPool.commonPool-worker-1 filter: -1937453784 ForkJoinPool.commonPool-worker-1 peek: 991114309 ForkJoinPool.commonPool-worker-1 filter: 991114309 ForkJoinPool.commonPool-worker-1 peek: -109655961 ForkJoinPool.commonPool-worker-1 filter: -109655961 ForkJoinPool.commonPool-worker-1 peek: 878490064 ForkJoinPool.commonPool-worker-1 filter: 878490064 ForkJoinPool.commonPool-worker-1 peek: 2031919515 ForkJoinPool.commonPool-worker-1 filter: 2031919515 ForkJoinPool.commonPool-worker-1 peek: -1855129379 ForkJoinPool.commonPool-worker-1 filter: -1855129379 ForkJoinPool.commonPool-worker-1 peek: 1897985020 ForkJoinPool.commonPool-worker-1 filter: 1897985020 ForkJoinPool.commonPool-worker-1 peek: 352116584 ForkJoinPool.commonPool-worker-1 filter: 352116584 main 排序:991114309, 1524371421 main 排序:878490064, 991114309 main 排序:2031919515, 878490064 main 排序:2031919515, 991114309 main 排序:2031919515, 1524371421 main 排序:1897985020, 1524371421 main 排序:1897985020, 2031919515 main 排序:352116584, 1524371421 main 排序:352116584, 991114309 main 排序:352116584, 878490064 ForkJoinPool.commonPool-worker-6 peek2:991114309 main peek2:1524371421 ForkJoinPool.commonPool-worker-3 peek2:352116584 ForkJoinPool.commonPool-worker-2 peek2:2031919515 ForkJoinPool.commonPool-worker-7 peek2:1897985020 ForkJoinPool.commonPool-worker-4 peek2:878490064 6

结论: 有状态的并行操作"不一定"并行 为啥是"不一定"?
【java8实战学习】因为官方并未明说, 但是观察下来, 是非并行的!
3.7 小结链式调用原理:
  1. stream链式调用原理: ReferencePipeline
  2. 每个中间操作产生一个流(新的流)
  3. 新流和原流的关系: 新流内有个sourceStage->指向原流的Head节点(ReferencePipeline$Head)
  4. 链式调用的维护: ReferencePipeline中的 nextStage -> nextStage -> null来维护链;
3.8 小结2
  1. 有状态操作 破坏链式调用
  2. 并行操作中有状态操作不一定并行, 如排序!

    推荐阅读