• 《Java8 实战》读书笔记


    《Java8 实战》读书笔记

    第一章:Java8

    1.1.2 流处理: java.util.strem  可以将代码思路改变成 从一个流到另外一个流,Java可以透明地将处理过程并行 拿到几个CPU内核上分别执行Stream操作流水线(简化并行操作的成本)

    1.1.3 用行为参数化将代码传递给方法

    1.1.3 流处理能力 要保证 不访问共享的可变数据

    第二章: 通过行为参数化传递代码

    1、 可通过参数 传递代码/行为: 创建一个函数式接口,接口中只能有一个抽象方法,皆空中可以拥有默认方法

    可以在函数式接口上加@FunctionalInterface 标注某接口是函数式接口,编译器会进行检查 该函数是否符合函数式接口的定义

    2、 多种行为,一个参数: 可通过不同的接口实现 定义多种行为

    3、 可使用匿名类 避免啰嗦的接口实现

    4、 可使用Lambda表达式 更简介地实现接口

    第三章: Lambda表达式

    • Lambda 表达式基本格式 (Apple a1,Apple a2)-> a1.getW().compare(a2.getW())
      1. 包括参数(类型,变量名)+ -> +Lambda主体
      2. 表达式不用带{} ,语句需要带{} ,例如:
        1. 1、(parameters)->expression
        2. 2、(parrameters)->{statements; }
      3. 参数可以为空
      4. 参数类型可以省略 编译器可以自己推断
      5. 当只有一个参数时 括号()也可省略
    • Lambda表达式利用函数式接口的步骤
      1. 定义函数式接口(一般使用Java提供的即可)
      2. 利用函数式接口 将具体业务的函数 行为参数化
      3. 利用Lambda表达式 实现函数式接口
      4. 具体业务函数 执行函数式接口内定义的方法
    • 常见默认函数式接口
      1. Predicted<T> : boolean test(T t)
      2. Comsumer<T>: void accept(T t)
      3. Fuction<T,R> : R apply(T t)
      4. 原始类型特化 : 避免装箱造成的代价(装箱后保存在堆中)
        1. 如 IntPredicate: boolean test(int t)
        2. 常见函数式接口
    • Lambda 表达式自动类型检查的具体步骤:
      1. 找出使用Lambda表达式的函数对应的参数类型(是个函数式接口) 如Predicted<Apple>
      2. 找出这个函数式接口的方法,Lambda表达式的 参数要符合这个方法的参数

    注意:同一个Lambda 可以对应不同的 函数式接口

    • Lambda表达式 若使用局部变量 那局部变量必须是final型 或 事实上是final
      1. 局部变量保存在栈中
      2. 若Lambda使用新的线程去访问局部变量 实际是访问它的副本 若局部变量仅仅被赋值一次 就没什么影响
    • 方法引用(更简洁地写Lambda语句)
      1. Apple::getWeight 等价于 (Apple a)->a.getWeight()
      2. 构造函数也可以使用方法引用 并可以使用带参数的构造函数
        1. Supplier<Apple> c1=Apple::new 返回Apple类型的对象 使用默认构造函数
        2. Supplier<Interger,Apple> c1=Apple::new 使用参数为Interger的构造函数
    • 复合Lambda表达式
      1. 比较器复合
        1. 逆序 appleList.sort(comparing(Apple::getWeight).reversed());
        2. 比较器链: 按重量递减;一样重时按国家排序
          1. sort(comparing(Apple::getWeight).reversed()

    .thenComparing(Apple::getCountry));

    1. 谓词复合 negate 非,and ,or (复合顺序从左向右 确定优先级)
      1. Predicate<Apple> redAndHeavyAppleOrGreen=redApple.and(a->a.getWeight()>150)

    .or(a->”green”.euquals(a.getColor()));

    1. 函数复合
      1. andThen: f.andThen(g) 相当于 g(f(x))
      2. compose: f.compose(g) 相当于 f(g(x))
    • Lambda表达式的用处
      1. 在环绕执行模式 可以利用Lambda提高灵活性和可重用性
      2. 环绕执行模式指的是:在一个方法所必须的代码中间,你需要执行一些操作

    第四章: 流 Stream

    • 流的概念: 从支持数据处处理操作的源 生成的元素序列P72

    A stream is a sequence of elements from a source that supports data processing operations

    • 流与集合的区别:
      1. 流中的元素是按需计算的,流就像一个延迟创建的集合,只有在消费者要求的时候才会计算
      2. 集合是内存中的数据结构 每个元素都需要先计算处理 才能添加到集合中
    • 流只能遍历一次
    • 内部迭代:流帮我们将迭代做了 这样流可以透明的并行处理 或 用更优化的顺序处理
    • 中间操作: filter或 sorted 操作 会返回另外一个流,且只在触发终端操作后执行
    • 终端操作: 从流的 流水线 生成结果,结果不含流

    第五章: 使用流

    5.1 筛选和切片

    • 谓词筛选: 返回boolean的函数称为谓词; filter方法接收谓词 做出筛选
    • 去重 distinct()
    • 截断 只取n个元素 limit(n)
    • 跳过 跳过前n个元素 skip(n)

    5.2 映射 (一种类型 映射成另外一种类型)

    • map() 将每个元素 映射成一个新的元素 如map(Dish::getName) 或 map(n->n*n)
    • flatMap() 扁平化一个流

    5.3 查找和匹配 (终端操作)

    1、 allMatch 、anyMatch 、noneMatch、(加谓词 即可判断)

    2、 findFirst、 findAny 需要使用Optional<T> 做返回值 因为可能结果不存在

    3、 Optional 中的方法:

     isPresent() 包含值时返回true;ifPresent(Consumer<T> block) 值存在时执行代码块

     T get() 返回值,若不存在抛出NoSuchElement异常

     T orElse(T other) 返回值 若不存在 返回默认值T

    注: 函数描述符指的是 操作中 lambda函数的参数类型;有状态指的是 该操作会存储中间状态

    5.4 规约 reduce

    • 求和
      1. reduce(0,(a,b)->a+b) 或 reduce(0,Integer::sum);
      2. 不使用初值时返回为Optinal<Integer>
    • 最值
      1. reduce(Interger::min) 或 reduce((x,y)->x<y?x:y)

    5.6 数值流

    • 为避免装箱造成的额外成本 存在IntStream DoubleStream 和LongStream 三个数值流,分别将元素特化为int、long、double
    • 使用mapToInt mapToDouble mapToLong 可将流 映射到数值流
    • 使用.boxed() 将数值流 映射到 流
    • 用特化的OptinalInt OptinalDouble OptionalLong 来存储结果,orElse(1) 可提供默认值
    • 使用rangeClosed(start,end) 或 range(start,end+1) 产生[start,end] 的数

     

    5.7 构建流

    • 由值创建流 of(“v1”,”v2”)
    • 由数组创建流stream(new int[] {2,4,5})
    • 由文件生成流 Stream<String> lines=Files.lines() P127
    • 由函数生成流 (可生成无限流)iterate() 和 generate() P128
      1. iterate(0,n->n+2)
      2. generate(Math::random)

    第六章:用流收集数据 collect

    收集器 用函数式编程的方式 将交易按货币分组的例子,避免了指令式风格冗长的代码

    • 预定义收集器 Collectors 实现了 一些预定义的收集器: 如表6-1所示
    • 收集器 都可以用reducing工厂方法定义规约过程reducing(初值,转换函数,合并操作)
      1. reduce 旨在将两个值 结合起来生成一个新值 是一个不可变的归约
      2. collect 改变容器 积累要输出的结果
    • 分组groupingBy
      1. 按类型分组 groupingBy(Dish::getType)
      2. 自定义分组 groupingBy(dish->{if(xxx) return TYPE1;else return TYPE2;})
      3. 多级分组 groupingBy(Dish::getType1,groupingBy(Dish::getType2))
      4. 按组收集数据groupingBy(Dish::getType,countting()
      5. 将收集器的结果转化成另外一种类型 groupingBy(Dish::getType,collectingAndThen(maxBy(xx),Optinal::get))P144
    • 分区 partitioningBy (实际上是 通过谓词进行分组 组别为true false)
    • 自定义Collector P156
      1. Collector接口:T要收集的数据类型 ;A累加器的类型 ;R返回值的类型

    1. supplier() 建立累加器实例;accumulator() 将数据累加到累加器
    2. finisher() 将累加器 转换成 返回值; combiner() 合并 并行结果
    3. characteristic() 定义收集器的行为
      1. UNORDERED 归约结果不受遍历和累加顺序影响
      2. CONCURRENT accumulator()可并行
    • IDENTITY_FINISH : A可以直接转换成R

    第七章: 并行数据处理与性能

    • range 操作比 iterate 更快 因为不用装箱且数据可分段
    • 利用 parallel() 命令可以将 顺序流转为 并行流
    • sequential() 命令 将并行流 转为顺序流 可以在流水线上 结合这两个命令 实现精细化控制并行
    • 并行流中 使用默认的ForkJoinPool ,默认线程数为处理器数量
    • Java8 中加入了Spliterator 可分迭代器 用于并行遍历数据源中的数据
      1. 重写Spliterator的例子P178

    实践:1 求两个数组的交集 https://leetcode-cn.com/problems/intersection-of-two-arrays/

            return Arrays.stream(nums1)

            .filter(n1->Arrays.stream(nums2).anyMatch(n2->n2==n1))

            .distinct()

            .parallel()

            .toArray();

  • 相关阅读:
    TinySpider开源喽
    TinyXmlParser开源喽
    Tiny快速入门之控制层开发
    TinyDBRouter
    TinyIOC
    开源前要做好哪些准备工作?
    分布式锁的简单实现
    TinyDBCluster Vs routing4db
    HTML5基础(五)
    HTML5基础(四)
  • 原文地址:https://www.cnblogs.com/lancelee98/p/15336823.html
Copyright © 2020-2023  润新知