如何将 for-each 循环应用于字符串中的每个字符?
Posted
技术标签:
【中文标题】如何将 for-each 循环应用于字符串中的每个字符?【英文标题】:How do I apply the for-each loop to every character in a String? 【发布时间】:2011-01-27 22:37:03 【问题描述】:所以我想对字符串中的每个字符进行迭代。
所以我想:
for (char c : "xyz")
但我得到一个编译器错误:
MyClass.java:20: foreach not applicable to expression type
我该怎么做?
【问题讨论】:
【参考方案1】:如果您使用 Java 8,则可以在 String
上使用 chars()
来获得 Stream
的字符,但您需要将 int
转换回 char
,因为 chars()
返回一个IntStream
。
"xyz".chars().forEach(i -> System.out.print((char)i));
如果您将 Java 8 与 Eclipse Collections 一起使用,则可以使用带有 lambda 或方法引用的 CharAdapter
类 forEach
方法来迭代 String
中的所有字符。
Strings.asChars("xyz").forEach(c -> System.out.print(c));
这个特定的例子也可以使用方法引用。
Strings.asChars("xyz").forEach(System.out::print)
注意:我是 Eclipse Collections 的提交者。
【讨论】:
【参考方案2】:不幸的是,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 中我们可以这样解决:
String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));
chars() 方法返回IntStream
,如doc 中所述:
返回一个 int 流,对 char 值进行零扩展 顺序。任何映射到代理代码点的字符都会被传递 通过未解释。如果在流发生时序列发生了突变 正在读取,结果未定义。
为什么使用forEachOrdered
而不是forEach
?
forEach
的行为是明确的不确定性,因为forEachOrdered
对该流的每个元素执行操作,如果流具有定义的遇到顺序,则按照 流的遇到顺序 .所以forEach
不保证订单会被保留。另请查看question 了解更多信息。
我们也可以使用codePoints()
进行打印,请参阅此answer 了解更多详情。
【讨论】:
这会创建多个对象,所以这个答案是不完整的,但需要注意的是这可能比简单的索引循环效率低。【参考方案4】:在这种情况下,您也可以使用 lambda。
String s = "xyz";
IntStream.range(0, s.length()).forEach(i ->
char c = s.charAt(i);
);
【讨论】:
【参考方案5】:另一个有用的解决方案,您可以将此字符串用作字符串数组
for (String s : "xyz".split(""))
System.out.println(s);
【讨论】:
优雅,但不幸的是,如果字符串的任何元素split()
映射到多个 Java 字符(几乎所有表情符号都是这种情况),它就不起作用。例如,您的示例的这种变体将循环四次而不是三次:for (String s : "x?z".split("")) System.out.println(s);
【参考方案6】:
对于 Travers 一个字符串,您还可以将 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 中字符串处理的方法,有助于遍历特定字符的字符串。
【讨论】:
你知道for (char st: "xyz".toCharArray())
是什么吗?
-1 离题(主题:for-each),并使用 charAt 代替 charAT【参考方案7】:
String s = "xyz";
for(int i = 0; i < s.length(); i++)
char c = s.charAt(i);
【讨论】:
OP 期待增强的 for 循环。 投了反对票,因为这不是 OP 所要求的。虽然这是一个有效的解决方案,但它完全不是所要求的 不管 OP 期望什么,我猜这比 for-each 的性能要好。【参考方案8】:您需要使用 String 类的toCharArray
() 方法将 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);
【讨论】:
【参考方案9】:在String
中对每个char
进行for-each 的最简单方法是使用toCharArray()
:
for (char ch: "xyz".toCharArray())
这为您提供了 for-each 构造的简洁性,但不幸的是,String
(它是不可变的)必须执行防御性副本以生成 char[]
(它是可变的),因此会有一些成本损失。
来自documentation:
[
toCharArray()
返回]一个新分配的字符数组,它的长度就是这个字符串的长度,其内容被初始化为包含这个字符串所代表的字符序列。
迭代数组中的字符有更详细的方法(常规 for 循环、CharacterIterator
等),但如果您愿意支付费用,toCharArray()
for-each 是最简洁的。
【讨论】:
编译器会认识到不需要真正的副本并应用适当的优化吗? @Pacerier 不,当前的 Java 编译器永远不会优化代码。 @RAnders00 那么,在这种情况下,toCharArray( )
被调用了 3 次?
如果字符串长度为 211900000
,完成 for (char c : str.toCharArray())
所需的时间约为 250 毫秒,而完成 for (char c : charArray)
所需的时间小于 10 毫秒。当然,这些时间值将取决于硬件,但要点是一种方法比另一种方法成本高得多。
@RafiduzzamanSonnet:不,toCharArray()
不在循环体内;它只被调用一次,然后循环遍历该结果数组。 (for-each 循环不同于一般的 for
-loop,后者在每次迭代时评估停止条件。)以上是关于如何将 for-each 循环应用于字符串中的每个字符?的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法在 XSLT 转换中用应用模板替换 for-each?