java8コラムディレクトリ:
- java8実際の研究ノート:ラムダ式の構文と関数型プログラミング・インターフェース
- java8実際の研究ノート:コンポジットラムダ式
- java8実際の読書ノート:知人ストリーム、基本的な操作の流れ(フロー計算)
- java8戦闘読書ノート:利用価値ストリームは、ストリームは、オプションのクラスを作成します
- java8研究ノート:データの収集を探検は原則java8の流れ
、ToListメソッドtoSet、toCollection、接合、GROUPBY(グループの複数のレベルを有する)、コア原則を低減し、実施例の使用を実装する:この論文はCollectosは、に焦点を当て、詳細java8コレクタを提供し、コレクタが開始構築します。
操作のコレクション
コレクション操作は、ToListメソッド、toSet、toCollectionが含まれます。まず、ストリーム内のデータは、最終的なセットによって返されるデータの種類を算出します。コレクタは述べコレクションコレクタ3、のように定義されます。
1public静的<T>コレクター<T、?、リスト<T >> ToListメソッド() 2public静的<T>コレクター<T、?、セット<T >> toSet() 3public静的<T、Cが延びコレクション<T >>コレクター<T、?、C> toCollection(サプライヤー<C> collectionFactory)
ヒント:抗再びこれらのコレクターは、そのようなサプライヤー、アキュムレータ、コンバイナ、特性のコア属性の値をプッシュするの理論に基づいて記事の推奨。しかし、特別な注意、ToListメソッド、toCollection並列に実行されているサポートされていますが、toSet()メソッドは、並列動作をサポートしていません。
私たちの例を初めて目には、メニュー内のすべての料理の名前を返すために使用されています:
1public静的ボイドtest_toList(一覧<皿>メニュー){ 2リストの<string>名前= menu.stream()(ディッシュ::のgetName)マップ 3 .collect(Collectors.toList())。 4}
原則ToListメソッドの方法の実現としてされているノートのjava8を読ん:java8フローデータ収集の原則探るも詳細に記載されているが、それはもはやBenpianのハイライトです。
接合
コレクターは、次の3つのオーバーロードされたメソッドを定義します。
1public静的コレクタ<たCharSequence、?、文字列>接合() 2public静的コレクタ<たCharSequence、?、文字列>接合(たCharSequenceデリミタ) 3public静的コレクタ<たCharSequence、?、文字列>(たCharSequenceデリミタ、接合 4のCharSequenceプレフィックスたCharSequenceサフィックス)
2.1参加
1public静的コレクタ接合(){<たCharSequence、文字列?> 2リターン新しいCollectorImpl <たCharSequence、StringBuilderの文字列>( 3のStringBuilder ::新しい、StringBuilderの::アペンド、 4(R1、R2) - > {r1.append( R2);戻りR1;}、 5のStringBuilder ::のtoString、CH_NOID)。 6}
- サプライヤ<A>供給()のStringBuilderの関数で::新しい、すなわちStringBuilderのは、アキュムレータの初期値としてメソッドを作成します。
- BiConsumerアキュムレータアキュムレータ:のStringBuilder ::アペンド、すなわちストリーム要素は、さらに、実行されます。
- BinaryOperator <A>合成合成、appendメソッドは、法令の文字列を呼び出されます。
- コンバータフィニッシャー機能:StringBuilderのための最終目標の累積リターンはなく、String型のターゲットは、その変換するために、StringBuilderの#toStringメソッドを呼び出すので、
- セット<特徴>任意のアクションなしの特性。
方法の役割と結論付けることができる私達上で定義された関数から:ストリームの文字列は、追加の文字要素が動作フローを実行する、例えば、フロー要素、間に区切りがありません。
2.2接合(たCharSequenceデリミタ)
1public静的コレクタ<たCharSequence、文字列?>接合(たCharSequenceデリミタ){ 2リターン接合(区切り、 ""、 ""); 3} 4public静的コレクター<?たCharSequence、文字列>接合(たCharSequence区切り、 5たCharSequenceプレフィックス、 6たCharSequenceサフィックス){ 7戻り新しいCollectorImpl <>( 8() - >新しいStringJoiner(デリミタ、接頭辞、接尾辞)、 9 StringJoiner ::アドオン、StringJoiner ::マージ、 10 StringJoiner ::のtoString、CH_NOID)。 11}
- >新しいStringJoiner(区切り文字、接頭辞、接尾辞)、初期値StringJoinerアキュムレータ - サプライヤー<A>サプライヤーは、()()の関数です。
- BiConsumerアキュムレータアキュムレータ:StringJoiner ::アペンド、すなわちストリーム要素は、さらに、実行されます。
- BinaryOperator <A>コンバイナコンバイナ、StringJoiner ::マージ。
- コンバータフィニッシャー機能:StringBuilderのための最終目標の累積リターンはなく、String型のターゲットは、その変換するために、StringBuilderの#toStringメソッドを呼び出すので、
- セット<特徴>任意のアクションなしの特性。
次のように例のは、以下のとおりです。
関連重合コレクタ
minBy、maxBy、合計、平均、および他の関連する機能は、次の文の主要な方法を含む関連コレクタ重合:
1public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) 2public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) 3public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) 4public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper) 5public static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper) 6public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) 7public static <T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper) 8public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper)
上面这些方法比较简单,下面举个简单的例子介绍其使用:
分组
Collectors提供了3个groupingBy重载方法,我们一个一个来理解。
4.1 从示例入手
我们从其中一个最简单的函数说起,从而慢慢引出
1public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy( 2 Function<? super T, ? extends K> classifier)
- Collector>> 首先我们先来关注该方法的返回值Collector<T, ?, Map<K,List< T>>,其最终返回的数据类型为:Map<K, List< T >>
- Function classifier 分类函数。
示例如下:例如如下是购物车实体类,并且初始化数据如下:
1public class ShopCar { 2 private int id; 3 private int sellerId; 4 private String sellerName; 5 private String goodsName; 6 private int buyerId; 7 private String buyerName; 8 private int num; 9} 10// 初始化数据如下: 11public static List<ShopCar> initShopCar() { 12 return Arrays.asList( 13 new ShopCar(1, 1, "天猫" , "华为手机", 1 , "dingw", 5), 14 new ShopCar(1, 2, "京东" , "华为手机", 2 , "ly", 2), 15 new ShopCar(1, 1, "京东" , "小米手机", 3 , "zhl", 3), 16 new ShopCar(1, 2, "1号店" , "华为手机", 1 , "dingw", 5), 17 new ShopCar(1, 2, "天猫" , "苹果手机", 1 , "dingw", 2) 18 ); 19}
首先我们看一下java8之前的写法:
1public static void test_group_jdk7(List<ShopCar> shopCars) { 2 Map<String, List<ShopCar>> shopBySellerNameMap = new HashMap<>(); 3 for(ShopCar c : shopCars ) { 4 if(shopBySellerNameMap.containsKey( c.getSellerName() )) { 5 shopBySellerNameMap.get(c.getSellerName()).add(c); 6 } else { 7 List<ShopCar> aList = new ArrayList<>(); 8 shopBySellerNameMap.put(c.getSellerName(), aList); 9 aList.add(c); 10 } 11 } 12 print(shopBySellerNameMap); 13}
上面的代码应该很容易理解,根据商家名称进行分组,拥有相同商家的名称的购物车项组成一个集合,最终返回Map>类型的数据。
那如何使用java8的流分组特性来编写对应的代码呢?下面的思考过程非常关键,经过前面的学习,我想大家应该也具备了如下分析与编写的能力?
首先其声明如下:public static Collector>> groupingBy(Function classifier),那在本例中,T,K这两个参数代表什么意思呢?
- T : ShopCar
- K : String (sellerName的类型) 其判断的主要依据为groupingBy方法返回的参数Collector< T, ?, Map< K, List< T>>>,代表< T, A, R>,其中最后一个泛型参数R对应的就是本例需要返回的Map< K, List< T>>,故分析出T,K代表的含义。
然后再看其参数:Function classifier,即接受的函数式编程接口为T -> K,即通过ShopCar 返回一个String,又根据其名称可知,该函数为一个分类函数,故基本可以写成如下代码:
1public static void test_group_jdk8(List<ShopCar> shopCars) { 2 Map<String, List<ShopCar>> shopBySellerNameMap = 3 shopCars 4 .stream() 5 .collect(Collectors.groupingBy(ShopCar::getSellerName)); 6 //.collect(Collectors.groupingBy( (ShopCar c) -> c.getSellerName() )) 7 print(shopBySellerNameMap); 8}
其运行效果如下:
为了加深对groupingBy方法的理解,接下来我们重点分析一下其源码的实现。
4.2 源码分析groupingBy方法
1public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier) { // @1 2 return groupingBy(classifier, toList()); // @2 3}
代码@1:分类参数,已经在上文中详细介绍。
代码@2:调用groupingBy重载方法,传入的参数为toList(),有点意思,传入的参数为Collectors.toList(),结合上文中的示例,需要返回值类为:Map< String, List< ShopCar>>,与这里的List对应起来了。
1public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) { 2 return groupingBy(classifier, HashMap::new, downstream); 3} 该重载方法,再次调用3个参数的groupingBy方法。
1public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy( 2 Function<? super T, ? extends K> classifier, 3Supplier<M> mapFactory, 4Collector<? super T, A, D> downstream) { // @1 5 Supplier<A> downstreamSupplier = downstream.supplier(); // @2 start 6 BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); 7 BiConsumer<Map<K, A>, T> accumulator = (m, t) -> { 8 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 9 A container = m.computeIfAbsent(key, k -> downstreamSupplier.get()); 10 downstreamAccumulator.accept(container, t); 11 }; // @2 end 12 13 BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner()); // @3 14 @SuppressWarnings("unchecked") 15 Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory; 16 17 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { // @4 18 return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID); 19 } 20 else { // @5 21 @SuppressWarnings("unchecked") 22 Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher(); 23 Function<Map<K, A>, M> finisher = intermediate -> { 24 intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); 25 @SuppressWarnings("unchecked") 26 M castResult = (M) intermediate; 27 return castResult; 28 }; 29 return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID); 30 } 31}
代码@1:参数介绍:
- Function classifier 分类函数。
- Supplier< M> mapFactory map构建函数。()-> Map
- Collector downstream 下游收集器,在上面的示例中,该参数为Collectos.toList()。
代码@2:构建最终的累积器。其实现要点如下:
- 对流中的元素,使用Function classifier,获取对应的分类键值。
- 使用mangledFactory创建累积初始值,并调用Map#computeIfAbsent方法,放入的值为:downstreamSupplier.get()。可以类比上例中Map>,请结合如下代码进行理解:
代码@3:构建最终的组合器,这里使用的是Collectos.mapMerger,其内部的实现就是对每个元素,执行map#merge方法。
代码@4:如果收集器的行为为IDENTITY_FINISH,直接根据上面已创建的累积器、组合器,创建一个最终的收集器。
代码@5:如果收集器的行为不包含IDENTITY_FINISH,则需要最终调用原收集器的finisher方法。才能最终需要返回的类型。
groupingBy的原理就讲解到这里,我们接下来思考如下场景: 还是上面的购物车场景,现在要求先按照供应商名称分组,然后按照购买人分组(即多级分组),类似于SQL group by sellerId,buyerId。
思考过程:首先二级分类需要返回的数据类型为Map> >,而只有一个参数的groupingBy(Function classifier),只接受一个分类参数,其内部会调用两个参数的groupingBy(Function classifier,Collector downstream),默认第二个参数为Collectors.toList(),故我们可以做的文章是改变这个默认值,传入符合业务场景的收集器,结合目前的需求,很显然,该参数应该是支持分组的收集器,即应该可以通过嵌套groupingBy方法,实现二级分组,其具体代码如下:
1/** 2 * 二级分组示例 3 * @param shopCars 4 */ 5public static void test_level_group(List<ShopCar> shopCars) { 6 Map<String, Map<String, List<ShopCar>>> result = 7 shopCars.stream().collect(Collectors.groupingBy(ShopCar::getSellerName, 8 Collectors.groupingBy(ShopCar::getBuyerName))); 9 System.out.println(result); 10}
温馨提示:上面介绍的分组,主要的Map存储结构为HashMap,java8为ConcurrentMap对应类继承体系提供了对应的分组函数:groupingByConcurrent,其使用方法与groupingBy方法类型,故不重复介绍。
partitioningBy
分区,分区可以看出是分组的特殊化,接受的分类函数返回boolean类型,即是谓词Predicate predicate。其声明如下:
1public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) 2public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)
由于其用法与分组类似,故这里就一笔带过了。
reducing
规约。其函数声明如下:
1public static <T, U> Collector<T, ?, U> reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op)
其参数如下:
- U identity 规约初始值。
- Function mapper 累加器函数。
- BinaryOperator op 组合器函数。 关于Collectors.reducing,建议可以直接使用Stream自身提供的reducing方法,具体请参考博文:java8实战读书笔记:初识Stream、流的基本操作(流计算)
本文分享自微信公众号 - 中间件兴趣圈(dingwpmz_zjj)
原文出处及转载信息见文内详细说明,如有侵权,请联系 [email protected] 删除。
原始发表时间:2019-06-10
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
点赞 4分享
我来说两句
0 条评论
登录 后参与评论
推荐阅读
-
远程办公经验为0,如何将日常工作平滑过度到线上?
我是一名创业者,我的公司(深圳市友浩达科技有限公司)在2018年8月8日开始运营,现在还属于微型公司。这个春节假期,我一直十分关注疫情动向,也非常关心其对公司带来的影响。
TVP官方团队 11 天前
-
数据中台,概念炒作还是另有奇效? | TVP思享
作者简介:史凯,花名凯哥,腾讯云最具价值专家TVP,ThoughtWorks数据智能业务总经理。投身于企业数字化转型工作近20年。2000年初,在IBM 研发企业级中间件,接着加入埃森哲,为大型企业提供信息化架构规划,设计,ERP,云平台,数据仓库构建等技术咨询实施服务,随后在EMC负责企业应用转型业务,为企业提供云迁移,应用现代化服务。现在专注于企业智能化转型领域,是数据驱动的数字化转型的行业布道者,数据中台的推广者,精益数据创新体系的创始人,2019年荣获全球Data IQ 100人的数据赋能者称号,创业邦卓越生态聚合赋能官TOP 5。2019年度数字化转型专家奖。打造了行业第一个数据创新的数字化转型卡牌和工作坊。创建了精益数据创新方法论体系构建数据驱动的智能企业,并在多个企业验证成功,正在向国内外推广。
TVP官方团队 11 天前
-
扩展 Kubernetes 之 CRI
使用 cri-containerd 的调用流程更为简洁, 省去了上面的调用流程的 1,2 两步
王磊-AI基础 28 天前
-
扩展 Kubernetes 之 Kubectl Plugin
kubectl 功能非常强大, 常见的命令使用方式可以参考 kubectl --help,或者这篇文章
王磊-AI基础 26 天前
-
多种登录方式定量性能测试方案
最近接到到一个测试任务,某服务提供了两种登录方式:1、账号密码登录;2、手机号+验证码登录。要对这两种登录按照一定的比例进行压测。
八音弦 14 天前
-
线程安全类在性能测试中应用
首先验证接口参数签名是否正确,然后加锁去判断订单信息和状态,处理用户增添VIP时间事务,成功之后释放锁。锁是针对用户和订单的分布式锁,使用方案是用的redis。
八音弦 14 天前
-
使用CDN(jsdelivr) 优化博客访问速度
PS: 此篇文章适用于 使用 Github pages 或者 coding pages 的朋友,其他博客也类似.
IFONLY@CUIT 15 天前
-
扩展 Kubernetes 之 CNI
Network Configuration 是 CNI 输入参数中最重要当部分, 可以存储在磁盘上
王磊-AI基础 29 天前
-
聚焦【技术应变力】云加社区沙龙online重磅上线!
云加社区结合特殊时期热点,挑选备受关注的音视频流量暴增、线下业务快速转线上、紧急上线防疫IoT应用等话题,邀请众多业界专家,为大家提供连续十一天的干货分享。从视野、预判、应对等多角度,帮助大家全面提升「技术应变力」!