为什么Java中的String类没有实现Iterable?
许多Java框架类实现Iterable
,但String
不。 迭代String
字符是有意义的,就像迭代常规数组中的项一样。
String
没有实现Iterable
的原因吗?
真的没有一个好的答案。 Java中的迭代器特别适用于离散项目(对象)的集合。 你会认为一个实现CharSequence
的String
应该是离散字符的“集合”。 相反,它被视为恰好由字符组成的单个实体。
在Java中,似乎迭代器只适用于集合而不是string。 没有理由为什么会这样(接近我可以告诉 – 你可能必须与高斯林或API作家谈话); 它似乎是约定或devise决定。 事实上,没有什么能够阻止 CharSequence
实现Iterable
。
也就是说,你可以迭代string中的字符,如下所示:
for (int i = 0; i < str.length(); i++) { System.out.println(str.charAt(i)); }
要么:
for(char c : str.toCharArray()) { System.out.println(c); }
要么:
"Java 8".chars().forEach(System.out::println);
另外请注意,您不能修改string的字符,因为string是不可变的。 String的可变伴侣是StringBuilder(或更老的StringBuffer)。
编辑
根据对这个答案的评论来澄清。 我试图解释为什么在String
上没有Iterator 可能的基本原理 。 我不是想说这是不可能的; 实际上我认为CharSequence
实现Iterable
有意义的。
String
提供了CharSequence
,它只是在概念上与String
不同。 一个String
通常被认为是一个单一的实体,而CharSequence
恰恰是:一个字符序列。 在字符序列上(即在CharSequence
)有一个迭代器是有意义的,但不能简单地在String
本身上。
正如Foxfire在评论中正确地指出的那样, String
实现了CharSequence
接口,所以type-wise是一个CharSequence
。 在语义上,在我看来,它们是两个单独的东西 – 我可能在这里是迂腐的,但是当我想到一个String
我通常把它看作是一个单一的实体,恰好由字符组成。 考虑数字1, 2, 3, 4
和数字1234
之间的区别。 现在考虑stringabcd
和字符序列a, b, c, d
之间的区别。 我试图指出这种差异。
在我看来,问为什么String
没有一个迭代器就像问为什么Integer
没有一个迭代器,以便您可以遍历个别数字。
原因很简单:string类比Iterable旧。
显然没有人想把接口添加到String(这有点奇怪,因为它实现了基于完全相同的想法的CharSequence)。
然而,这将是有点不足,因为Iterable返回一个对象 。 所以它将不得不包裹每个字符返回。
编辑:就像比较:.Net不支持在string上枚举,但是在.net中Iterable也可以在本地types上工作,所以没有必要的包装,因为它需要在Java中。
值得一提的是,我的同事Josh Bloch强烈希望将这个特性添加到Java 7中:
for (char c : aString) { ... }
和
for (int codePoint : aString) { ... }
这将是循环字符和逻辑字符(代码点)的最简单的方法。 它不需要使String
实现Iterable
,这将迫使Boxing发生。
没有这种语言function,这个问题就不会有很好的答案。 他似乎很乐观,他可以得到这个发生,但我不知道。
他们只是忘了这么做。
如果你真的有兴趣在这里迭代:
String str = "StackOverflow"; for (char c: str.toCharArray()){ //here you go }
使String实现为Iterable的主要原因之一是为了简化(each)循环,如上所述。 所以,没有把String实现为Iterable的原因可能是天真实现的内在低效率,因为它需要装箱结果。 但是,如果由String.iterator()返回的结果迭代器的实现是最终的,编译器可以对它进行特殊处理并生成无装箱/拆箱的字节码。
什么是可Iterable
的? Iterable<Integer>
是最有意义的,每个元素代表一个Unicode代码点。 甚至当我们需要toCharArray
时候, Iterable<Character>
也是缓慢而毫无意义的。