您的位置 首页 php

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

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

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

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

StringTokenizer 被废弃了吗?

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

参考:

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() .

参考:~jim…

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

所以,大胆用吧,StringTokenizer 还是可以用的,用的好还能出奇效!另外,往期 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);
    }

}  

在我本机测试结果如下:

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

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

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

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

总结

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

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

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

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

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

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

版权申明:本文系 “Java技术栈” 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重大家的劳动成果和知识产权,抄袭必究。

文章来源:智云一二三科技

文章标题:你只会用 split?试试 StringTokenizer,性能可以快 4 倍

文章地址:https://www.zhihuclub.com/79502.shtml

关于作者: 智云科技

热门文章

网站地图