【问题标题】:Faster way to split a string in java then add to an ArrayList在java中拆分字符串然后添加到ArrayList的更快方法
【发布时间】:2014-05-29 02:47:54
【问题描述】:

在一个学校项目中,我被要求用 Java 编写一个简单的数学解析器。该程序运行良好。太好了,我使用 NetBeans 分析器工具来检查程序的性能。为此,我对以下表达式的数学解析器进行了 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 的内容 - 第一行。

我的问题是:有没有更快的方法来拆分字符串,然后将部分字符串添加到数组列表中?还是有其他方法可以用来分割字符串然后使用子字符串?

【问题讨论】:

  • ArrayLists 以一定的大小开始并不断增长。例如,如果数组列表的大小为 10,并且您添加了第 11 个元素,则分配一个大小为 20 的新数组列表,并将旧数组列表的所有元素复制到新的数组中,依此类推。改用链表。
  • @MohanKumar 我不知道。让我看看你的建议。谢谢。
  • 我在想。使用partialFormula.clear() 而不是以上述方式“清除”它不是更好的主意吗?
  • 我认为您需要使用 Pattern 和 Matcher 手动解析公式。
  • @MohanKumar 链表增加了间接性,数组没有。增长操作几乎总是在缓存上执行,这比链表间接引入的开销要快得多

标签: java performance arraylist split


【解决方案1】:

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

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

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

【讨论】:

  • 让我快速检查您的建议 =)
  • 遗憾的是它不是。这需要更长的时间。该方法比循环花费了近 100 毫秒 =/
  • 更简单的正则表达式:[-+*/].
  • @PML 好吧,该死。对不起。
【解决方案2】:

尝试预先分配 ArrayList,这样我们就不必在列表增长时为重新分配付费。下面的数字20 只是一个占位符。选择一个比您预期的最大表达式稍大的数字。

partialFormula=new ArrayList<String>(20);

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

【讨论】:

    【解决方案3】:

    正则表达式会减慢速度(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+2 和你的代码尝试了它,因为它只考虑第一个元素:“1”。但老实说我没有看到你的代码的问题=/
    • @PML 哦,哎呀。忘记在字符串末尾添加 :-)
    • 它有效。它只是在最后一个语句中缺少一个 ')'。好吧,我非常感谢您的时间和解释。整个程序现在只需要 134 毫秒。该方法本身现在需要 13.1 毫秒。非常感谢!
    • 在 "partialFormula.add(formula.substring(lastIndex);" 中缺少一个 ')' 来关闭 .add 方法 =)
    • @PML 不使用 IDE 来回答 StackOverflow 问题的危险。
    【解决方案4】:

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

    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]));  
        }
    

    【讨论】:

    • 是的,它将创建一个字符串数组列表。但不是OP想要的。当 OP 想要 1234,af,d53 时,您的示例字符串将是列表 1,2,3,4,+,a,f,?,d,5,3
    • 我误会了。应该是 String [] blah=a.split("\\+|\\-|\*|\\/");然后只需使用 list.add(blah[i]);
    • 这正是 OP 所拥有的,但代码行数更多。
    猜你喜欢
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2019-01-13
    • 1970-01-01
    相关资源
    最近更新 更多