java8实战学习总结1

  1. 1.1 什么是lambda表达式
  2. 1.2 什么样的场景能使用lambda表达式
  3. 1.3 lambda表达式实现一个接口的四种写法
  • 2. 函数式编程
    1. 2.1 什么是函数式编程
    2. 2.2 什么是命令式编程
    3. 2.3 什么是函数式接口 FunctionalInterface
    4. 2.4 什么是 default 方法
    5. 2.5 default方法的意义
    6. 2.6 java8内置的常用函数式接口
      1. (1). Predicate
      2. (2). Consumer
      3. (3). Supplier
      4. (4). Function<T, R>
      5. (5). UnaryOperator
      6. (6). BinaryOperatior
      7. (7). BiFunction<T, U, R>
    7. 2.7 方法引用
      1. (1). 静态方法的方法引用
      2. (2). 实例方法的方法引用
      3. (3). 构造方法的方法引用
    8. 2.8. 变量引用和隐式final
      1. 为何内部类使用外部变量要是final的
  • 3. stream流式编程
    1. 3.1. 外部迭代和内部迭代
      1. (1). 什么是外部迭代
      2. (2). 什么是内部迭代
    2. 3.2. 中间操作/终止操作/惰性求值
      1. (1). 什么是中间操作?
        1. map
        2. flatMap
        3. distinct
        4. limit
        5. skip
        6. filter
        7. peek
        8. sorted
        9. (1.1) 有状态操作
        10. (1.2) 无状态操作
      2. (2). 什么是终止操作?
        1. forEach
        2. collect
        3. reduce
        4. toArray
        5. min/max/count
        6. findAny
        7. findFirst
        8. allMatch
        9. anyMatch
        10. noneMatch
        11. (1.1) 短路操作
        12. (1.2) 非短路操作
      3. (3). 什么是惰性求值?
    3. 3.3 stream流的创建
      1. (1) 集合
      2. (2) 数组
      3. (3). 数字
        1. IntStream
        2. LongStream
        3. Random
      4. (4).自己创建
    4. 3.4 并行流
      1. (1). parallel()
      2. (2). 并行流默认使用的线程池
      3. (3). 自定义线程池
    5. 3.5 收集器 collect
      1. (1). 收集对象的属性列表为一个新集合
      2. (2). 统计信息汇总
      3. (3). 分块:使用断言(一分为二)
      4. (4). 分组:使用属性(一分为N, 类似sql groupby)
      5. (5). 分组并汇总计数
      6. (6). 小结
        1. Collectors.toList()
        2. Collectors.toCollection()
        3. Collectors.summarizingInt(x)
        4. Collectors.partitioningBy(x)
        5. Collectors.groupingBy(x)
        6. Collectors.counting()
    6. 3.6 stream运行机制
      1. (1). 链式调用
      2. (2). 属性sourceStage
      3. (3). Head -> nextStage -> nextStage -> null
      4. (4). 无状态操作运行机制
      5. (5). 有状态操作运行机制
      6. (6) 并行操作: parallel()
    7. 3.7 小结链式调用原理:
    8. 3.8 小结2
  • 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>

    输入T, 输出R的函数

    (5). UnaryOperator

    一元函数: 输入1个输出 1个: 类型都是T

    (6). BinaryOperatior

    二元函数: 输入2个输出1个: 类型都是T

    (7). BiFunction<T, U, R>

    输入两个输出一个: 输入 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<Boolean, List> genders = students.stream().collect(Collectors.partitioningBy(s->s.getGender() == Gender.MALE))

    (4). 分组:使用属性(一分为N, 类似sql groupby)

    Map<Grade, List> grades = students.stream().collect(Collectors.groupingBy(Student::getGrade))

    (5). 分组并汇总计数

    Map<Grade, Long> 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
    image.png

    (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

    结论: 有状态的并行操作"不一定"并行 为啥是”不一定”?

    因为官方并未明说, 但是观察下来, 是非并行的!

    3.7 小结链式调用原理:

    1. stream链式调用原理: ReferencePipeline
    2. 每个中间操作产生一个流(新的流)
    3. 新流和原流的关系: 新流内有个sourceStage->指向原流的Head节点(ReferencePipeline$Head)
    4. 链式调用的维护: ReferencePipeline中的 nextStage -> nextStage -> null来维护链;

    3.8 小结2

    1. 有状态操作 破坏链式调用
    2. 并行操作中有状态操作不一定并行, 如排序!

    转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 hi@niewj.com

    ×

    喜欢就点赞,疼爱就打赏