Java 丢了好多年,最近在拣起来,首先当然是了解这么多年来它的变化,于是发现了 Java 8 的java.util.stream。在学习和试验的过程中,相比较于 C# 和 javascript,有那么些心得,作文以记之。
早些时间写过一篇《ES6 的 for..of 和 Generator,从伪数组 jQuery 对象说起》,和这个主题有点关系。其实我记得还有一篇讲 C# 的,没找到,也许只是想过,没写成,成了虚假记忆。
前言
之所以把 C#、JavaScript 和 Java 三种语言的实现写在一起,主要是为了放在一起有一个类比,可能会有助于理解。
集合数据
C# 的集合数据基类是 Collection,它实现了 ICollection接口,而 ICollection 又从 IEnumerable 接口继承——实际上要讨论的内容都基于 IEnumerable 接口。另外还有一个非泛型的 IEnumerable 接口,不过建议大家尽量使用泛型,所以这个非泛型的接口就当我没说。顺便提一句,数组也是实现了 IEnumerable 接口的。System.Linq 中提供的扩展大大方便了集合处理过程。
JavaScript 最常见的集合数据类型就是数组,自 ES6 发布以后,这个范围扩展到了 iterable 对象。不过这里要讨论的内容都是在 Array.prototype 中实现的。除此之外,underscore、lodash 这些第三方库中也实现了很多集合数据处理的方法,但不在本文讨论内容之内。
Java 的集合类型由 Collection 接口定义。本文讨论的内容是 Java 8 的特性,在 java.util.stream 包中实现,由 Collection.stream() 引入。
示例语言版本
后面示例中的部分 C# 语句可能需要支持 6.0 语言版本的编译器,如 Visual Studio 2015 或者 Visual Studio "15"
JavaScript 代码都使用了 ES6 语法,目前大部分浏览器支持,Node 5 也完全支持。
Java 要求 Java 8(或 1.8)版本
遍历
问题提出
给定一个名称列表,数组类型, ["Andy", "Jackson", "Yoo"],要求遍历出到的控制台。
C# 的遍历
对于集合来说,最常用的就是遍历,不过 for,foreach, while 之类大家都耳熟能详了,不再多说。这里说的是 forEach() 方法。
很遗憾,C# 的 Linq 扩展 里没有提供 ForEach() 方法,不过 All(IEnumerable, Func) 和 Any(IEnumerable, Func) 都可以代替。这两个方法的区别就在于第二个参数 Func 的返回值。这两个方法都会遍历集合,对集合中的每个元素依次调用第二个参数,Func 所指的委托方法,并检查其返回值,All() 检查到 false 中止遍历,而 Any() 检查到 true 中止遍历。
All() 的意思是,所有元素都符合条件则返回 true,所有只要有一个不符合条件,返回了 false,则中止遍历,返回 false;Any() 的意思是只要发现有元素符合条件则返回 true。
Func 是一个公用委托。Func<...> 系列公用委托都用于委托带有返回值的的方法,所有 Func<... tresult> 都是最后一个参数 TResult 代表返回值类型。
因此,C# 的遍历输出可以这样实现
string[] names = { "Andy", "Jackson", "Yoo" };
names.All(name => {
Console.WriteLine(name);
return true;
});
string[] names = { "Andy", "Jackson", "Yoo" };
names.Any(name => {
Console.WriteLine(name);
return false;
});
有 Lambda 就是好
JavaScript 的遍历
JavaScript 的 Array 实现了 forEach 实例方法,即 Array.prototype.forEach()。
对于 JavaScript 的数组,可以这样遍历
var names = ["Andy", "Jackson", "Yoo"];
names.forEach(name => {
console.log(name);
});
对于 JavaScript 的伪数组,可以这样
var names = {
0: "Andy",
1: "