当前位置: 首页 > news >正文

网站建设优化开发公司哪家好沈阳网站制作培训

网站建设优化开发公司哪家好,沈阳网站制作培训,正规的编程培训机构,政务网站建设论文本章内容口用co1lectors类创建和使用收集器 口将数据流归约为一个值 口汇总:归约的特殊情况 数据分组和分区口 口 开发自己的自定义收集器 我们在前一章中学到#xff0c;流可以用类似于数据库的操作帮助你处理集合。你可以把Java8的流看作花哨又懒惰的数据集迭代器。它们… 本章内容口用co1lectors类创建和使用收集器 口将数据流归约为一个值 口汇总:归约的特殊情况 数据分组和分区口 口 开发自己的自定义收集器     我们在前一章中学到流可以用类似于数据库的操作帮助你处理集合。你可以把Java8的流看作花哨又懒惰的数据集迭代器。它们支持两种类型的操作:中间操作(如fi1ter或map)和终端操作(如count、findrirst、forEach和reduce)。中间操作可以链接起来将一个流转换为另一个流。这些操作不会消耗流其目的是建立一个流水线。与此相反终端操作会消耗流以产生一个最终结果例如返回流中的最大元素。它们通常可以通过优化流水线来缩短计算时间。 我们已经在第4章和第5章中用过co11ect终端操作了当时主要是用来把stream中所有的元素结合成一个List。在本章中你会发现co1lect是一个归约操作就像reduce一样可以接受各种做法作为参数将流中的元素累积成一个汇总结果。具体的做法是通过定义新的Co1lector接口来定义的因此区分collection、collector和co1lect是很重要的。下面是一些查询的例子看看你用collect和收集器能够做什么。口对一个交易列表按货币分组获得该货币的所有交易额总和(返回一个MapcurrencyInteger)口将交易列表分成两组:贵的和不贵的(返回一个MapBoolean,ListTransaction)。口创建多级分组比如按城市对交易分组然后进一步按照贵或不贵分组(返回一个MapBoolean,ListTransaction激动吗?很好我们先来看一个利用收集器的例子。想象一下你有一个由Transaction构成的List并且想按照名义货币进行分组。在没有Lambda的Java里哪怕像这种简单的用例实现起来都很啰嗦就像下面这样。 6.1 收集器简介     前一个例子清楚地展示了函数式编程相对于指令式编程的一个主要优势:你只需指出希望的结果--“做什么”而不用操心执行的步骤--“如何做”。在上一个例子里传递给collect方法的参数是co1lector接口的一个实现也就是给stream中元素做汇总的方法。上一章里的toList只是说“按顺序给每个元素生成一个列表”;在本例中groupingBy说的是“生成一个Map它的键是(货币)桶值则是桶中那些元素的列表”。 要是做多级分组指令式和函数式之间的区别就会更加明显:由于需要好多层嵌套循环和条件指令式代码很快就变得更难阅读、更难维护、更难修改。相比之下函数式版本只要再加上一个收集器就可以轻松地增强功能了你会在6.3节中看到它。6.1.1 收集器用作高级归约 刚刚的结论又引出了优秀的函数式API设计的另一个好处:更易复合和重用。收集器非常有用因为用它可以简洁而灵活地定义co1lect用来生成结果集合的标准。更具体地说对流调用co1lect方法将对流中的元素触发一个归约操作(由co1lector来参数化)。图6-1所示的归约操作所做的工作和代码清单6-1中的指令式代码一样。它遍历流中的每个元素并让collector进行处理。 一般来说,collector会对元素应用一个转换函数(很多时候是不体现任何效果的恒等转换,例如toList)并将结果累积在一个数据结构中从而产生这一过程的最终输出。例如在前面所示的交易分组的例子中转换函数提取了每笔交易的货币随后使用货币作为键将交易本身 累积在生成的Map中。如货币的例子中所示collector接口中方法的实现决定了如何对流执行归约操作。我们会在6.5节和6.6节研究如何创建自定义收集器。但co1lectors实用类提供了很多静态工厂方法可以方便地创建常见收集器的实例只要拿来用就可以了。最直接和最常用的收集器是toList静态方法它会把流中所有的元素收集到一个ist中:   ListTransactiontransactionstransactiongtream.collect(Collectors.toList()) 6.1.2 预定义收集器 在本章剩下的部分中我们主要探讨预定义收集器的功能也就是那些可以从co1lectors类提供的工厂方法(例如groupingBy)创建的收集器。它们主要提供了三大功能:口将流元素归约和汇总为一个值 口 元素分组 口 元素分区 我们先来看看可以进行归约和汇总的收集器。它们在很多场合下都很方便比如前面例子中提到的求一系列交易的总交易额。 然后你将看到如何对流中的元素进行分组同时把前一个例子推广到多层次分组或把不同 的收集器结合起来对每个子组进行进一步归约操作。我们还将谈到分组的特殊情况“分区”即使用谓词(返回一个布尔值的单参数函数)作为分组函数。 6.4节末有一张表总结了本章中探讨的所有预定义收集器。在6.5节你将了解更多有关co1lector接口的内容。在6.6节中你会学到如何创建自己的自定义收集器用于co1lectors类的工厂方法无效的情况。6.2 归约和汇总 为了说明从Collectors工厂类中能创建出多少种收集器实例我们重用一下前一章的例包含一张佳看列表的菜单! 就像你刚刚看到的,在需要将流项目重组成集合时,一般会使用收集器( stream方法co1lect的参数)。再宽泛一点来说但凡要把流中所有的项目合并成一个结果时就可以用。这个结果可以是任何类型可以复杂如代表一棵树的多级映射或是简单如一个整数--也许代表了菜单的热量总和。这两种结果类型我们都会讨论:6.2.2节讨论单个整数6.3.1节讨论多级分组。我们先来举一个简单的例子利用counting工厂方法返回的收集器数一数菜单里有多少种菜: long howManyDishes menu.stream().collect (Collectors .counting()); 这还可以写得更为直接: long howManyDishes menu.stream().count() counting收集器在和其他收集器联合使用的时候特别有用后面会谈到这一点。在本章后面的部分我们假定你已导人了co1lectors类的所有静态工厂方法: import static java.util.stream.Collectors.*;这样你就可以写counting()而用不着写collectors.counting()之类的了。让我们来继续探讨简单的预定义收集器看看如何找到流中的最大值和最小值。6.2.1 查找流中的最大值和最小值 假设你想要找出菜单中热量最高的菜。你可以使用两个收集器Collectors.maxBy和Collectors.minBy来计算流中的最大或最小值。这两个收集器接收一个comparator参数来比较流中的元素。你可以创建一个comparator来根据所含热量对菜看进行比较并把它传递给Collectors .maxBy:   ComparatorDishdishCaloriesComparatorComparator.comparingInt(Dish::getCalories): Optiona1lDishmostCalorieDishmenu.stream() .collect(maxBy(dishCaloriesComparator)); 你可能在想optionalDish是怎么回事。要回答这个问题我们需要问“要是menu为空怎么办”。那就没有要返回的菜了!Java8引|人了optiona1它是一个容器可以包含也可以不包含值。这里它完美地代表了可能也可能不返回菜看的情况。我们在第5章讲findAny方法的时候简要提到过它。现在不用担心我们专门用第10章来研究optionalT及其操作。另一个常见的返回单个值的归约操作是对流中对象的一个数值字段求和。或者你可能想要求平均数。这种操作被称为汇总操作。让我们来看看如何使用收集器来表达汇总操作。 6.2.3 连接字符串 joining工厂方法返回的收集器会把对流中每一个对象应用tostring方法得到的所有字符串连接成一个字符串。这意味着你把菜单中所有菜看的名称连接起来如下所示: String shortMenu menu.stream().map(Dish::getName).collect (joining()); 请注意joining在内部使用了stringBuilder来把生成的字符串逐个追加起来。此外还要注意如果Dish类有一个tostring方法来返回菜看的名称那你无需用提取每一道菜名称的函数来对原流做映射就能够得到相同的结果: String shortMenu menu.stream().collect(joining()); 二者均可产生以下字符串: porkbeefchickenfrench friesriceseason fruitpizzaprawnssalmon 但该字符串的可读性并不好。幸好joining工厂方法有一个重载版本可以接受元素之间的分界符这样你就可以得到一个逗号分隔的菜看名称列表: String shortMenu menu.stream().map(Dish::getName) .collect (joining(,)); 正如我们预期的那样它会生成: pork,beef,chicken,french fries,rice,season fruit,pizza,prawns, salmon 到目前为止我们已经探讨了各种将流归约到一个值的收集器。在下一节中我们会展示为什么所有这种形式的归约过程其实都是co1lectors.reducing工厂方法提供的更广义归约收集器的特殊情况。 6.2.4 广义的归约汇总 事实上我们已经讨论的所有收集器都是一个可以用reducing工厂方法定义的归约过程的特殊情况而已。co11ectors.reducing工厂方法是所有这些特殊情况的一般化。可以说先前讨论的案例仅仅是为了方便程序员而已。(但是请记得方便程序员和可读性是头等大事!)例如可以用reducing方法创建的收集器来计算你菜单的总热量如下所示: int totalCalories menu.stream().collect(reducing(0Dish::getCalories(ij)-i j)) 它需要三个参数。口第一个参数是归约操作的起始值也是流中没有元素时的返回值所以很显然对于数值和而言0是一个合适的值。口第二个参数就是你在6.2.2节中使用的函数将菜看转换成一个表示其所含热量的int。 口第三个参数是一个Binaryoperator将两个项目累积成一个同类型的值。这里它就是对两个int求和。同样你可以使用下面这样单参数形式的reducing来找到热量最高的菜如下所示: OptionalDishmostCalorieDish menu.stream().collect(reducing((d1,d2)-dl.getCalories()d2.getCalories()?d1 :d2)); 你可以把单参数reducing工厂方法创建的收集器看作三参数方法的特殊情况它把流中的第一个项目作为起点把恒等函数(即一个函数仅仅是返回其输入参数)作为一个转换函数。这也意味着要是把单参数reducing收集器传递给空流的co1lect方法收集器就没有起点;正如我们在6.2.1节中所解释的它将因此而返回一个optionalpish对象。收集与归约 在上一章和本章中讨论了很多有关归约的内容。你可能想知道stream接口的collect和reduce方法有何不同因为两种方法通常会获得相同的结果。例如你可以像下面这样使用reduce方法来实现toListCollector所做的工作:   StreamIntegerstreamArrays.asList(l2,3,456).stream();ListIntegernumbersstream.reduce( new rrayListInteger() (ListIntegerlInteger e)-{1 .add(e); return li } (ListInteger1lListInteger12)-{ 11.addд11(12); return 11;}); 这个解决方案有两个问题:一个语义问题和一个实际问题。语义问题在于reduce方法旨在把两个值结合起来生成一个新值它是一个不可变的归约。与此相反collect方法的设计就是要改变容器从而累积要输出的结果。这意味着上面的代码片段是在滥用reduce方法因为它在原地改变了作为累加器的List。你在下一章中会更详细地看到以错误的语义使用reduce方法还会造成一个实际问题:这个归约过程不能并行工作因为由多个线程并发修改同一个数据结构可能会破坏List本身。在这种情况下如果你想要线程安全就需要每次分配一个新的List而对象分配又会影响性能。这就是co1lect方法特别适合表达可变容器上的归约的原因更关键的是它适合并行操作本章后面会谈到这一点。 1.收集框架的灵活性:以不同的方法执行同样的操作你还可以进一步简化前面使用reducing收集器的求和例子--引用Integer类的sum方法而不用去写一个表达同一操作的Lammbda表达式。这会得到以下程序: int totalCalories menu.stream().collect(reducing(0,4-- 初始值Dish::getCalories,◁-转换函数Integer::sum))i4- 累积函数 从逻辑上说归约操作的工作原理如图6-3所示:利用累积函数把一个初始化为起始值的累加器和把转换函数应用到流中每个元素上得到的结果不断迭代合并起来。 6.3 分组 一个常见的数据库操作是根据一个或多个属性对集合中的项目进行分组。就像前面讲到按货币对交易进行分组的例子一样如果用指令式风格来实现的话这个操作可能会很麻烦、啰嗦而且容易出错。但是如果用Java8所推崇的函数式风格来重写的话就很容易转化为一个非常容易看懂的语句。我们来看看这个功能的第二个例子:假设你要把菜单中的菜按照类型进行分类有肉的放一组有鱼的放一组其他的都放另一组。用collectors.groupingBy工厂方法返回的收集器就可以轻松地完成这项任务如下所示: MapDish.Type,ListDishdishesByType menu.stream().collect(groupingBy(Dish::getType)); 其结果是下面的Map: (FISHlprawns,salmon],0THER[french fries,rice,season fruit,pizza],MEAT[pork,beef,chickenl} 这里你给groupingBy方法传递了一个Function(以方法引用的形式)它提取了流中每:道Dish的Dish.ype。我们把这个Function叫作分类函数因为它用来把流中的元素分成不同的组。如图6-4所示分组操作的结果是一个ap把分组函数返回的值作为映射的键把流中所有具有这个分类值的项目的列表作为对应的映射值。在菜单分类的例子中键就是菜的类型 但是分类函数不一定像方法引用那样可用,因为你想用以分类的条件可能比简单的属性访问器要复杂。例如你可能想把热量不到400卡路里的菜划分为“低热量”(diet)热量400到700卡路里的菜划为“普通”(normal)高于700卡路里的划为“高热量”(fat)。由于pish类的作者没有把这个操作写成一个方法你无法使用方法引用但你可以把这个逻辑写成Lambda表达式: public enum CaloricLevel(DIETNORMALFAT MapCaloricLevel,ListDish dishesByCaloricLevel menu.stream().collect (groupingBy(dishif (dish.getCalories() 400)return CaloricLevel.DIET;else if (dish.getCalories() 700)return CaloricLeve1.NORMAL: else returnaricevel.FT: 现在你已经看到了如何对菜单中的菜看按照类型和热量进行分组但要是想同时按照这两个标准分类怎么办呢?分组的强大之处就在于它可以有效地组合。让我们来看看怎么做。 6.4 分区 分区是分组的特殊情况:由一个谓词(返回一个布尔值的函数)作为分类函数它称分区函数。分区函数返回一个布尔值这意味着得到的分组Map的键类型是Boolean于是它最多可以分为两组--true是一组false是一组。例如如果你是素食者或是请了一位素食的朋友来共进晚餐可能会想要把菜单按照素食和非素食分开: 分区函数 MapBoolean,ListDish partitionedMenumenu.stream().collect(partitioningBy(Dish::isVegetarian)); 这会返回下面的Map: falselpork,beef,chicken,prawns,salmon]truelfrench fries,rice,season fruit,pizza]} 那么通过Map中键为true的值就可以找出所有的素食菜看了 ListDish vegetarianDishes partitionedMenu.get(true); 请注意,用同样的分区谓词,对菜单ist创建的流作筛选,然后把结果收集到另外一个List中也可以获得相同的结果: ListDish vegetarianDishes menu.stream().filter(Dish::isVegetarian).collect (toList());
http://www.w-s-a.com/news/712833/

相关文章:

  • 湖南省住房和城乡建设厅门户网站网站建设课程性质
  • 如何设计公司网站公司网站空间要多大
  • 建筑公司网站排名5G网站建设要多少个
  • seo怎样新建网站弹簧东莞网站建设
  • 在线做爰直播网站石家庄房产
  • 建筑网站哪里找拓者设计吧首页
  • 广州网站的建设wordpress注册数学验证码
  • 装修平台自己做网站有几个黄页名录网站开发
  • php网站的安全优势平面设计师培训
  • 乐清市网站建设设计重庆沙坪坝区
  • 什么是seo站内优化开发网页的工具有哪些
  • 文化类网站是不是休闲娱乐类网站青州市建设局网站
  • 网站的中英文切换代码做现货黄金网站
  • 万江区网站建设公司前端如何根据ui设计写页面
  • 宿迁公司做网站手机免费创建网站的软件
  • 免费可商用素材网站山东威海网站开发
  • 建设网站什么语言比较合适柳州建设网经济适用房
  • 企业网站的主要功能板块平台推广是做什么的
  • 网页网站自做全搞定西安建设工程信息网诚信平台
  • 网站vip怎么做建网站外包公司
  • 胶州建网站域名不备案可以正常使用吗
  • 网站建设客户开发方案软件工程师行业分析
  • 沈阳网站建设黑酷科技微信小程序怎么一键删除
  • 做网站产品搜索展示实现西安百度推广服务公司
  • 建立网站接受投注是什么意思一般使用的分辨率的显示密度是多少
  • 怎么建立一个网站开展业务网站建设人员的工资分配
  • 求职网站建设方案企业网站开发需求分析
  • 西安企业网站开发可以做哪些有趣的网站
  • 房产类网站开发云南百度建站
  • 泰州网站建设电话彩票网站怎么做代理