简体   繁体   中英

Something crazy happens with StringBuilder.append(String str);

I've got a problem with my java-project.

following function should deliver a String for a SQL-Statement:

private static String createInsertString(Pat p)
{   
    StringBuilder x = new StringBuilder();


    x.append(""  + p.getPatnr() +","+ p.getSvnr());

    java.sql.Date andat = null,gebdat;

    if(p.getAndat()==null)
        andat=null;
    else
        andat=new java.sql.Date(p.getAndat().getTimeInMillis());

    if(p.getGebdat()==null)
        gebdat=null;
    else
        gebdat=new java.sql.Date(p.getGebdat().getTimeInMillis());

    x.append("," + andat==null?"null":andat);
    x.append("," + p.getTele()==null?"null":p.getTele());
    x.append("," + p.getVName() +","+ p.getNname());
    x.append("," + p.getKk()==null?"null":p.getKk());
    x.append("," + gebdat==null?"null":gebdat);
    x.append("," + p.getAdrplzort()==null?"null":6);
    x.append("," + p.getAdrstr()==null?"null":p.getAdrstr());
    x.append("," + p.getAdrhnr()==null?"null":p.getAdrhnr());
    s.append("," + p.getReplzort()==null?"null":p.getReplzort().getPlzortnr());
    x.append("," + p.getRestr()==null?"null":p.getRestr());
    x.append("," + p.getRehnr()==null?"null":p.getRehnr());
    x.append("," + p.getLevel());
    x.append("," + p.getCon()==null?"null":p.getCon());
    x.append("," + (p.isPa()?"y":"n")+","+ (p.isLonly()?"y":"n") +","+ (p.isGest()?"y":"n"));
    x.append("," + p.getBem()==null?"null":p.getBem());
    x.append("," + (p.isKat1()?'y':'n') +","+ (p.isKat2()?'y':'n') +","+ (p.isKat3()?'y':'n'));

    System.out.println(x);

    return x.toString();
} 

the output is

6,6465136nullnull,Jürgen,Wieslernullnull6nullnullnullnull,0null,n,n,nnull,n,n,n

but it should be like this:

6,6465136,null,null,Jürgen,Wiesler,null,null,6,null,null,null,null,0,null,n,n,n,null,n,n,n

Anyone an Idea? I'm using jdk 1.7 on debian(64-bit)

The problem is how the operators bind. Look at this:

x.append("," + andat==null?"null":andat);

Now think of it as:

x.append(("," + andat) == null ? "null" : andat);

The LHS is never going to be null, so it's always just appending andat ... and that still converts to "null" if the reference is null, because that's the default behaviour of StringBuilder .

Your code is much more complicated - and inefficient - than it needs to be. Consider rewriting it as:

private static String createInsertString(Pat p)
{   
    StringBuilder x = new StringBuilder();
    java.sql.Date andat = p.andat == null ? null 
        : new java.sql.Date(p.getAndat().getTimeInMillis());
    java.sql.Date gebdat = p.getGebdat() == null ? null 
        : new java.sql.Date(p.getGebdat().getTimeInMillis());

    x.append(p.getPatnr()).append(",")
     .append(p.getSvnr()).append(",")
     .append(andat).append(",")
     .append(p.getTele()).append(",")

     // etc

    return x.toString();
}

Note that I think you had a bug in the original:

x.append("," + p.getVName() +","+ p.getNname());

Where these meant to be calling two different getters?

You are misusing .append() by putting concatenations inside them! This misses the entire point of what StringBuilder is supposed to be used for.

 x.append("," + andat==null?"null":andat);

should be

 x.append(",").append( andat == null ? "null" : andat);

which would be the correct logic to make your ternary operator work as you intended.

.append() returns a reference to the StringBuilder so that you can chain .append() calls as much as you need.

Anytime you are putting a string concatenation inside of .append() you are just creating more intermediate String objects that eat up memory, cpu cycles and then use more resources as they now need to be garbage collected.

Also you should pre-allocate your StringBuilder with a default size that is slightly bigger than what you expect your contents to be to avoid wasted allocations and garbage creation.

See the Javadoc for the StringBuilder(int) constructor.

The problem comes from your '+'.

  1. If you use a StringBuilder, don't use '+': it is not efficient
  2. "," + andat==null?"null":andat results in ",null"==null?"null":andat if andat is null.

The '+' string concatenation has priority over the ternary operator

When you use the '+' with String your compiler actually translates that to a StringBuilder (or a StringBuffer before Java5)

So having

String s = a + b + c;

is actually translated to:

String s = new StringBuilder().append(a).append(b).append(c).toString().

Therefore using + within a StringBuilder is counter-productive as you create additional unecessary StringBuilder.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM