Menu

Check StringBuffer sizes against usage

Developers
Brian R
2006-02-09
2012-10-07
  • Brian R

    Brian R - 2006-02-09

    StringBuffer instances, when created with the default constructor, create an internal array with a length of 16 characters. We should be able to determine the minimal size of the buffer by summing the lengths of any literals appended to it and raise a suggestion to either specify the minimal length or use a larger value if one is already specified. This increases performance by avoiding buffer enlargements and copy operations.

    Examples:

    // buffer too small

    StringBuffer sb = new StringBuffer(5);
    sb.append("This is my very own string buffer. ");

    // default constructor sizes buffer to 16, need more than 83 chars in this case

    StringBuffer sb = new StringBuffer();
    sb.append("This is my very own string buffer. ");
    sb.append("Date: ").append(new Date());
    sb.append("I hope you use PMD to better your products");

     
    • Allan Caplan

      Allan Caplan - 2006-02-25

      This rule is now checked in. See the strings ruleset, the rule is called InsufficientStringbufferDeclaration

       
    • Allan Caplan

      Allan Caplan - 2006-02-10

      Brian
      I started on this rule a while ago, but put it on the shelf because of some unknowns. Maybe you can help?
      First, figuring out the initial size of the StringBuffer. StringBuffer(23) gives a clear indication of how large the object is initially. int x = 3;StringBuffer(x); no problem. If the constructor is StringBuffer(someList.size()*52), there's a reasonable confidence that someone knew what they were doing, but the rule has no idea if they really did. So, in this case I'd have to skip the occurance.

      The next problem comes from appending variables. .append("444") tells me that you just added 3 characters to the StringBuffer. Even local variables I could probrably figure out from the symbol table. But .append(foo.getSomeString()) is a black box. Could just skip those. But now we're at 2 assumptions.

      The last problem (I'm sure there's bound to be more) is what to do inside controll blocks. A StringBuffer being appended inside a while or for loop - there's no way of knowing how many times the loop will loop. Should the rule then assume once? Lastly, what about if statements. Unless it's in a loop, the part inside the IF statement may or may not be added to the buffer.

      Right now it's in a state where none of the above is taken into account. So, if you have an if/else, both parts are taken into account for the rule. Ideally, I think it should figure out which one is longer (or, "looks" longer), but there's still the issues I listed above. It's really a simple rule, if you have any thoughts I can either check it in or create a jar for you to try to see if it does what you're expecting.
      Al

       
      • Brian R

        Brian R - 2006-02-10

        Ok, I'd not try to read into the developers mind too much if they've gone to the trouble to initialize the buffer using an expression, the rule just terminates. If they have or haven't specified a fixed number then we're game on and then we just go on summing up the literal string lengths to see if they exceed that number. Yes, for loops I'd assume at least one iteration. For conditionals I'd assume the worst case path. As you say, its impossible to know the length results of String-returning expressions statically so those are left off the grand sum.

        I guess I imagined it to be a rough check, a heads up for those who just blindly create StringBuffers and are unaware of the hidden costs if they don't initialize them to their advantage.

        It would be an interesting runtime exercise to set a breakpoint on the StringBuffer.expandCapacity() method. If/when the debugger hits it, then an optimizer could then walk back up the stack to see if the static code had enough info to have allowed the developer to have presized it correctly.

        Hope that helps,
        Brian

         

Log in to post a comment.