charAt()或子串? 哪个更快?

我想遍历String中的每个字符,并将String的每个字符作为String传递给另一个函数。

String s = "abcdefg"; for(int i = 0; i < s.length(); i++){ newFunction(s.substring(i, i+1));} 

要么

 String s = "abcdefg"; for(int i = 0; i < s.length(); i++){ newFunction(Character.toString(s.charAt(i)));} 

最终结果必须是String。 那么任何更快或更高效的想法?

像往常一样:没关系,但如果你坚持花时间进行微优化,或者你真的想为你的特殊用例进行优化,试试这个:

 import org.junit.Assert; import org.junit.Test; public class StringCharTest { // Times: // 1. Initialization of "s" outside the loop // 2. Init of "s" inside the loop // 3. newFunction() actually checks the string length, // so the function will not be optimized away by the hotstop compiler @Test // Fastest: 237ms / 562ms / 2434ms public void testCacheStrings() throws Exception { // Cache all possible Char strings String[] char2string = new String[Character.MAX_VALUE]; for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) { char2string[i] = Character.toString(i); } for (int x = 0; x < 10000000; x++) { char[] s = "abcdefg".toCharArray(); for (int i = 0; i < s.length; i++) { newFunction(char2string[s[i]]); } } } @Test // Fast: 1687ms / 1725ms / 3382ms public void testCharToString() throws Exception { for (int x = 0; x < 10000000; x++) { String s = "abcdefg"; for (int i = 0; i < s.length(); i++) { // Fast: Creates new String objects, but does not copy an array newFunction(Character.toString(s.charAt(i))); } } } @Test // Very fast: 1331 ms/ 1414ms / 3190ms public void testSubstring() throws Exception { for (int x = 0; x < 10000000; x++) { String s = "abcdefg"; for (int i = 0; i < s.length(); i++) { // The fastest! Reuses the internal char array newFunction(s.substring(i, i + 1)); } } } @Test // Slowest: 2525ms / 2961ms / 4703ms public void testNewString() throws Exception { char[] value = new char[1]; for (int x = 0; x < 10000000; x++) { char[] s = "abcdefg".toCharArray(); for (int i = 0; i < s.length; i++) { value[0] = s[i]; // Slow! Copies the array newFunction(new String(value)); } } } private void newFunction(String string) { // Do something with the one-character string Assert.assertEquals(1, string.length()); } } 

答案是: 没关系 。

描述您的代码。 这是你的瓶颈吗?

newFunction真的需要一个String吗? 如果你能使newFunction获取一个char并将其调用如下,那会更好:

 newFunction(s.charAt(i)); 

这样,您就可以避免创建临时String对象。

回答你的问题:很难说哪一个更有效率。 在这两个示例中,必须创建一个只包含一个字符的String对象。 哪个更有效取决于在特定的Java实现上如何实现String.substring(...)Character.toString(...) 。 找到它的唯一方法是通过分析器运行程序,并查看哪个版本使用更多CPU和/或更多内存。 通常情况下,您不应该担心像这样的微优化 – 只有在您发现这是性能和/或内存问题的原因时才花时间。

在您发布的两个片段中,我不想说。 我同意Will的观点,它几乎肯定与您的代码的整体性能无关 – 如果不是,您可以进行更改并自行确定哪些是您的硬件上的JVM最快的数据。

也就是说,如果首先将String转换为char数组,然后在数组上执行迭代,那么第二个片段可能会更好。 这样做只会执行一次String开销(转换为数组)而不是每次调用。 此外,您可以使用一些索引将数组直接传递给String构造函数,这比数组中取出char以单独传递它(然后转换为单字符数组)更有效:

 String s = "abcdefg"; char[] chars = s.toCharArray(); for(int i = 0; i < chars.length; i++) { newFunction(String.valueOf(chars, i, 1)); } 

但是为了强调我的第一点,当你看到你在每次调用String.charAt()实际上避免的东西时 - 它是两个边界检查,一个(懒惰)布尔OR和一个加法。 这不会产生任何明显的差异。 String构造函数的区别也不存在。

从本质上讲,两个成语在性能方面都很好(两者都没有立即显然效率低下),所以你不应该花费更多的时间来处理它们,除非探查器显示这会占用你应用程序的大量运行时间。 即便如此,通过重新newFunction此区域中的支持代码,您几乎肯定可以获得更多性能提升(例如,让newFunction获取整个字符串); 到目前为止,java.lang.String得到了很好的优化。

我首先使用String.toCharArray()从源String获取底层char [],然后继续调用newFunction。

但我同意Jesper的意见,如果你能处理字符并避免所有String函数,那将是最好的…