2021-03-22

Java 8 实战

前言

Why Java 8?

代码简洁,可读性高,不改变原值(不可见、范型)

// 输入 abdeeeea;输出 eeeeaabd
  private static void jdk7sort(List<Map.Entry<Character, Integer>> list) {
        Collections.sort(list, new Comparator<Map.Entry<Character, Integer>>() {
            @Override
            public int compare(Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2) {
                {
                    int firstCount = o1.getValue();
                    int secondCount = o2.getValue();
                    if (firstCount != secondCount) {
                        return secondCount - firstCount;
                    }
                    return o1.getKey().charValue() - o2.getKey().charValue();
                }
            }
        });
    }

    private static void jdk8sortAndThenCompare(List<Map.Entry<Character, Integer>> list) {
        list.sort(Map.Entry.<Character, Integer>comparingByValue().reversed().thenComparing(Map.Entry.comparingByKey()));
    }
  • Cool(语法糖)不改语法结构,运行时等价,语义自然

Lambda 表达式

Lambda-函数式编程

  • 拼接行为(搭积木 复合)像linux命令: cat tmp.md |grep GET 其中的|、 catgrep为操作,tmp.mdGET、返回结果为输出。
  • 降低匿名类的创建成本
  • 环绕执行模式
  • 行为参数化
  • 使用函数式接口来传递行为
  • 执行一个行为
  • 传递lambda

Lambada-接口

Lambada 打开方式

  • 函数式接口定义输入、输出,用户定义法则,共同构成函数-公式

煮个🌰 勾股定理

1. 两个入参一个返回参数,选 BiFinction
2. 定义法则 ( x, y ) ->
       
( int ) ( Math. sqrt ( Math. pow ( x, 2 ) + Math. pow ( y, 2 ))
3. 构成 函数 BiFunction < Integer, Integer, Integer > pythagorean = ( x, y ) ->
       
( int ) ( Math. sqrt ( Math. pow ( x, 2 ) + Math. pow ( y, 2 ))) ;
4. 函数调用 pythagorean.apply ( 3 , 4 )
  • 抽象出有公共法则(数据处理方式)、输入、输出的方法函数化放在工具类中,供各个模块调用

Lambada 可扩展

  • 如果已有的函数式接口不够用,可以自定义:
@FunctionalInterface
public interface TriFunction<A, B, C, R> {

  R apply(A a, B b, C c);
}

 

Lambada 复合-关联词

  • 比较器复合 Comparator.comparing
  1. 逆序 reversed()
  2. 比较器链 thenComparing

  • 谓词复合Predicate
  1. negate
  2. and 优先级从左到右
  3. or

  • 函数复合Function
  1. 然后f.andThen(g)=g(f(x))
  2. 组合f.compose(g)=f(g(x))

Stream

What’S Stream?

  • 定义:从支持数据处理操作的源生成的元素序列
  1. 元素序列:流提供类似集合的可以访问特定元素类型的接口;集合->数据,流->计算
  2. 源:流会使用一个提供数据的源,如集合、数组或输入/输出资源;顺序性
  3. 数据处理操作:类似数据库操作,如filtermapreducematchsort;执行:顺序、并行
  • 特点
  1. 流水线:数据库查询
  2. 内部迭代
  • 用法
  1. 一个数据源(如集合)来执行一个查询
  2. 一个中间操作链,形成一条流的流水线
  3. 一个终端操作,执行流程线,生成结果
  • 其他:
  1. 状态操作:接受一个流时需要知道先前的历史

Stream-特征

  • 只能遍历一次

  • 内部迭代

 

  • parallelStream并行流
  1. 使用前提:无共享可变状态static

  • 映射到数值流
  1. mapToInt
  • 转换回对象流
  1. boxed
  • Optional
  1. OptionalInt
  2. OptionalLong
  3. OptionalDouble

Stream-构建

  • 由值构建 Stream.of(“Java 8”,”Lambda”,”In”); Stream.empty()
  • 由数组创建 Arrays.stream(new int[]{1,2,3,4,5})
  • 由文件生成 Files.lines(Paths.get(dir),Charset.defaultCharset())
  • 由函数生成:无限流
  1. 迭代 Stream.iterate(0,n->n+2)
  2. 生成 Stream.generate(Supplier<T>) 例如Stream.generate(Math::random)

Stream-模式

  • 中间操作:
  1. 筛选
  2. 切片
  3. 映射

  • 终端操作
    1. 查找
    2. 匹配
    3. 规约

Stream-flatMap

  • 中间操作-映射扁平化

Stream-Reduce

  • 前提:内部状态有界
  • 类型一:
    • 入参
    • 一个初始值
    • 一个BinaryOperation<T> 两个元素合并成新值
    • 返回:T
  • 类型二:
  • 入参:一个BinaryOperation<T>
  • 返回:Optional<T>

Stream-Collector

  • public interface Collector<T, A, R> {
  1.  Supplier<A> supplier();//建立新的结果集合
  2. BiConsumer<A, T> accumulator();//将元素添加到结果容器
  3. Function<A, R> finisher();//对结果容器应用最终转换
  4. BinaryOperator<A> combiner();//合并两个结果容器
  5. Set<Characteristics> characteristics();}//行为:是否可合并规约,优化提示
  • UNORDERED 无序
  • CONCURRENT 并行,若无UNORDERED,仅无序数据源可以并行规约
  • IDENTITY_FINIHSH恒等函数,A不检查转R安全
  • T:流中要手机的项目的范型
  • A:累加器的类型,在收集过程中用于累积部分结果的对象
  • R:收集操作的到的对象的类型
  • 功能:
    • 将流元素规约和汇总为一个值
      1. 统计Longcounting()
      2. 最大值Optional<T>maxBy(Comparator<T>)
      3. 总和IntegersummingInt(ToIntFunction<T>)
      4. 平均DoubleaveragingInt(ToIntFunction <T>)
      5. 汇总IntSummaryStatistics:最大,最小,总和,平均: summarizingInt(ToIntFunction <T>)
      6. 连接字符串Stringjoining() joining(”,”)
      7. 广义上规约:reducing(U,Function<T,U>,BinaryOperator<U>)【初始值、转换函数;必须:累计函数
    • 元素分组(多级别)Map<K,List<T>>groupingBy(Function<T,K>,Collector)【必须:Function<T,K>】
    • 元素分区Map<Boolean,List<T>>:由一个谓词作为分类函数为分区函数partitioningBy(Predicate<T>,Collector)【必须:Predicate<T>】

Stream-Collector-分组

  • 多级:collectingAndThen

并行数据处理

Why parallel?

//影响所有并行流,并行线程池大小,建议设置成处理器数量
log.info("java.util.concurrent.ForkJoinPool.common.parallelism :{}", System.getProperty("java.util.concurrent.ForkJoinPool.common.parallelism"));
Long start = System.nanoTime();
//122
log.info("{}", Stream.iterate(1L, i -> i + 1).limit(1000000).reduce(0L, Long::sum));
long mid = System.nanoTime();
//22
log.info("parallel {}", Stream.iterate(1L, i -> i + 1).limit(1000000).parallel().reduce(0L, Long::sum));
long end = System.nanoTime();
log.info("normal time: {}, parallel time: {}", (mid - start) / 1000000, (end - start) / 10000000);
 

How parallel?

  • 避免共享可变状态
  • 想使用并行流提升性能的建议:
  1. 如有疑问,测量
  2. 留意装箱,用IntStream等避免装箱
  3. 有些操作不适合并行如limitfindFirst
  4. 流水线总成本,单元素通过流水线的处理成本大,并行性能可能更好
  5. 元素过少时,并行化开销高于处理少数几个元素开销。
  6. 流自身特点 ,若流可分可并行,若不可分入无限流Distinct就不合适
  7. 合并的代价 combiner大可能会超出通过并行流得到的性能提升

RecursiveTask-分支/合并框架

  • 实现唯一的抽象方法R compute()
  • 实现伪代码

ForkJoinPool

  • 问题:在处理有共享可变状态问题时,parallel计算结果不正确
  • 解决方案:自定义并行流计算Function:自定义ForkJoinTask<R>通过extend RecursiveTask<R>,在其compute()方法中分支/合并算法定义流的拆分、合并,并通过ForkJoinPool.invoke
  • ForkJoinPool,参数:java.util.concurrent.ForkJoinPool.common.parallelism默认处理器数量
  • 并行计算时有成本的,一般要用测试数据说明是否适合使用

Spliterator-Splitable iterator

  • 问题:默认拆分粒度可能导致结果并非预期
  • 原理:递归调用trySplit生成新Spliterator对象,直到对象为null
  • 特性:

自定义Spliterator

  • Implements Spliterator<R>实现
  1. tryAdvance 若剩余元素存在,执行给定操作
  2. trySplit 拆分子类
  3. estimateSize 遍历所遇到的元素数量的估量值
  4. characteristics定义特征
  • StreamSupport.stream(自定义spliterator,是否并行)
  • 对流进行reduce,初始化、拆分、合并。

CompletableFuture 组合式异步编程

  • 场景:异步服务调用
  • 方式:
  1. CompletableFuturecompute方法预存储异步线程计算结果;主线程继续执行操作,在需要使用结果时get
  2. 使用CompletableFuture.supplyAsync(Supplier<U>,Executor),后续join。其中Executor的核心线程数可以根据异步任务数灵活调整
  3. 复杂的异步调用:构造同步,操作异步;有多个步骤:
  • supplyAsync
  • thenApply(Function<T,U>)
  • thenCompose(Function<T,CompletableFuture>)join
  1. 异步组合构造:
  • supplyAsync
  • thenCombine(supplyAsync,Function<T,U>)get

复制流

其他新特性

  • Optional取代null10
  • 时间:LocalDateLocalDateTimeLocalTimeInstantDuration12

 ------------------------------------------------
    LocalDate   |    LocalTime |    ZoneId  
 ------------------------------------------------
|     LocalDateTime                                       |
 ------------------------------------------------
|                 ZoneDateTime                         

 ------------------------------------------------

思想

 

  • Stream API
  1. 声明性-更简洁,更易读
  • 范型:上下界-类型推断,sort,定义入参要满足的条件
  1. 可复合-更灵活
  • Lambda
  • 中间操作、终端操作
  1. 可并行-性能更好
  • parallelStream
  • 怎么做-->做什么
  • Java7 的sort VS  Java8 sorted

方法|异同

java版本

对象

性质

入参

复合

返回

sort

7

list

终端操作

comparator

支持

void

sorted

8

stream

中间操作

comparator

支持

stream

  • Stream reduce VS 中间操作,两个入参;Collectors.reducing 终端操作聚合,三个入参;规约,最后一个入场相同且必须
  • Collectors  VS final修饰的工具类,内部类CollectorImpl实现Collector 接口

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值