51

许多 Java 框架类实现Iterable了 ,但String没有。迭代 a 中的字符是有意义的String,就像可以迭代常规数组中的项目一样。

String有没有实施的原因Iterable

4

8 回答 8

29

真的没有很好的答案。Java 中的迭代器特别适用于离散项(对象)的集合。您会认为String实现的 aCharSequence应该是离散字符的“集合”。相反,它被视为恰好由字符组成的单个实体。

在 Java 中,迭代器似乎只真正应用于集合而不是字符串。没有理由这样做(据我所知,您可能必须与 Gosling 或 API 编写者交谈);这似乎是惯例或设计决定。确实,没有什么可以阻止 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);
}

或者:

"Java 8".chars().forEach(System.out::println);

另请注意,您不能就地修改字符串的字符,因为字符串是不可变的。String 的可变伴侣是 StringBuilder(或旧的 StringBuffer)。

编辑

根据对此答案的评论进行澄清。我试图解释为什么String. 我并不是想说这是不可能的。确实,我认为CharSequence实施Iterable.

String提供CharSequence,如果仅在概念上,它与 a 不同String。AString通常被认为是一个单一的实体,而CharSequence恰恰是:一个字符序列。在字符序列(即 on )上有一个迭代器是有意义的CharSequence,但不仅仅是在 aString本身上。

正如 Foxfire 在评论中正确指出的那样,String实现了CharSequence接口,所以类型方面, aString是 a CharSequence。从语义上讲,在我看来它们是两个独立的东西——我可能在这里很迂腐,但当我想到 a 时,String我通常认为它是一个恰好由字符组成的单一实体。1, 2, 3, 4考虑数字序列和数字之间的区别1234abcd现在考虑字符串和字符序列之间的区别a, b, c, d。我试图指出这种差异。

在我看来,问为什么String没有迭代器就像问为什么Integer没有迭代器,这样你就可以迭代各个数字。

于 2010-05-05T11:02:05.053 回答
13

原因很简单:字符串类比 Iterable 更古老。

显然没有人想要将接口添加到 String (这有点奇怪,因为它确实实现了基于完全相同的想法的 CharSequence)。

但是,它会有些低效,因为 Iterable 返回一个 object。所以它必须包装每个返回的 Char。

编辑:作为比较:.Net 确实支持枚举 String,但是在 .Net Iterable 中也适用于本机类型,因此不需要包装,因为它在 Java 中是必需的。

于 2010-05-05T11:11:57.947 回答
12

对于它的价值,我的同事 Josh Bloch 强烈希望将此功能添加到 Java 7:

for (char c : aString) { ... }

for (int codePoint : aString) { ... }

这将是循环遍历字符和逻辑字符(代码点)的最简单方法。它不需要制作Stringimplement Iterable,这将迫使拳击发生。

如果没有该语言功能,就不会有一个很好的答案来解决这个问题。他似乎非常乐观地认为他能做到这一点,但我不确定。

于 2010-05-05T22:56:58.223 回答
3

他们只是忘了这样做。

于 2010-05-26T10:19:51.313 回答
2

如上所述,使 String 实现 Iterable 的主要原因之一是启用简单的 for(each) 循环。因此,不让 String 实现 Iterable 的一个原因可能是天真的实现固有的低效率,因为它需要对结果进行装箱。但是,如果生成的迭代器(由 String.iterator() 返回)的实现是最终的,编译器可以对其进行特殊处理并生成免于装箱/拆箱的字节码。

于 2010-06-04T07:04:04.900 回答
1

如果你真的很想在这里迭代:

String str = "StackOverflow";

for (char c: str.toCharArray()){
     //here you go
}
于 2010-05-05T11:04:15.247 回答
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
}

现在,对于这样一个简单的事情来说,这看起来很多,但它允许将字符串视为可迭代的字符数组,并与旨在处理事物集合(列表、集合等)的方法透明地工作。

于 2020-11-14T06:38:39.247 回答
-1

Iterable什么?Iterable<Integer>最有意义,其中每个元素代表一个 Unicode 代码点。Iterable<Character>当我们有时,即使是缓慢而毫无意义的toCharArray

于 2010-05-05T11:59:23.463 回答