java 循环遍历字符串_遍历字符串中所有字符的最快方法

第一个更新:在生产环境(不建议使用)中尝试此方法之前,请先阅读以下内容:http : //www.javaspecialists.eu/archive/Issue237.html 从Java 9开始,上述解决方案将不再起作用,因为现在Java默认将字符串存储为byte []。

第二次更新:截至2016年10月25日,在我的AMDx64 8core和源1.8上,使用'charAt'和字段访问之间没有区别。看来jvm已经过充分优化,可以内联和精简任何'string.charAt(n)'调用。

这完全取决于String被检查的时间。如问题所述,如果用于长字符串,则检查字符串的最快方法是使用反射访问char[]字符串的支持。

在64种AMD Phenom II 4核心955 @ 3.2 GHZ(在客户端模式和服务器模式下)上使用9种不同技术(见下文!)对JDK 8(win32和win64)进行完全随机化的基准测试表明,使用String.charAt(n)速度最快字符串,reflection用于访问字符串支持数组的字符串的速度几乎是大型字符串的两倍。

本实验

尝试了9种不同的优化技术。

所有字符串内容都是随机的

以0、1、2、4、8、16等开头的字符串大小为2的倍数的形式进行测试。

每个字符串大小进行1000次测试

每次将测试随机排列。换句话说,每次测试都以随机顺序进行,超过1000次。

整个测试套件都向前和向后进行,以显示JVM预热对优化和时间的影响。

整个套件执行两次,一次在-client模式下,另一个在-server模式下。

结论

-客户端模式(32位)

对于长度为1到256个字符的字符串,呼叫string.charAt(i)胜出率是平均每秒处理1340万到5.88亿个字符。

而且,总体来说,客户端(客户端)和服务器(服务器)的速度提高了5.5%,如下所示:

for (int i = 0; i < data.length(); i++) {

if (data.charAt(i) <= ' ') {

doThrow();

}

}

而不是像这样带有局部最终长度变量:

final int len = data.length();

for (int i = 0; i < len; i++) {

if (data.charAt(i) <= ' ') {

doThrow();

}

}

对于512到256K字符长的长字符串,使用反射访问String的后备数组最快。此技术的速度几乎是String.charAt(i)的两倍(快 178%)。在此范围内的平均速度为每秒11.11亿个字符。

必须提前获取字段,然后可以在库中的不同字符串上重新使用它。有趣的是,与上面的代码不同,使用Field访问,使用本地最终长度变量比在循环检查中使用“ chars.length”要快9%。可以将现场访问设置为最快的方法如下:

final Field field = String.class.getDeclaredField("value");

field.setAccessible(true);

try {

final char[] chars = (char[]) field.get(data);

final int len = chars.length;

for (int i = 0; i < len; i++) {

if (chars[i] <= ' ') {

doThrow();

}

}

return len;

} catch (Exception ex) {

throw new RuntimeException(ex);

}

-server模式下的特殊注释

在我的AMD 64机器上的64位Java机器上,在服务器模式下以服务器模式获得32个字符长的字符串后,现场访问开始获胜。在客户端模式下,只有512个字符的长度才能看到。

同样值得一提的是,当我在服务器模式下运行JDK 8(32位构建)时,无论大小字符串,整体性能都降低了7%。这是JDK 8早期版本的内部版本121 Dec 2013。因此,目前看来,32位服务器模式比32位客户端模式慢。

话虽如此……似乎唯一值得调用的服务器模式是在64位计算机上。否则实际上会影响性能。

对于在-server modeAMD64上运行的32位版本,我可以这样说:

总的来说,String.charAt(i)是明显的赢家。尽管介于8到512个字符之间,但在“新”,“重用”和“领域”中还是赢家。

在客户端模式下,String.charAt(i)的速度提高了45%

在客户端模式下,大型字符串的字段访问速度是后者的两倍。

同样值得一提的是,String.chars()(Stream和并行版本)是破产。比其他任何方式都要慢。该StreamsAPI是执行一般的字符串操作一个相当缓慢的方式。

愿望清单

Java String的谓词可以接受优化的方法,例如contains(predicate),forEach(consumer),forEachWithIndex(consumer)。因此,无需用户知道长度或重复调用String方法,这些方法就可以帮助解析库beep-beep beep加速。

继续做梦:)

快乐的弦!

〜SH

该测试使用以下9种方法测试字符串是否存在空格:

“ charAt1”-检查字符串是否包含通常的方式:

int charAtMethod1(final String data) {

final int len = data.length();

for (int i = 0; i < len; i++) {

if (data.charAt(i) <= ' ') {

doThrow();

}

}

return len;

}

“ charAt2” –与上面相同,但使用String.length()代替了对长度进行最后的本地int

int charAtMethod2(final String data) {

for (int i = 0; i < data.length(); i++) {

if (data.charAt(i) <= ' ') {

doThrow();

}

}

return data.length();

}

“流”-使用新的JAVA-8 String的IntStream并通过它进行检查

int streamMethod(final String data, final IntPredicate predicate) {

if (data.chars().anyMatch(predicate)) {

doThrow();

}

return data.length();

}

“ streamPara”-同样,但是OH-LA-LA-并行!

// avoid this at all costs

int streamParallelMethod(final String data, IntPredicate predicate) {

if (data.chars().paralle

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值