在Java中迭代字符串字符的方法有:

使用StringTokenizer ? 将String转换为char[]并对其进行迭代。

最简单/最好/最正确的迭代方法是什么?


当前回答

我不会使用StringTokenizer,因为它是JDK遗留的类之一。

javadoc说:

StringTokenizer是一个遗留类 出于兼容性原因而保留 尽管在new中不鼓励使用 代码。建议任何人 查找此功能,请使用 的split方法 regex包代替。

其他回答

这里有一些专门的类:

import java.text.*;

final CharacterIterator it = new StringCharacterIterator(s);
for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
   // process c
   ...
}

我使用一个for循环来迭代字符串,并使用charAt()来获取每个字符以检查它。由于String是用数组实现的,charAt()方法是一个常量时间操作。

String s = "...stuff...";

for (int i = 0; i < s.length(); i++){
    char c = s.charAt(i);        
    //Process char
}

这就是我要做的。对我来说这似乎是最简单的。

至于正确性,我不相信这里存在。这完全取决于你的个人风格。

如果需要性能,那么必须在环境中进行测试。没有别的办法。

下面是示例代码:

int tmp = 0;
String s = new String(new byte[64*1024]);
{
    long st = System.nanoTime();
    for(int i = 0, n = s.length(); i < n; i++) {
        tmp += s.charAt(i);
    }
    st = System.nanoTime() - st;
    System.out.println("1 " + st);
}

{
    long st = System.nanoTime();
    char[] ch = s.toCharArray();
    for(int i = 0, n = ch.length; i < n; i++) {
        tmp += ch[i];
    }
    st = System.nanoTime() - st;
    System.out.println("2 " + st);
}
{
    long st = System.nanoTime();
    for(char c : s.toCharArray()) {
        tmp += c;
    }
    st = System.nanoTime() - st;
    System.out.println("3 " + st);
}
System.out.println("" + tmp);

在Java网上,我得到:

1 10349420
2 526130
3 484200
0

在Android x86 API 17上,我得到:

1 9122107
2 13486911
3 12700778
0

如果你需要遍历字符串的代码点(见这个答案),一个更短/更可读的方法是使用Java 8中添加的CharSequence#codePoints方法:

for(int c : string.codePoints().toArray()){
    ...
}

或者直接使用流而不是for循环:

string.codePoints().forEach(c -> ...);

如果你想要字符流,还有CharSequence#chars(尽管它是IntStream,因为没有CharStream)。

StringTokenizer完全不适合将字符串分解为单个字符的任务。使用String#split(),你可以通过使用一个不匹配的正则表达式轻松做到这一点,例如:

String[] theChars = str.split("|");

但是StringTokenizer不使用正则表达式,并且没有可以指定的分隔符字符串来匹配字符之间的空白。你可以使用一个可爱的小技巧来完成同样的事情:使用字符串本身作为分隔符字符串(使其中的每个字符都成为分隔符),并让它返回分隔符:

StringTokenizer st = new StringTokenizer(str, str, true);

但是,我只是为了排除它们而提到这些选项。这两种技术都将原始字符串分解为单字符字符串,而不是char原语,并且都以对象创建和字符串操作的形式涉及大量开销。与在for循环中调用charAt()相比,后者几乎没有开销。