专栏首页Java技术栈你只会用 split?试试 StringTokenizer,性能可以快 4 倍!!

你只会用 split?试试 StringTokenizer,性能可以快 4 倍!!

我们都知道,分割字符串要使用 String 的 split() 方法,split 方法虽然深入人心,使用也简单,但效率太低!

其实在 JDK 中,还有一个性能很强的纯字符串分割工具类:StringTokenizer

这个类在 JDK 1.0 中就推出来了,但在实际工作却发现很少有人使用,网上有人说不建议使用了,甚至还有人说已经废弃了,真的是这样吗?

StringTokenizer 被废弃了吗?

栈长翻阅了一些资料,原来在 Oracle JDK 官方文档中已经有了描述,这是最新的 Oracle JDK 15 的官方文档关于 StringTokenizer 的说明:

StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.

参考:https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/StringTokenizer.html

StringTokenizer 原来是一个遗留类,并未被废弃,只是出于兼容性原因而被保留,在新代码中已经不鼓励使用它了,建议使用 String 的 split 方法或 java.util.regex 包代替。

再来看 StringTokenizer 类的源码:

可以看到 StringTokenizer 类并未标识 @Deprecated,说明在后续的版本中也还可以继续使用,官方还会继续保留,并不会进行删除。

就像 JDK 集合中的 Vector 和 Hashtable 类一样,虽然它们略显笨重,但并不说明它们没有用了,另外,它们也不存在致命缺陷,所以一直保留到现在并未废除掉。

StringTokenizer 没人用了吗?

答案:非也!

栈长在最新的 Spring 5.x 框架 StringUtils 工具类中就发现了 StringTokenizer 的使用身影:

org.springframework.util.StringUtils#tokenizeToStringArray

另外,栈长还看到了一篇《Faster Input for Java》的文章,其中就介绍了他们是使用 StringTokenizer 来分割字符串的,其效率是 string.split() 的 4 倍

We split the input line into string tokens, since one line may contain multiple values. To split the input, StringTokenizer is 4X faster than string.split().

参考:https://www.cpe.ku.ac.th/~jim/java-io.html

所以,即使 JDK 不鼓励使用它了,但它并未被废除,并且性能还这么强,在一些对性能比较敏感的系统中,或者对性能比较有要求的编程竞赛中,StringTokenizer 就能发挥重要作用。

所以,大胆用吧,StringTokenizer 还是可以用的,用的好还能出奇效!另外,往期 Java 技术系列文章我也已经整理好了,关注公众号Java技术栈,在后台回复:java,可以获取阅读,非常齐全。

StringTokenizer vs split

说了这么多,相信大部分人都只用过 split,而没用过 StringTokenizer,那么栈长今天就来对比下这两个字符串分割法的性能及利弊。

测试代码如下:

import java.util.Random;
import java.util.StringTokenizer;

/**
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
public class SplitTest {

    private static final int MAX_LOOP = 10000;

    /**
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        System.out.println(sb.toString());
        for (int i = 0; i < 1000; i++) {
            sb.append(new Random().nextInt()).append(" ");
        }
        split(sb.toString());
        stringTokenizer(sb.toString());
    }

    /**
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    private static void split(String str) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < MAX_LOOP; i++) {
            String[] arr = str.split(" ");
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < arr.length; j++) {
                sb.append(arr[j]);
            }
        }
        System.out.printf("split 耗时 %s ms\n", System.currentTimeMillis() - start);
    }

    /**
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    private static void stringTokenizer(String str) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < MAX_LOOP; i++) {
            StringTokenizer stringTokenizer = new StringTokenizer(str, " ");
            StringBuilder sb = new StringBuilder();
            while (stringTokenizer.hasMoreTokens()) {
                sb.append(stringTokenizer.nextToken());
            }
        }
        System.out.printf("StringTokenizer 耗时 %s ms", System.currentTimeMillis() - start);
    }

}

在我本机测试结果如下:

测试次数

split

StringTokenizer

1

1ms

1ms

10

7ms

3ms

100

30ms

16ms

1000

129ms

51ms

10000

570ms

486ms

100000

3816ms

3130ms

从测试数据看,虽然 StringTokenizer 有一点性能优势,但并不太明显,我并没有测试出有 4 倍的性能差距,可能和测试数据、测试方法、以及测试的 JDK 版本有关系。

然后,我再把 split 测试方法中的 " " 改成 "\\s"

测试次数

split

StringTokenizer

1

6ms

1ms

10

25ms

4ms

100

90ms

20ms

1000

240ms

59ms

10000

835ms

481ms

100000

5616ms

3362ms

把 split 方法改成正则表达式再测试,这下差距就明显了。

我们都知道解析正则表达式会比较慢一点,这很正常,但 StringTokenizer 并不支持传入正则表达式,只能使用字符串作为分隔符,所以这测试结果就没多大意义了,这就是症结了。。

总结

虽然 JDK 不鼓励使用 StringTokenizer 了,但并不说明它不能用了,相反,如果你的系统对性能有非常严格的要求,又不是很复杂的字符串分割,好好使用它反而可以带来高效。

但话又说回来,一般的应用程序用 split 也就够了,因为它够简单、又支持正则表达式,在一般的应用中也不会存在像文中测试的大批量的字符串循环分割,另外,StringTokenizer 在单次分割的性能上也没有性能优势。

最后,关于字符串的分割方法,我们除了字符串本身的 split 方法,我们还要知道 StringTokenizer 这个类,多知道点不是坏事。另外,在 Spring、Apache Commons 工具类中也都有封装好的 StringTokenizer 工具类,有兴趣的可以直接拿去用。

好了,今天的分享就到这里了,后面栈长我会更新更多好玩的 Java 技术文章,关注公众号Java技术栈第一时间推送,不要走开哦。

本节教程所有实战源码已上传到这个仓库:

https://github.com/javastacks/javastack

最后,觉得我的文章对你用收获的话,动动小手,给个在看、转发,原创不易,栈长需要你的鼓励。

本文分享自微信公众号 - Java技术栈(javastack),作者:栈长

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-08-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java高效分割字符串

    最近优化一段代码的调用时间,发现性能瓶颈居然是io和split!io操作慢情有可原,那么对于split有没有更高效的方法呢?

    weishu
  • 字符串分割性能对比

    对于开发人员来说,字符串分割很常见。那么我们就来掰一下他的由来和应用场景,在前后端交互场景中,用户批量操作,

    叔牙
  • 字符串优化处理

    原文:https://www.relaxheart.cn/to/master/blog?uuid=87

    七七分享
  • Java 程序优化:字符串操作、基本运算方法等优化策略

    字符串对象或者其等价对象 (如 char 数组),在内存中总是占据最大的空间块,因此如何高效地处理字符串,是提高系统整体性能的关键。

    哲洛不闹
  • Java 程序该怎么优化?技巧篇

    研发过程中,String 的 API 用的应该是最多,创建 String 对象,以及字符串分割处理那是常有的事儿。

    一猿小讲
  • 非常重要 却被世人忽略的Java基础知识 原

    本文将一点一滴的累计记录Java中的一些细节知识。不只是加以说明,而是所有的细节都找到来源,以官方文档、知名社区的介绍为主。

    随风溜达的向日葵
  • Java 程序优化:字符串操作、基本运算方法等优化策略

    字符串对象或者其等价对象 (如 char 数组),在内存中总是占据最大的空间块,因此如何高效地处理字符串,是提高系统整体性能的关键。

    哲洛不闹
  • hadoop 里执行 MapReduce 任务的几种常见方式

    说明: 测试文件: echo -e "aa\tbb \tcc\nbb\tcc\tdd" > 3.txt hadoop fs -put 3.txt /tm...

    用户1177713
  • 数组、字符串类问题小记

    数组、字符串类的问题,是一类最为基础的问题,但是比较考察人,也经常出现在技术面中,今天想就这类问题,做个记录,好记心不如烂笔头。

    Coder的技术之路
  • Java StringTokenizer快速指南

    StringTokenizer类可以帮助我们把字符串分割为多个符号(token)。  StreamTokenizer提供类似的功能,但StringTokeniz...

    用户7886150
  • Hadoop MapReduce编程学习

    一直在搞spark,也没时间弄hadoop,不过Hadoop基本的编程我觉得我还是要会吧,看到一篇不错的文章,不过应该应用于hadoop2.0以前,因为代码中有...

    用户3003813
  • Java类收集

    想必大家对SimpleDateFormat并不陌生。SimpleDateFormat 是 Java 中一个非常常用的类,该类用来对日期字符串进行解析和格式化输出...

    干货满满张哈希
  • Hadoop阅读笔记(一)——强大的MapReduce

    前言:来园子已经有8个月了,当初入园凭着满腔热血和一脑门子冲动,给自己起了个响亮的旗号“大数据 小世界”,顿时有了种世界都是我的,世界都在我手中的赶脚。可是.....

    JackieZheng
  • Hadoop使用学习笔记(3)

    我们先用老版本的API编写,下一篇会用新的API,并解释区别: 环境配置: 提交Job,开发IDE所在机器环境:Windows 7,4C8G,Intel...

    干货满满张哈希
  • Hadoop(十五)MapReduce程序实例

    一、统计好友对数(去重) 1.1、数据准备 joe, jon joe , kia joe, bob joe ,ali kia, ...

    用户1195962
  • Hadoop(十五)MapReduce程序实例

        从上面的文件格式与内容,有可能是出现用户名和好友名交换位置的两组数据,这时候这就要去重了。

    大道七哥
  • java解析xml技术(一)

    forrestlin
  • eclipse/intellij idea 远程调试hadoop 2.6.0

    很多hadoop初学者估计都我一样,由于没有足够的机器资源,只能在虚拟机里弄一个linux安装hadoop的伪分布,然后在host机上win7里使用eclips...

    菩提树下的杨过
  • Java实例教程(下)

    Java当前日期/时间Java将字符串转换为日期Java当前工作目录Java正则表达式Java立方体编译并执行Java Online

    用户7886150

扫码关注云+社区

领取腾讯云代金券