pursue wind pursue wind
首页
Java
Python
数据库
框架
Linux
中间件
前端
计算机基础
DevOps
项目
面试
书
关于
归档
MacOS🤣 (opens new window)
GitHub (opens new window)
首页
Java
Python
数据库
框架
Linux
中间件
前端
计算机基础
DevOps
项目
面试
书
关于
归档
MacOS🤣 (opens new window)
GitHub (opens new window)
  • 技术面试题篇

  • 面试准备篇

  • 技术面试题自测篇

  • 练级攻略篇

  • 工作篇

  • 面经篇

  • 笑傲Java面试

    • 2-1 导学-Java编程技巧部分
    • 2-2 IDEA Java配置补充
    • 2-4 Java8 Stream 接口:流和并发计算实例
      • [](#管道运算)管道运算
        • [](#例子1:-map--filter)例子1: Map + Filter
        • [](#例子2-map--filter--reduce)例子2: Map + Filter + Reduce
        • [](#stateful-vs-stateless)Stateful vs Stateless
        • [](#flatmap)flatMap
      • [](#并行计算)并行计算
    • 2-5 和面试官聊聊实现管道和流计算的基石:函数式的Monad
    • 2-6 Buffer的原理和使用场景+面试题解读
    • 2-7 补充提问:同步和阻塞、异步和非阻塞等不等价?
    • 2-8 阿里面试题:中文乱码处理和大文件计算词频
    • 2-9 实战场景Coding训练:解读反射+代理+AOP 并结合业务逻辑实现
    • 2-10 注解部分答案
    • 2-11 反射-元编程面试题目合集
    • 2-12 面试必备:Java8-11的新特性和理解的误区
    • 2-13 白板篇-Java编程总结(以及面试题)
    • 3-1 算法和数据结构导学
    • 3-2 教你面试时不会忘记的5种手写排序
    • 3-3 手写链表算法
    • 3-4 手写栈和队列面试专项
    • 3-5 课后习题+面试题:用栈和队列实现表达式解析
    • 3-6 迷宫伪代码和8皇后问题源代码
    • 3-7 3-7 树部分源代码
    • 3-8 8皇后问题
    • 3-10 动态规划的课前题目
    • 3-11 总结和课后习题:白板篇-数据结构和算法
    • 4-1 解读:并发编程知识体系
    • 4-2 看看你的基础:Java线程状态之间如何转换?
    • 4-3 CAS和原子操作
    • 4-4 同步器(上篇)——面试官问synchronized本质是什么?
    • 4-5 同步器(中)——AbstractQueuedSynchronizer
    • 4-6 面试官:说6个Java的同步器?
    • 4-7 面试官出难题:并发环境下单例怎么写性能最高
    • 4-8 面试官:LinkedBlockingDeque和SynchronousQueue工作原理一样吗?
    • 4-9 面试要点:volatile的简短补充
    • 4-10 给面试官讲讲无锁编程(Lock-Free Programming)
    • 4-11 高阶并发编程Coding训练:N种优化哲学家就餐问题的方法
    • 4-12 并发基础篇:总结和思考题
    • 4-13 并发部分的通关Boss: 生成、发放大量红包并控制资金流速
  • LeetCode

  • 面试
  • 笑傲Java面试
pursuewind
2021-12-13
目录

2-4 Java8 Stream 接口:流和并发计算实例

# Java8 Stream 接口:流和并发计算实例

现在的将来发展越来越偏向于函数式了。主要是因为我们在开发Java的时候经常会有很多业务逻辑。很多类型,很多数据需要处理。通过数学严格定义的函数式编程,加上方便的管道运算,再加上各种各样在操作,构成了我们今天丰富多彩的Stream生态。

Java8的Stream对一个元素序列提供顺序和并行运算。最重要的4个能力是:

  1. 支持函数式编程
  2. 提供管道运算能力
  3. 提供并发计算能力
  4. 提供大量的操作

关联面试题:

  1. 什么是流?
  2. ::运算符的作用?
  3. Java 8的Stream价值是什么?
  4. 创建Stream有几种方法?
  5. coding:利用parallel并发执行任务?

# 管道运算

**流是随着时间产生的数据序列。**我们写程序的时候还有很多种流。比如文件流、字符流、网络流、信息流、订阅流……

Stream也是流,它为序列提供顺序、并发运算。

image-20210126000627892

管道是组织流计算的一种手段,Linux的管道连接一个进程的输出到另一个进程的输入。Stream底层也是管道在支持。每一步操作,都是一个管道。这个管道。连接上游的输出,和下游的输入。Stream的管道设计。是从数据源开始连接上很多中间操作(intermediate operation),对数据进行变换。最后接上一个终止操作(terminal operation)对结果进行运算。和转换。

# 例子1: Map + Filter

@Test
public void test_mapfilter() {
    Stream.of(1,2,3,4,5,6)
        .map(x -> x.toString())
        .map(x -> x + x)
        .map(x -> x + x + x)
        //                .map(x -> Integer.parseInt(x))
        .map(Integer::parseInt)
        .forEach(x -> {
            System.out.println(x);
        });
}

Stream.of是一个数据源的工厂,用来构造流。除此之外容器(collection)类型都可以用stream() 方法直接构造流。

函数式编程最关心的就是类型。map将一个类型映射成另一个类型。forEach是终止操作。

# 例子2: Map + Filter + Reduce

image-20210130103159117

上面例子中的result是OptionalInt类型。Optional 类型代表一个可能有值,可能没有值的箱子(Monad)。isPresent 可以判断这个箱子是否有值。因为T必须是对象,因此OptionalInt是针对int封装的Optional类型。

下面构造了一个空流,返回的OptionalInt的isPresent值为false 。可以用orElseGet 设置默认值。

@Test
public void test_mapfilterreduce(){
    //var result = Stream.of(1,2,3,4,5,)
    var result = IntStream.of()
        .map(x -> x * x)
        .filter(x -> x < 20)
        .reduce( Math::max);
    //                    .orElse(0);
    //.reduce(0, Integer::min);
    System.out.println(result.isPresent());
    System.out.println(result.orElseGet(() -> 0));
}

关于更多 Monad,我们在下一节讨论。

# Stateful vs Stateless

状态是一个很宽泛的概念。比如内存中的值、寄存器中的值发生变化我们就称之为状态的变化。比如说变量的数据、类型的成员都可以称之为状态。

下面的程序中,sorted是一个中间操作。他对原始数据进行排序,内部的实现中sorted 会改变原始数据的顺序。这种我们称之为stateful ,也就是有状态操作。

@Test
public void test_mutation() {
    var stream = Stream.of(1,3,5,2,3,4,5,6).sorted();
    stream.forEach(System.out::println);
}

相比之下,map操作,不改变任何状态。只是将一个类型映射成另一个类型,我们称之为无状态操作(stateless)。

# flatMap

@Test
public void test_flatMap(){
    // String -> Stream<R>
    var set = Stream.of("My", "Mine")
        .flatMap(str -> str.chars().mapToObj(i -> (char)i))
        .collect(Collectors.toSet());
    System.out.println(set.stream().collect(Collectors.toList()));
}

# 并行计算

并行、并发等概念会在并发编程部分详细介绍。

流经过parallel或者parallelStream运算之后,内部会创建ForkJoinPool组织并行计算。通常是以CPU核数-1数量创建线程。也可以自己提供ForkJoinPool。

下面程序中我们自己提供了ForkJoinPool,约定线程数为2。更多细节,请参考视频讲解。

@Test
public void test_parallel() throws ExecutionException, InterruptedException {

    var r = new Random();
    var list = IntStream.range(0, 1_000_000)
        .map(x -> r.nextInt(10_000_000))
        .boxed()
        .collect(Collectors.toList());

    var t0 = System.currentTimeMillis();
    System.out.println(list.stream().max((a, b) -> a - b));
    System.out.println("time:" + (System.currentTimeMillis() - t0));

    // 1000
    var pool = new ForkJoinPool(2);
    var t1 = System.currentTimeMillis();
    var max = pool.submit(() -> list.parallelStream().max((a , b) -> a -b)).get();

    //        list.stream().parallel().max((a , b) -> a -b);

    // 15
    // Spliter 1024 -> Thread0 1024 -> Thread1

    System.out.println("time:" + (System.currentTimeMillis() - t1) + ",max:" + max);
}
Last Updated: 2023/02/14, 18:02:00
2-2 IDEA Java配置补充
2-5 和面试官聊聊实现管道和流计算的基石:函数式的Monad

← 2-2 IDEA Java配置补充 2-5 和面试官聊聊实现管道和流计算的基石:函数式的Monad→

Theme by Vdoing | Copyright © 2019-2023 pursue-wind | 粤ICP备2022093130号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
  • 飙升榜
  • 新歌榜
  • 云音乐民谣榜
  • 美国Billboard榜
  • UK排行榜周榜
  • 网络DJ