范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

WebFlux前置知识(三)

  Stream 流式 API 也是 JDK8 开始引入的 API,用过的小伙伴都说爽,没用过的小伙伴则感到一脸懵逼。现在 JDK 已经到 16 了,可能很多人还不熟悉 Stream 流操作,这次趁着讲 WebFlux,和大家一起回顾一下 Stream 流操作。  1.Stream 流简介
  说到 Stream,大家可能很容易想到 Java IO 中的各种流操作,名字看起来很像,但这其实是两个完全不同的东西。
  Java8 中的 Stream 不存储数据,它通过函数式编程模式来对集合进行链状流式操作。  2.基本玩法
  先来个简单的例子感受下 Stream 的操作。
  例如我有一个数组,如下:  int[] arr = {1, 2, 3, 4, 5, 6};
  现在想给这个数组求平均数,如下:  double asDouble = IntStream.of(arr).average().getAsDouble();
  一行代码搞定,首先调用 IntStream.of 方法获取流对象,然后调用 average 方法计算平均数,再调用 getAsDouble 方法获取结果。全程都是方法调用,不用自己写求平均数的逻辑。
  再比如求和,如下:  int sum = IntStream.of(arr).sum();
  也是直接调用 sum 方法即可。
  而且我们还可以在流中对数据进行二次加工,例如给数组中的每个元素先求平方再求和:  double[] arr = {1, 2, 3, 4, 5, 6}; double sum = DoubleStream.of(arr).map(i -> Math.pow(i, 2)).sum();
  先在 Map 中对每一个元素求平方,然后再求和。
  这里就能涉及到两个概念:  中间操作  终止操作
  所谓中间操作,就是中途求平方的操作,所谓终止操作就是最终计算出结果的操作,只要方法的返回值不是一个 Stream,那就是终止操作,否则就是中间操作。  3.Stream 的创建
  获取一个流的方式多种多样,最常见的就是从集合或者数组中获取一个流,当然我们也可以直接自己创建一个流出来。
  一起来看下。  集合
  List 集合或者 Set 集合都可以直接搞一个流出来,方式如下:  List list = new ArrayList<>(); Stream s1 = list.stream(); Set set = new HashSet<>(); Stream s2 = set.stream();
  集合中直接调用 stream 方法就可以获取到流。  数组
  通过数组获取流的方式也很简单,如下:  IntStream stream = Arrays.stream(new int[]{11, 22, 33, 44, 55, 66}); 数字 Stream
  也可以直接利用 IntStream、LongStream 等对象创建一个数字 Stream,如下:  IntStream s1 = IntStream.of(1, 2, 3); DoubleStream s2 = DoubleStream.of(1, 2, 3); LongStream s3 = LongStream.of(1L, 2L, 3L); 自己创建Random random = new Random(); Supplier supplier = () -> random.nextInt(100); Stream stream = Stream.generate(supplier).limit(5);
  调用 Stream.generate 方法可以自己创建一个流,自己创建的时候需要提供一个 Supplier,通过调用 Supplier 中的 get 方法自动获取到元素。
  无论哪种创建方式,大家需要明白的是,Stream 并不会保存数据,它只会对数据进行加工。  4.Stream 的中间操作
  中间操作可以分为两大类:  map 或者 filter 会从输入流中获取每一个元素,并且在输出流中得到一个结果,这些操作没有内部状态,称为无状态操作。  reduce、sum、max 这些操作都需要内部状态来累计计算结果,所以称为有状态操作。
  分别来看下:
  无状态操作  map/mapToXxx  flatMap/flatMapToXxx  filter  peek
  有状态操作  distinct  sorted  limit/skip
  map
  Stream.map() 是 Stream 中最常用的一个转换方法,可以把一个 Stream 对象转为另外一个 Stream 对象。map 方法所接收的参数就是一个 Function 对象,松哥在前面文章中和大家介绍过 Function 对象了,就是有输入有输出(参见WebFlux 前置知识(一)),了解了 map 的参数,那么 map 的功能就很明白了,就是对数据进行二次加工。
  举个栗子,例如把一个字符串数组转为数字:  String[] arr = {"1", "2", "3"}; Stream s1 = Arrays.stream(arr); Stream s2 = s1.map(i -> Integer.valueOf(i));
  再比如一个数字流,给所有的元素乘 2,如下:  IntStream.of(1, 2, 3).map(i -> 2 * i).forEach(System.out::println);
  最后的 forEach 就是将元素打印出来。
  JDK 中也提供了一些现成的格式转换,如下图:
  这样可以直接将元素转为 Double、Long、Obj 等类型,例如下面这样:  String[] arr = {"1", "2", "3"}; Stream s1 = Arrays.stream(arr); s1.mapToLong(i -> Long.parseLong(i)).forEach(System.out::println);
  flatMap
  flatMap 可以把 Stream 中的每个元素都映射为一个 Stream,然后再把这多个 Stream 合并为一个 Stream。
  例如如下代码,返回的 Stream 中的元素是数组:  Stream s = Stream.of(new Integer[]{1, 2, 3}, new Integer[]{4, 5, 6}, new Integer[]{7, 8, 9}); s.forEach(System.out::println);
  通过 flatMap 我们可以将 Stream 中的元素变为 Integer:  Stream s = Stream.of(new Integer[]{1, 2, 3}, new Integer[]{4, 5, 6}, new Integer[]{7, 8, 9}).flatMap( i -> Arrays.stream(i)); s.forEach(System.out::println);
  filter
  filter 操作会对一个 Stream 中的所有元素一一进行判断,不满足条件的就被过滤掉了,剩下的满足条件的元素就构成了一个新的 Stream。
  例如要找到数组中所有大于 3 的元素,如下:  IntStream.of(2, 3, 4, 5, 6, 7).filter(i -> i > 3).forEach(System.out::println);
  filter 方法接收的参数是 Predicate 接口函数,关于 Predicate 接口函数,大家可以参考WebFlux 前置知识(一))一文。
  peek
  peek 的入参是 Consumer,没有返回值,因此当我们要对元素内部进行处理时,使用 peek 是比较合适的,这个时候可以不用 map(map 的入参是 Function,它是有返回值的)。peek 方法本身会继续返回流,可以对数据继续进行处理。
  举个简单的数据转换的例子吧(最终返回的数据并不会被转换):  IntStream.of(2, 3, 4, 5, 6, 7).filter(i -> i > 3).peek(String::valueOf).forEach(i-> System.out.println(i)); ❝
  peek 方法的感觉就像数据中途被消费了一次。
  distinct
  这个是去重。由于去重操作需要获取到其他元素的值(比较之后才知道是否重复),所以这个是有状态操作。如下:  IntStream.of(2, 3, 4, 3, 7, 6, 2, 5, 6, 7).distinct().forEach(System.out::println);
  sorted
  sorted 是排序,因为也需要知道其他元素的值,然后才能去重,所以这个也是有状态操作,如下:  IntStream.of(2, 3, 4, 3, 7, 6, 2, 5, 6, 7).distinct().sorted().forEach(System.out::println);
  limit/skip
  limit 和 skip 配合操作有点像数据库中的分页,skip 表示跳过 n 个元素,limit 表示取出 n 个元素。例如下面这个例子:  Arrays.asList("A", "B", "C", "D", "E", "F").stream().skip(2).limit(3).forEach(System.out::println);
  这个会跳过 A 和 B,最终打印出 C D E。这也是一种有状态操作。  5.Stream 终止操作
  终止操作就是最终计算出结果的操作,只要方法的返回值不是一个 Stream,那就是终止操作,否则就是中间操作。
  终止操作又分为两类:  短路操作:不用处理全部元素就可以返回结果。  非短路操作:必须处理所有元素才能得到最终结果。
  各自都包含哪些操作,我们分别来看下:
  非短路操作  forEach/forEachOrdered  collect/toArray  reduce  min/max/count
  短路操作  findFirst/findAny  allMatch/anyMatch/noneMatch
  forEach/forEachOrdered
  forEach 和 forEachOrdered 都是接收一个 Consumer 类型的参数,完成对参数的消费,不同的是,在并行流中,forEachOrdered 会保证执行顺序。
  例如如下一段代码:  int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9}; Arrays.stream(arr).parallel().forEach(System.out::println); Arrays.stream(arr).parallel().forEachOrdered(System.out::println);
  前者打印出来的顺序不一定是 123456789,后者一定是。
  collect/toArray
  这两个都是收集器,可以将执行结果转为一个 List 集合或者一个数组:  List list = Stream.of(1, 2, 3, 4).filter(p -> p > 2).collect(Collectors.toList()); System.out.println(list);
  reduce
  reduce 是 Stream 的一个聚合方法,它可以把一个 Stream 的所有元素按照聚合函数聚合成一个结果。reduce 方法传入的对象是BinaryOperator 接口,它定义了一个apply 方法,负责把上次累加的结果和本次的元素进行运算,并返回累加的结果。
  举个简单的例子,数组求和,当然可以直接调用 sum 计算,我们这里也可以调用 reduce 来实现,如下:  Optional optional = Stream.of(1, 2, 3, 4).reduce((i, j) -> i + j); System.out.println(optional.orElse(-1));
  reduce 的参数是 BinaryOperator,这个接收两个参数,第一个参数是之前计算的结果,第二个参数是本次参与计算的元素,两者累加求和。
  再比如给一段话中间加上.,方式如下:  Optional s = Stream.of("wwwjavaboyorg".split("")).reduce((i, j) -> i + "." + j); System.out.println(s.orElse(""));
  最终执行结果如下:  w.w.w.j.a.v.a.b.o.y.o.r.g
  min/max/count
  这个就比较简单了,就是求最大值最小值,统计总个数,如下表示统计总个数:  Stream s = Stream.of(1, 2, 3, 4); long count = s.count(); System.out.println("count = " + count);
  如下表示统计最小值:  Stream s = Stream.of(1, 2, 3, 4); Optional min = s.min(Comparator.comparingInt(i -> i)); System.out.println("min.get() = " + min.get());
  findFirst/findAny
  这两个就是返回流中的第一个、任意一个元素,findAny 要在并行流中测试才有效果,举个栗子:  for (int i = 0; i < 10; i++) {     Optional first = Stream.of(1, 2, 3, 4).parallel().findFirst();     System.out.println("first.get() = " + first.get()); } System.out.println("============="); for (int i = 0; i < 10; i++) {     Optional first = Stream.of(1, 2, 3, 4).parallel().findAny();     System.out.println("first.get() = " + first.get()); }
  allMatch/anyMatch/noneMatch
  allMatch、anyMatch、noneMatch 用来判断所有元素、任意元素或者没有元素满足给定的条件。这三个方法的参数都是一个 Predicate 接口函数。  boolean b = Stream.of(1, 2, 3, 4).allMatch(i -> i > 5); System.out.println("b = " + b); 6.并行流
  通常情况下,对 Stream 的元素进行处理是单线程的,即一个一个元素进行处理。有时候我们希望可以并行处理 Stream 元素,因为在元素数量非常大的情况,并行处理可以大大加快处理速度。
  把一个普通 Stream 转换为可以并行处理的 Stream 非常简单,只需要用 parallel 方法进行转换:  new Random().ints().limit(50).parallel().forEach(i->{     System.out.println(Thread.currentThread().getName() + "--->" + i); });
  这样数据在后台就是并行打印的。  7.收集器
  收集器可以将计算结果重新整理收集到一个集合中,这个集合可以是一个 List/Set 获取其他,并且还可以在收集的过程中对数据进行处理。
  例如我有一个 users 集合,里边保存了用户数据,用户有 username、age 以及 gender 三个属性,如下代码分别表示:  提取出用户对象中的 age 属性组成新的集合并返回。  提取出用户对象中的 username 属性组成新的集合并返回。  提取出用户对象中的 gender 属性组成新的集合并返回(这里是一个 Set 集合,所以会自动去重)。  List ages = users.stream().map(User::getAge).collect(Collectors.toList()); System.out.println("ages = " + ages); List usernames = users.stream().map(User::getUsername).collect(Collectors.toList()); System.out.println("usernames = " + usernames); Set genders = users.stream().map(User::getGender).collect(Collectors.toSet()); System.out.println("genders = " + genders);
  Collectors.toList()  最终返回的是 ArrayList,Collectors.toSet()  最终返回的是 HashSet。
  如果我们想返回一个 Vector 或者 TreeSet,也是可以的,如下:  List ages = users.stream().map(User::getAge).collect(Collectors.toList()); System.out.println("ages = " + ages); List usernames = users.stream().map(User::getUsername).collect(Collectors.toCollection(Vector::new)); System.out.println("usernames = " + usernames); TreeSet genders = users.stream().map(User::getGender).collect(Collectors.toCollection(TreeSet::new)); System.out.println("genders = " + genders);
  也可以获取某一个字段的统计信息:  IntSummaryStatistics ageStatistics = users.stream().collect(Collectors.summarizingInt(User::getAge)); System.out.println("ageStatistics = " + ageStatistics);
  这个统计信息中包含:总和、最小值、平均值以及最大值等:  ageStatistics = IntSummaryStatistics{count=20, sum=1222, min=9, average=61.100000, max=96}
  还可以对数据进行分块,将男女不同性别统计出来:  Map> map = users.stream().collect(Collectors.partitioningBy(u -> u.getGender().equals("男"))); System.out.println("map = " + map);
  也可以按照性别对数据进行分组,如下:  Map> map2 = users.stream().collect(Collectors.groupingBy(User::getGender)); System.out.println("map2 = " + map2);
  分组后,Map 中的 key 就是性别;分块后,Map 中的 key 就是 true/false。
  再比如统计男女的人数:  Map map2 = users.stream().collect(Collectors.groupingBy(User::getGender,Collectors.counting())); System.out.println("map2 = " + map2);
  好啦,今天我们就先聊这么多~
  原文链接:https://mp.weixin.qq.com/s/cuxnkcfAOLZuxWRmYcnKWg

爱酱游话说INSIDE是你在玩游戏,还是游戏在玩你?如果有人问爱酱最喜欢的独立游戏作品,在我推荐的前五个游戏里一定有INSIDE的名字。该作是由大名鼎鼎的地狱边境(Limbo)制作商Playdead工作室开发的一款3D横版动作冒险游开黑吃鸡用什么手机好!专业游戏手机推荐随着掌机的式微,手机游戏品质的不断提升,手机游戏已经成为当下游戏市场的绝对主力。有预测表示,2021年,手机游戏将占据全球游戏市场59的份额,成长为一个价值千亿美元的市场。庞大的智鼠标垫也可以很嚣张当键盘,鼠标,耳机全都有了光,作为电脑桌面上的常客鼠标垫怎能耐得住寂寞,于是乎鼠标垫也有了光。当国外大厂的鼠标垫动辄几百元时,国产发光鼠标垫的出现正好填补了口袋不充裕玩家的需要。笔2019年初最惨的主播,不是旭旭宝宝,而是组装54万电脑的装机主播网络直播是很多人都喜欢的休闲方式,随着现在手机互联网的快速发展,在手机上看直播的人也是越来越多,在网络直播中我们根据自己的喜好去观看各种类型的内容,包括游戏美食户外美颜等等。最近几王者荣耀3月14日补偿公布,每人送10个皮肤碎片,网友称天美终于良心一回,你觉得呢?王者荣耀3月14日情人节福利,全服玩家送皮肤碎片,还有这等好事?究竟是怎么回事?且来看看闲余电竞馆的详细介绍!可能很多玩家还不知道,那就是王者荣耀官网将在即将到来的3月14号送出1乱世之歌楚留香X天行九歌联动定档3。15金陵聚沙,歌酒留香。楚留香与重磅国漫IP天行九歌联动定档3。15,届时将有全新定制主题玩法开启,更有精致时装全新称号上线。当武侠手游与精品国漫碰撞与融合,会给玩家带来怎样的江湖体验用奶妈平A补兵1000个再下课,不吃鸡不准下课,电竞学校是天堂?哈喽,大家好这里是大能有话说,现在电子竞技发展是越来越红火,而随之而来的就是有很多电子竞技培训学校的诞生,而很多少年,为了完成这些电子竞技梦想,毅然决然的加入了这些电子竞技培训学校穿越火线10年只卖过一次,拥有这一款角色的,起码30岁了今天继续来和大家讲解穿越火线。既然说到了稀有角色,大部分玩家应该都会想起最新所推出的王者复仇,或者是其他的王者角色。不过今天小编来和大家介绍的,却是曾经上架过3次的海豹突击队,拥有暴雪的暗黑不朽与腾讯的拉结尔,你更期待哪一个?很明显更期待暗黑破坏神不朽!不朽还没公测,只在预约阶段的手游,拉结尔则早已开始内测,两者相同的预约有相关礼包。没有公测,所以两个游戏到底哪个好玩,没法去下定论。而关于氪金还是氪命,外服角色不断入驻,两款角色你更钟情于哪一个呢!小伙伴们大噶好,很高兴又和大家见面了。全新外服永久活动终于来了,而活动中备受关注的两款道具就是AK47破空冰刃和全新的外服角色精英部队了。那么这位全新的黑人小哥,也是迄今为止外服入RNG。Letme直播疑似宣布复出救火?称将停播一段时间回报RNG!由于姿态退役Letme休息,前EDG上单AJ在本赛季成为了RNG的先发上单。不过,AJ的表现却始终没达到预期,赛季前期,受制于磨合等多方面的问题,AJ打得很挣扎。随着赛季的进行,A
三国志战略版诸葛亮神机妙算1。4W伤害,打掉对方一半兵力前言本文首发三国志战略版配将君的公众号,未授权禁止抄袭文章到其他平台。作者三国志战略版配将君大家好,我是三战配将君,每天帮配将开荒,和你说求贤令的武将选择,希望能帮到你!三国志战略听场游戏交响音乐会,助你上班有活力新京报国家大剧院新的一周,音乐助你上班有活力,让你工作高效率。本期周一早安曲栏目,挑选的是一场游戏交响音乐会,在这些旋律里,也许有你的游戏回忆。扫码听音乐会。日签设计新京报倪萍游戏交响音乐会由爱尔qvz2中文版平民无尽密籍(1)相信大家打qvz2中文版无尽时,一般只能打到20关左右就打不过了。那么,请看完这个篇攻略。第1点,无尽要带哪些植物?首先要有控制植物。原碗(原始碗豆的简称)是必要的,原碗又能击退又已经绝版的经典大作,未来是否会续作呢亲爱的小伙伴们,大家好,我是你们的大T。虽然现在的热门单机种类很丰富,受到好评的占了大部分,但也有一些单机游戏正处于辉煌的时候,但却突然出现了问题,开始绝版,给无数的玩家留下遗憾。原神突然发布公告,玩家喜出望外,直呼米哈游亲爸爸俗话说宝剑锋从磨砺出梅花香自苦寒来。从最开始Q版角色的崩坏学园2到后来战斗体验相当不错的崩坏3rd,再到游戏综合水平都挺高的原神,作为一名老玩家,米哈游的一路历程也都看在眼中。或许DNF新的装备系统呼之欲出,玩家纷纷献计,百花齐放还是统一?100版本来到末尾,105版本也正式提上了日程,而对于105版本来说,玩家最首要关注的问题只有一个装备系统!按照以往惯例,前一版本通过深渊爆出,后一版本就会通过团本升级,但经历过漩推荐10款耐玩沙盒游戏,方块方舟玩家骑地狱使者黑夜穿梭作为国内外最大的游戏发布平台之一,在Steam上玩家几乎可以找到任何类型的游戏,其中沙盒游戏的数量更是数不胜数。接下来就来为大家推荐十款耐玩的沙盒游戏吧。第一款为方块方舟,这是一款Metaverse元宇宙3A游戏代表STARL完整版路线图解析,最全发展路线总体路线图V2MISSION01全部已经完成STARL代币发布CGCMC上市网站发布白皮书1。0发布元界规划在Unity游戏引擎上开始Metaverse的社区开发又名社区部门聚集社吃鸡时隔312天,经典模式迎来第7张地图,剩余81629个资格欢迎诸位小伙伴们来到天哥开讲的和平精英精英小课堂熟悉这款游戏的老玩家们都知道,目前在经典模式里,一共有6张地图。它们分别是海岛沙漠雨林雪地山谷黄金岛。距离上一次2月2日登场的黄金岛元宇宙龙头SAND为何如此之强?01元宇宙爆火元宇宙很火,而越火泡沫就会越大,但如果理解泡沫拥抱泡沫远离泡沫的顺序不能搞反,否则就会越来越聪明,而别人越来越有钱。SAND是沙盒游戏,类似千万级日活的我的世界的链游RW侠带走AG后输给TTG的原因找到了!原来是阿泰搞的鬼?在最近一段时间由虎牙直播的王者荣耀KPL秋季赛季后赛败者组第2轮正在火热的开展,在12月9日当天,败者组第2轮的对决迎来了广州TTG跟济南RW侠的对决,相信绝大部分观众对于这一场的