Java8的stream API与 C#的 LINQ 拓展方法对比
为方便初学 Java8/C# 集合操作的人,特意写下这篇文章.
前期准备
单集合
分类筛选
- 计数(Count)
Date time1 = convertLocalDateToTimeZone(LocalDate.of(1990, 1, 1)); //0 Long count1 = list1.stream().filter(o -> o.getBirthday().equals(time1)).count();
int count1 = list1.Where(o => o.Birthday.Equals(new DateTime(1990, 1, 1)) && o.Sex == Sex.Male).Count(); long count2 = list1.Where(o => o.Birthday.Equals(new DateTime(1990, 1, 1)) && o.Sex == Sex.Male).LongCount(); /* 0 0 */
- 分组(GroupBy)
Map<Sex, List<Person>> group1 = list1.stream().collect(Collectors.groupingBy(Person::getSex)); Iterator it = group1.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Sex, List<Person>> groupByItem = (Map.Entry) it.next(); Sex sex = groupByItem.getKey(); out.println(sex); groupByItem.getValue().forEach(person -> { out.println(new Gson().toJson(person)); }); } /* 输出结果: Male {"height":170,"weight":50,"identifier":"2","address":"北京","birthday":"Feb 1, 1982 12:00:00 AM","hobbies":["吃飯","看電影"],"sex":"Male"} Female {"height":165,"weight":50,"identifier":"1","address":"北京","birthday":"Jan 1, 1981 12:00:00 AM","hobbies":["吃飯","逛街"],"sex":"Female"} X {"height":170,"weight":50,"identifier":"3","address":"北京","birthday":"Mar 1, 1983 12:00:00 AM","hobbies":["吃飯","上網"],"sex":"X"} */
var group1 = list1.GroupBy(o => o.Sex); //当我们使用 GroupBy() 扩展方法时,使用了延迟执行。 这意味着,当你遍历集合的时候,下一个要出现的项目可能会或者可能不会被加载。 这是一个很大的性能改进,但它会引起有趣的副作用。 list1.RemoveAll(o => o.Sex == Sex.X);//定义 groupby 集合后对原集合进行修改,会发现group1里面已经没了 Sex=X的分组 foreach (var groupByItem in group1) { Sex sex = groupByItem.Key; System.Console.WriteLine(sex); foreach (Person person in groupByItem) { System.Console.WriteLine(JsonConvert.SerializeObject(person)); } } /* 输出结果: {"Height":165,"Weight":50,"Birthday":"1981-01-01T00:00:00","Hobbies":["吃飯","逛街"],"Identifier":"1","Address":"北京","Sex":2} Male {"Height":170,"Weight":50,"Birthday":"1982-02-01T00:00:00","Hobbies":["吃飯","看電影"],"Identifier":"2","Address":"北京","Sex":1} Female {"Height":165,"Weight":50,"Birthday":"1981-01-01T00:00:00","Hobbies":["吃飯","逛街"],"Identifier":"1","Address":"北京","Sex":2} Male {"Height":170,"Weight":50,"Birthday":"1982-02-01T00:00:00","Hobbies":["吃飯","看電影"],"Identifier":"2","Address":"北京","Sex":1} */ //该 ToLookup() 方法创建一个类似 字典(Dictionary ) 的列表List, 但是它是一个新的 .NET Collection 叫做 lookup。 Lookup,不像Dictionary, 是不可改变的。 这意味着一旦你创建一个lookup, 你不能添加或删除元素。 var group2 = list1.ToLookup(o => o.Sex); foreach (var groupByItem in group2) { Sex sex = groupByItem.Key; foreach (Person person in groupByItem) { System.Console.WriteLine(sex); System.Console.WriteLine(JsonConvert.SerializeObject(person)); } } /* 输出结果: {"Height":165,"Weight":50,"Birthday":"1981-01-01T00:00:00","Hobbies":["吃飯","逛街"],"Identifier":"1","Address":"北京","Sex":3} {"Height":170,"Weight":50,"Birthday":"1982-02-01T00:00:00","Hobbies":["吃飯","看電影"],"Identifier":"2","Address":"北京","Sex":3} */
与此对比,stream没有RemoveAll的操作
- 匹配的第一项(findFirst/First,FirstOrDefault)
Person after90 = list1.stream() .filter(o -> o.getBirthday().after(convertLocalDateToTimeZone(LocalDate.of(1990, 1, 1)))) .findFirst() .orElse(null); // null
var after90 = list1.Where(o => o.Birthday >= new DateTime(1990, 1, 1)).First();//如果结果为空,将会导致异常,所以一般极少使用该方法 //An unhandled exception of type 'System.InvalidOperationException' occurred in System.Linq.dll: 'Sequence contains no elements' after90 = list1.Where(o => o.Birthday >= new DateTime(1990, 1, 1)).FirstOrDefault(); var after00 = list1.Where(o => o.Birthday >= new DateTime(2000, 1, 1)).FirstOrDefault();
- 遍历(ForEach)
list1.stream().forEach(o -> { //在ForEach當中可對集合進行操作 o.setSex(Sex.X); }); list1.forEach(o -> { out.println(new Gson().toJson(o)); }); /* {"height":165,"weight":50,"identifier":"1","address":"北京","birthday":"Jan 1, 1981 12:00:00 AM","hobbies":["吃飯","逛街"],"sex":"X"} {"height":170,"weight":50,"identifier":"2","address":"北京","birthday":"Feb 1, 1982 12:00:00 AM","hobbies":["吃飯","看電影"],"sex":"X"} {"height":170,"weight":50,"identifier":"3","address":"北京","birthday":"Mar 1, 1983 12:00:00 AM","hobbies":["吃飯","上網"],"sex":"X"} */
list1.ForEach(item => { //在ForEach當中可對集合進行操作 item.Sex = Sex.X; }); list1.ForEach(item => { System.Console.WriteLine(JsonConvert.SerializeObject(item)); });
- 极值Max/Min
//IntStream的max方法返回的是OptionalInt,要先判断有没有值再读取值.isPresent=false 时直接getAsInt会报错.mapToLong,mapToDouble同理 OptionalInt maxHeightOption = list1.stream().mapToInt(Person::getHeight).max(); //字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。 //当集合为长度0的集合时会返回起始值Integer.MIN_VALUE,起始值也不能乱传,个中缘由我暂不清楚 int maxHeight = list1.stream().mapToInt(Person::getHeight).reduce(Integer.MIN_VALUE, Integer::max); out.println(maxHeight); if (maxHeightOption.isPresent()) { maxHeight = maxHeightOption.getAsInt(); out.println(maxHeight); } //mapToInt参数的2种写法都一样,我比较喜欢以下写法,但是 idea 会报 warning OptionalInt minWeightOption = list1.stream().mapToInt(o -> o.getHeight()).min(); int minWeight = list1.stream().mapToInt(o -> o.getHeight()).reduce(Integer.MAX_VALUE, Integer::min);
int maxHeight = list1.Select(o => o.Height).Max(); //同 list1.Max(o => o.Height); int minWeight = list1.Min(o => o.Weight);
- 跳过(skip/Skip),截取(limit/Take)
//skip和 limit参数都是long, 这个要注意 list1.stream().skip(1L).limit(2L);
排序
- 去重复(Distinct)
list1.stream().map(Person::getIdentifier).distinct();
list1.Select(o=>o.Identifier).Distinct();
list1.Skip(1).Take(2);
- 升序(sort/OrderBy)
out.println("------------------------------------|升序|------------------------------------"); list1 = list1.stream().sorted(Comparator.comparing(Person::getBirthday)).collect(Collectors.toList()); out.println(new Gson().toJson(list1)); list1 = list1.stream().sorted((left, right) -> left.getBirthday().compareTo(right.getBirthday())).collect(Collectors.toList()); out.println(new Gson().toJson(list1));
//升序 list1 = list1.OrderBy(o => o.Birthday).ToList();
- 降序(sort/OrderByDescending)
out.println("------------------------------------|降序|------------------------------------"); list1 = list1.stream().sorted(Comparator.comparing(Person::getBirthday).reversed()).collect(Collectors.toList()); out.println(new Gson().toJson(list1)); list1 = list1.stream().sorted((left, right) -> right.getBirthday().compareTo(left.getBirthday())).collect(Collectors.toList()); out.println(new Gson().toJson(list1));
//降序 list1 = list1.OrderByDescending(o => o.Birthday).ToList();
多集合
- 交集 list1 ∩ list2
out.println("------------------------------------|交集 list1 ∩ list2|------------------------------------"); list1.stream().filter(o -> list2.contains(o)).collect(Collectors.toList());
//连接,下面表示把 list1和 list2当中相同身份证号的取出来,生成一个新的集合 //实际上, join 有另外的用法,类似 sqlserver 里面的多表连接,将不同数据源结合到一起,生成新的数据结构 var intersect = list1.Join(list2, o => o.Identifier, o => o.Identifier, (a, b) => a).ToList(); //交集 list1 ∩ list2 intersect = list1.Intersect(list2).ToList();
- 并集list1 ∪ list2
out.println("------------------------------------|并集list1 ∪ list2 |------------------------------------"); list1.addAll(list2);
//并集list1 ∪ list2 var union = list1.Union(list2).ToList();
- 差集list1 - list2
out.println("------------------------------------|差集list1 - list2|------------------------------------"); list1.stream().filter(item1 -> !list2.contains(item1)).collect(Collectors.toList());
//差集list1 - list2 var except = list1.Except(list2).ToList();
数据结构转换
out.println("------------------------------------|数据结构转换|------------------------------------"); List<Person> list3 = list1.stream().filter(o -> true).collect(Collectors.toList()); ArrayList<Person> list4 = list1.stream().filter(o -> true).collect(Collectors.toCollection(ArrayList::new)); Set<Person> list5 = list1.stream().filter(o -> true).collect(Collectors.toSet()); Object[] list6 = list1.stream().toArray(); Person[] list7 = list1.stream().toArray(Person[]::new);
//数据结构转换 list1.ToArray(); //注意如果 key 重复,ToDictionary会导致出错 list1.ToDictionary(o => o.Identifier, o => o); list1.ToHashSet();
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
VS下生成与配置静态库与动态库(一)
此处仅以VS2010为例,详细说明一下如何在VS环境下生成和使用C++的静态库与动态库。Qt下生成和使用静态和动态库后续再讲。 首先简单地理解一下静态库与动态库,以及两者的区别。 静态库(.lib): 将.cpp文件中的函数的地址和定义,以及函数之间的链接关系通通打包,生成的一个二进制文件; 动态库(.lib+.dll): 动态库的.lib文件,打包的只是.cpp文件中函数的地址和链接,函数的具体定义打包在*.dll文件中。 联系: 1.二者都不包含函数的声明部分,因此调用这两种库的时候,都需要包含相应的头文件(*.h); 2.静态库和动态库的.lib文件,在生成可执行文件(.exe)的时候,都将被打包进*.exe文件中; 区别: 1.静态库的.lib文件远大于动态库的.lib文件; 2.动态库的.dll文件作为可执行文件.exe的附加文件加入到程序中,一般放在*.exe的同级目录下。 简单地介绍完这两种库,下面来看看在VS下是怎么生成和使用的。 静态库: 生成: 1.新建一个空的Visual Studio 2010 ,Visual C++, Win32 控制台工程,取名...
- 下一篇
在闲鱼,我们如何用Dart做高效后端开发?
作者:闲鱼技术-临耕 背景 像阿里其他技术团队以及业界的做法一样,闲鱼的大多数后端应用都是全部使用java来实现的。java易用、丰富的库、结构容易设计的特性决定了它是进行业务开发的最好语言之一。后端应用中数据的存储、访问、转换、输出虽然都属于后端的范畴,但是其中变更的频率是不同的。通常领域对象确定之后,它的变化是很少的,但是客户端展示的变化很多,导致接口层(或者叫粘连前台和后台的胶水层)的变化非常快。大多数web应用采用统一的技术栈来实现后端,胶水层跟领域层使用统一技术,这样的做法仍然有可以优化的地方: 在预发环境中验证调试比较困难:一方面,每次提交代码、构建、部署、验证的总时间相对较长;另一方面,多人共用一个部署环境,相互干扰(代码冲突和部署冲突),增加了成本。后端开发人员都渴望有一个独立、高效的开发环境,就像开发一个前端页面那样 前
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS关闭SELinux安全模块
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Mario游戏-低调大师作品