【Java实用技术】字符串的拆分怎么最快?
本文是《【Java实用技术】字符串的拆分用什么方法好?》的姊妹篇,拆分方法最常用,使用看似简单但也有很多复杂的细节要注意,今天我们就来聊一聊字符串拆分怎么最快?
2种操作性能对比
import org.apache.commons.lang3.StringUtils;
/**
* Java实用技术课程 By Pandas.
* 公众号:Java实用技术手册
* JDK版本:jdk1.8.0_66
*
* @author Pandas
* @date 2021/10/31
*/
public class StringSplitQuick {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
int max = 100_0000;
for (int i = 0; i < max; i++) {
sb.append("a.");
}
// 构造一个100W个"a."拼接成的字符串:"a.a.a.a.a.......a."
String str = sb.toString();
long start1 = System.currentTimeMillis();
String[] cs1 = str.split("\\.");
long cost1 = System.currentTimeMillis() - start1;
long start2 = System.currentTimeMillis();
String[] cs2 = StringUtils.split(str, '.');
long cost2 = System.currentTimeMillis() - start2;
long start11 = System.currentTimeMillis();
String[] cs11 = str.split("a");
long cost11 = System.currentTimeMillis() - start11;
long start22 = System.currentTimeMillis();
String[] cs22 = StringUtils.split(str, 'a');
long cost22 = System.currentTimeMillis() - start22;
System.out.println("原生拆分.耗时:" + cost1 + "ms");
System.out.println("StringUtils拆分.耗时:" + cost2 + "ms");
System.out.println("原生拆分a耗时:" + cost11 + "ms");
System.out.println("StringUtils拆分a耗时:" + cost22 + "ms");
}
}
运行结果如下:
总体上来说,原生方法拆分是比StringUtils拆分耗时久点。
还能不能再快呢?这就要分析下源码。
字符串拆分之arraycopy
-
对于字符串拆分的原生操作
-
StringUtils拆分操作
我们注意到上面2个方法都用到了list.toArray()
方法,这个方法的源码用到了System.arraycopy(elementData, 0, a, 0, size);
方法,这个操作不仅增加额外耗时,也增加内存消耗。
PS:List扩容过程中也会用到这System.arraycopy()方法哦,有兴趣的同学可以多看看他的实现。
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
如果内存不够的话,一开始的例子,你可能会遇到下面的错误:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
考虑到我们在通常开发场景中,我们使用字符串拆分后的操作一般是对拆分后内容遍历,因此使用数组还是List,都不影响我们操作。
上述方法中的List转数组,白白消耗了内存和时间。
在有的工具类(比如hutool)中就改成了List<String>
作为返回类型。
补充说明
在《阿里巴巴Java开发手册》(嵩山版)中,有这么一句话
在上一节中,无论是原生split还是StringUtils,都将拆分后为空字符串的部分去掉,因此原始的List容量实际是小于等于保留全部分割数据的大小的。这个在一些拆分后业务处理是有影响的=>就是会数组越界。
比如很常见的场景,由"key=value"
组成的字符串,按照“=”
拆分,如果不注意,直接使用arr[1]
获取value,一定会数组越界。
这时候使用StringUtils.splitPreserveAllTokens(str, "=");
可以有效保留空白字符位置。
当然,如果字符串中连要分割的字符都没有,上述方法还是不能返回第二个位置的数据。
这个时候你需要自己写一个字符串拆分工具类,返回固定长度的数组/List,这样方法调用者可以放心使用数组。
感谢阅读本期内容,希望对新入行的你有帮助。
往期内容:
我是Pandas,专注Java实用技术分享,公众号
Java实用技术手册
和B站均有视频解说,欢迎来玩。如果你觉得这篇文章有用,别忘了点赞+关注,一起进步!
- 点赞
- 收藏
- 关注作者
评论(0)