许多Java框架类实现Iterable
,但String
没有。迭代String
中的字符是有意义的,就像可以迭代常规数组中的项目一样。
String
没有实现Iterable
的原因是什么?
答案 0 :(得分:24)
确实没有一个好的答案。 Java中的迭代器特别适用于离散项(对象)的集合。您会认为实现String
的{{1}}应该是离散字符的“集合”。相反,它被视为恰好由字符组成的单个实体。
在Java中,似乎迭代器只是真正应用于集合而不是字符串。没有理由这样的方式(我可以告诉你 - 你可能不得不与Gosling或API编写者交谈);它似乎是惯例或设计决定。实际上,没有任何阻止 CharSequence
实施CharSequence
。
也就是说,你可以像这样迭代字符串中的字符:
Iterable
或者:
for (int i = 0; i < str.length(); i++) {
System.out.println(str.charAt(i));
}
或者:
for(char c : str.toCharArray()) {
System.out.println(c);
}
另请注意,由于字符串是不可变的,因此无法修改字符串的字符。 String的可变伴侣是StringBuilder(或旧的StringBuffer)。
修改强>
根据对此答案的评论澄清。我试图解释一个可能的理由为什么"Java 8".chars().forEach(System.out::println);
上没有迭代器。我并不想说这是不可能的;事实上,我认为String
实施CharSequence
是有意义的。
Iterable
提供String
,如果仅在概念上与CharSequence
不同。 String
通常被认为是单个实体,而String
恰恰是:一系列字符。在字符序列上(即CharSequence
上)有一个迭代器是有意义的,但不仅仅是CharSequence
本身。
正如Foxfire在评论中正确指出的那样,String
实现了String
界面,因此类型方面,CharSequence
是String
。在语义上,在我看来,它们是两个独立的东西 - 我可能在这里迂腐,但是当我想到CharSequence
时,我通常认为它是一个恰好由字符组成的单个实体。考虑数字序列String
和数字1, 2, 3, 4
之间的差异。现在考虑字符串1234
和字符序列abcd
之间的差异。我试图指出这种差异。
在我看来,问为什么a, b, c, d
没有迭代器就像问为什么String
没有迭代器,这样你就可以迭代各个数字。
答案 1 :(得分:12)
原因很简单:字符串类比Iterable更老。
显然没有人想要将接口添加到String(这有点奇怪,因为它确实实现了基于完全相同想法的CharSequence)。
然而,由于Iterable返回一个对象,因此有些不完整。所以它必须包裹每个Char返回。
编辑:正如比较:.Net确实支持对String进行枚举,但在.Net中,Iterable也适用于本机类型,因此不需要包装,因为它在Java中是必需的。
答案 2 :(得分:10)
对于它的价值,我的同事Josh Bloch强烈希望将此功能添加到Java 7中:
for (char c : aString) { ... }
和
for (int codePoint : aString) { ... }
这将是循环字符和逻辑字符(代码点)的最简单方法。它不需要使String
实现Iterable
,这将迫使拳击发生。
如果没有这种语言功能,对这个问题不会有一个非常好的答案。他似乎非常乐观地认为他可以做到这一点,但我不确定。
答案 3 :(得分:4)
他们只是忘了这样做。
答案 4 :(得分:2)
使String实现Iterable的一个主要原因是启用简单的for(each)循环,如上所述。因此,不使String实现Iterable的原因可能是天真实现的固有低效率,因为它需要装箱结果。但是,如果生成的迭代器(由String.iterator()返回)的实现是最终的,编译器可以对其进行特殊处理,并生成无需装箱/取消装箱的字节码。
答案 5 :(得分:0)
如果你真的有兴趣在这里迭代:
String str = "StackOverflow";
for (char c: str.toCharArray()){
//here you go
}
答案 6 :(得分:0)
我不确定为什么在2020年仍无法实现这一点,我猜想是在Java中对字符串给予了很多特殊处理(编译器重载了+
运算符,用于字符串连接,字符串文字,存储在公共池中的字符串常量等)中,此功能可能难以实现,或者看起来复杂(从实现者的角度来看,值得付出很多努力)。
另一方面,实现与此相近的工作并不是太多的工作。我在我的一个项目中想要这个,所以我写了这些简单的类:
public class CharIterable implements Iterable<Character> {
public CharIterable(CharSequence seq) {
this.seq = seq;
}
@Override
public Iterator<Character> iterator() {
return new CharIterator(seq);
}
private final CharSequence seq;
}
public class CharIterator implements Iterator<Character> {
public CharIterator(CharSequence sequence) {
this.sequence = sequence;
}
@Override
public synchronized boolean hasNext() {
return position < sequence.length();
}
@Override
public synchronized Character next() {
return sequence.charAt(position++);
}
/**
* Character sequence to iterate over
*/
private final CharSequence sequence;
/**
* Current position of iterator which is the position of the item that
* will be returned by {@link #next()}.
*/
private int position = 0;
}
有了这些,我可以做到:
for (Character c: new CharIterable("This is a test")) {
\\ do something with c
}
现在,对于这么简单的事情来说,这看起来很多了,但是它随后允许将字符串视为可迭代的字符数组,并使用旨在处理事物(列表,集合等)的方法透明地工作。 / p>
答案 7 :(得分:-1)
Iterable
什么? Iterable<Integer>
最有意义,每个元素代表一个Unicode代码点。当我们Iterable<Character>
时,即使toCharArray
也会缓慢而毫无意义。