如何将for-each循环应用于字符串中的每个字符?


189

因此,我想为字符串中的每个字符进行迭代。

所以我认为:

for (char c : "xyz")

但出现编译器错误:

MyClass.java:20: foreach not applicable to expression type

我怎样才能做到这一点?

Answers:


333

为,每每最简单的方法char在一个String是使用toCharArray()

for (char ch: "xyz".toCharArray()) {
}

这为您提供了for-each构造的简洁性,但是不幸的是String(这是不可变的)必须执行防御性复制才能生成char[](可变的),因此要付出一定的代价。

文档中

[ toCharArray()返回] 一个新分配的字符数组,其长度是此字符串的长度,并且其内容已初始化为包含此字符串表示的字符序列。

还有更多详细的方法可以遍历数组中的字符(常规用于循环CharacterIterator等),但是如果您愿意为此付出代价toCharArray(),则每个方法最简洁。


1
编译器会认识到不需要真实副本并进行适当的优化吗?
Pacerier,2014年

1
@Pacerier不,当前的Java编译器永远不会优化代码。
RAnders00 '02

1
@ RAnders00那么,在这种情况下toCharArray( )被称为3次?
denvercoder9 '16

1
字符串长度211900000为时,完成所需的时间for (char c : str.toCharArray()) { }为〜250ms,完成所需的时间for (char c : charArray) { }为<10ms。当然,这些时间值将取决于硬件,但是可以得出的结论是,一种方法比另一种方法成本高得多。
denvercoder9 '16

7
@RafiduzzamanSonnet:不,toCharArray()不在循环体内;它只被调用一次,然后循环遍历该结果数组。(for-each循环与通用for-loop 有所不同,后者在每次迭代中都会评估停止条件。)
not-just-yeti

50
String s = "xyz";
for(int i = 0; i < s.length(); i++)
{
   char c = s.charAt(i);
}

 


7
OP希望增强循环功能。
AmitG

3
投反对票,因为这不是OP所要求的。尽管这是一个有效的解决方案,但这并不是要问的问题
Sirens

1
无论OP期望什么,它的性能都比我猜的要好。
埃里克·王

9

另一个有用的解决方案,您可以将此字符串作为String数组使用

for (String s : "xyz".split("")) {
    System.out.println(s);
}

优雅,但不幸的是,如果字符串中的任何元素都split()映射到多个Java字符,则将无法正常工作,几乎所有表情符号都是这种情况。例如,您的示例的这种变体将循环四次而不是三次:for (String s : "x😁z".split("")) { System.out.println(s); }
skomisa

5

您需要使用toCharArrayString类的()方法将String对象转换为char数组:

String str = "xyz";
char arr[] = str.toCharArray(); // convert the String object to array of char

// iterate over the array using the for-each loop.       
for(char c: arr){
    System.out.println(c);
}

4

Java 8中,我们可以将其解决为:

String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));    

chars()方法返回doc中IntStream提到的:

返回此序列的int零扩展char值的流。映射到代理代码点的任何字符都将通过未解释的传递。如果在读取流时序列发生突变,则结果不确定。

为什么使用forEachOrdered而不是forEach

的行为forEach是明确不确定的,其中,如果流具有已定义的遇到顺序forEachOrdered,则在此操作时,将按流的遇到顺序对此流的每个元素执行操作。因此forEach,不能保证将保留订单。还要检查这个问题以获取更多信息。

我们也可以使用codePoints()打印,有关更多详细信息,请参见此答案


这会创建多个对象,因此,如果没有一个可能比简单的索引循环效率低的警告,这个答案就无法完成。
toolforger

4

不幸的是Java没有制作String工具Iterable<Character>。这很容易做到。有,StringCharacterIterator但是甚至没有实现Iterator...因此,请自己制作:

public class CharSequenceCharacterIterable implements Iterable<Character> {
    private CharSequence cs;

    public CharSequenceCharacterIterable(CharSequence cs) {
        this.cs = cs;
    }

    @Override
    public Iterator<Character> iterator() {
        return new Iterator<Character>() {
            private int index = 0;

            @Override
            public boolean hasNext() {
                return index < cs.length();
            }

            @Override
            public Character next() {
                return cs.charAt(index++);
            }
        };
    }
}

现在,您可以(某种程度上)轻松运行for (char c : new CharSequenceCharacterIterable("xyz"))...


3

如果您使用Java 8,则可以chars()在上使用String来获取Stream字符a,但是您需要将其int强制转换为a,charchars()返回an IntStream

"xyz".chars().forEach(i -> System.out.print((char)i));

如果将Java 8与Eclipse Collections一起使用,则可以将CharAdapterforEach方法与lambda或方法引用一起使用,以遍历.NET中的所有字符String

Strings.asChars("xyz").forEach(c -> System.out.print(c));

此特定示例也可以使用方法参考。

Strings.asChars("xyz").forEach(System.out::print)

注意:我是Eclipse Collections的提交者。


1

在这种情况下,您也可以使用lambda。

    String s = "xyz";
    IntStream.range(0, s.length()).forEach(i -> {
        char c = s.charAt(i);
    });

-7

对于遍历字符串,您也可以将charAt()其与字符串一起使用。

喜欢 :

String str = "xyz"; // given String
char st = str.charAt(0); // for example we take 0 index element 
System.out.println(st); // print the char at 0 index 

charAt() 是Java中字符串处理的方法,它有助于遍历特定字符的字符串。


2
你知道是什么for (char st: "xyz".toCharArray()) {}
AmitG

这将无法编译。
Maroun

-1脱离主题(主题:针对每个主题),并使用charAt代替charAT
peenut 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.