在java中拆分字符串的更快方法然后添加到ArrayList

时间:2014-04-14 23:15:31

标签: java performance arraylist split

对于一个学校项目,我被要求用Java编写一个简单的数学解析器。该程序工作正常。我用NetBeans profiler工具检查程序的性能非常好。为此,我对以下表达式的数学解析器进行了1000次调用循环:"1-((x+1)+1)*2",其中x被当前循环计数替换。花了262ms。问题是,在方法splitFormula中占用了50%的时间,我将在下面介绍:

private static void splitFormula(String formula){
    partialFormula=new ArrayList<>();

    for(String temp: formula.split("\\+|\\-|\\*|\\/"))
        partialFormula.add(temp);
}

,其中partialFormula是一个ArrayList的字符串。为了数值计算表达式,我需要多次调用splitFormula方法,所以我真的需要清除partialFormula ArrayList - 第一行的内容。

我的问题是:是否有更快的方法来分割字符串然后将部分字符串添加到arraylist?或者是否有其他方法可用于拆分字符串然后使用子字符串?

4 个答案:

答案 0 :(得分:7)

正则表达式可以减慢速度(String#split使用正则表达式)。一般来说,如果你想编写简单的代码,正则表达式是好的,但如果你想要快速代码,看看是否有另一种方式。尝试不使用正则表达式执行此操作:

编辑:这应该是一种更好的方法(跟踪索引而不是附加到StringBuilder):

private static void splitFormula(String formula){
    partialFormula.clear(); // since there is a method for this, why not use it?

    int lastIndex = 0;
    for (int index = 0; index < formula.length(); index++) {
        char c = formula.charAt(index);
        if (c == '-' || c == '+' || c == '*' || c == '/') {
            partialFormula.add(formula.substring(lastIndex, index));
            lastIndex = index + 1; //because if it were index, it would include the operator
        }
    }
    partialFormula.add(formula.substring(lastIndex));
}

StringBuilder方法:

private static void splitFormula(String formula){
    partialFormula.clear();

    StringBuilder newStr = new StringBuilder();

    for (int index = 0; index < formula.length(); index++) {
        char c = formula.charAt(index);
        if (c == '-' || c == '+' || c == '*' || c == '/') {
            partialFormula.add(newStr.toString());
            newStr.setLength(0);
        } else {
            newStr.append(c);
        }
    }
    partialFormula.add(newStr.toString());
}

如果我们查看String#split的源代码,很明显为什么那么慢(来自GrepCode):

public String[] split(String regex, int limit) {
    return Pattern.compile(regex).split(this, limit);
}

每次编译一个正则表达式!因此,我们可以看到加速代码的另一种方法是首先编译我们的正则表达式,然后使用Pattern#split进行拆分:

//In constructor, or as a static variable.
//This regex is a better form of yours.
Pattern operatorPattern = Pattern.compile("[-*+/]");
...
private static void splitFormula(String formula){
    partialFormula.clear();

    for(String temp: operatorPattern.split(formula)) {
        partialFormula.add(temp);
    }
}

答案 1 :(得分:0)

您不需要for循环。 split返回一个数组,您可以从数组中创建ArrayList

partialFormula = new ArrayList<>(Arrays.asList(formula.split("\\+|\\-|\\*|\\/")));

这是否明显更快,我不知道。

答案 2 :(得分:0)

请事先预先分配ArrayList,这样我们就不必在列表增长时支付重新分配费用。下面的20数字只是一个占位符。选择一个比你期望的最大表达式大一点的数字。

partialFormula=new ArrayList<String>(20);

请参阅this question,了解这可能会给您带来什么。

答案 3 :(得分:0)

这将创建一个字符串数组列表。

String a= "1234+af/d53";
    char [] blah=a.toCharArray(); 
    ArrayList<String> list=new ArrayList<String>();
    for (int i = 0; i < blah.length; i++) {
        list.add(Character.toString(blah[i]));  
    }