为什么Java中的String类没有实现Iterable?

时间:2010-05-05 10:57:08

标签: java string iterable

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

String没有实现Iterable的原因是什么?

8 个答案:

答案 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界面,因此类型方面,CharSequenceString。在语义上,在我看来,它们是两个独立的东西 - 我可能在这里迂腐,但是当我想到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也会缓慢而毫无意义。