Dan*_*ani 5 java string performance split stringtokenizer
通过鼓励这个,事实上我有十亿串的解析,我想修改我的代码接受的StringTokenizer代替的String []
我和你之间唯一能够获得美味的x2性能提升的事实就是你正在做的事情
"dog,,cat".split(",")
//output: ["dog","","cat"]
StringTokenizer("dog,,cat")
// nextToken() = "dog"
// nextToken() = "cat"
Run Code Online (Sandbox Code Playgroud)
如何使用StringTokenizer获得类似的结果?有没有更快的方法来做到这一点?
Jon*_*eet 12
你只是用逗号标记吗?如果是这样,我会编写自己的标记化器 - 它可能最终比更通用的StringTokenizer更有效,它可以查找多个标记,并且您可以使它按照您的喜好行事.对于这样一个简单的用例,它可以是一个简单的实现.
如果它有用,你甚至可以Iterable<String>通过强类型而不是提供的Enumeration支持来实现并获得增强的for-loop支持StringTokenizer.如果你想要任何帮助编码这样的野兽,请告诉我 - 这真的不应该太难.
此外,我会尝试在实际数据上运行性能测试,然后再跳过现有解决方案.您是否知道实际花费了多少执行时间String.split?我知道你有很多字符串要解析,但是如果你之后做了一些重要的事情,那么我希望它比分裂更重要.
coo*_*ird 10
在修补StringTokenizer课程后,我找不到满足要求返回的方法["dog", "", "cat"].
此外,StringTokenizer仅出于兼容性原因而保留该类,并且String.split鼓励使用该类.来自API规范StringTokenizer:
StringTokenizer是一个遗留类,出于兼容性原因而保留,尽管在新代码中不鼓励使用它.建议任何寻求此功能的人都使用split方法String或java.util.regex包.
由于问题是该String.split方法的表现不佳,我们需要找到一个替代方案.
注意:我说的是"据说表现不佳",因为很难确定每个用例都会导致StringTokenizer优于该String.split方法.此外,在许多情况下,除非字符串的标记化确实是通过适当的分析确定的应用程序的瓶颈,否则我觉得它最终会成为过早的优化,如果有的话.在冒险进行优化之前,我倾向于说编写有意义且易于理解的代码.
现在,根据当前的要求,可能滚动我们自己的标记器并不会太困难.
滚动我们自己的tokenzier!
以下是我写的一个简单的tokenizer.我应该注意,没有速度优化,也没有错误检查以防止超过字符串的结尾 - 这是一个快速而肮脏的实现:
class MyTokenizer implements Iterable<String>, Iterator<String> {
String delim = ",";
String s;
int curIndex = 0;
int nextIndex = 0;
boolean nextIsLastToken = false;
public MyTokenizer(String s, String delim) {
this.s = s;
this.delim = delim;
}
public Iterator<String> iterator() {
return this;
}
public boolean hasNext() {
nextIndex = s.indexOf(delim, curIndex);
if (nextIsLastToken)
return false;
if (nextIndex == -1)
nextIsLastToken = true;
return true;
}
public String next() {
if (nextIndex == -1)
nextIndex = s.length();
String token = s.substring(curIndex, nextIndex);
curIndex = nextIndex + 1;
return token;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Run Code Online (Sandbox Code Playgroud)
在MyTokenizer将采取String来标记和String作为分隔符,并使用该String.indexOf方法来执行分隔符搜索.令牌由该String.substring方法产生.
我怀疑通过在char[]级别而不是在String级别上处理字符串可能会有一些性能改进.但我会把它作为练习留给读者.
该类还实现Iterable并且Iterator为了利用for-eachJava 5中引入的循环结构StringTokenizer是一个Enumerator,并且不支持该for-each构造.
它更快吗?
为了找出这是否更快,我写了一个程序来比较以下四种方法的速度:
StringTokenizer.MyTokenizer.String.split.Pattern.compile.在这四种方法中,字符串"dog,,cat"被分成标记.尽管StringTokenizer包含在比较中,但应注意它不会返回所需的结果["dog", "", "cat].
标记化重复总共100万次,以便花费足够的时间来注意方法的差异.
用于简单基准测试的代码如下:
long st = System.currentTimeMillis();
for (int i = 0; i < 1e6; i++) {
StringTokenizer t = new StringTokenizer("dog,,cat", ",");
while (t.hasMoreTokens()) {
t.nextToken();
}
}
System.out.println(System.currentTimeMillis() - st);
st = System.currentTimeMillis();
for (int i = 0; i < 1e6; i++) {
MyTokenizer mt = new MyTokenizer("dog,,cat", ",");
for (String t : mt) {
}
}
System.out.println(System.currentTimeMillis() - st);
st = System.currentTimeMillis();
for (int i = 0; i < 1e6; i++) {
String[] tokens = "dog,,cat".split(",");
for (String t : tokens) {
}
}
System.out.println(System.currentTimeMillis() - st);
st = System.currentTimeMillis();
Pattern p = Pattern.compile(",");
for (int i = 0; i < 1e6; i++) {
String[] tokens = p.split("dog,,cat");
for (String t : tokens) {
}
}
System.out.println(System.currentTimeMillis() - st);
Run Code Online (Sandbox Code Playgroud)
结果
测试使用Java SE 6(build 1.6.0_12-b04)运行,结果如下:
Run 1 Run 2 Run 3 Run 4 Run 5
----- ----- ----- ----- -----
StringTokenizer 172 188 187 172 172
MyTokenizer 234 234 235 234 235
String.split 1172 1156 1171 1172 1156
Pattern.compile 906 891 891 907 906
因此,从有限的测试中可以看出,只有五次运行,StringTokenizer事实上确实出现了最快,但是MyTokenizer排在第二位.然后,String.split是最慢的,预编译的正则表达式比split方法稍快.
与任何小基准一样,它可能不具备现实生活条件的代表性,因此结果应采用谷物(或土墩)盐.
| 归档时间: |
|
| 查看次数: |
7121 次 |
| 最近记录: |