简体   繁体   中英

StringBuilder appends null as “null”

How come?

    StringBuilder sb = new StringBuilder();

    sb.append("Hello");
    sb.append((String)null);
    sb.append(" World!");
    Log.d("Test", sb.toString());

Produces

06-25 18:24:24.354: D/Test(20740): Hellonull World!

I expect that appending a null String will not append at all!!
BTW, the cast to String is necessary because StringBuilder.append() has a lot of overloaded versions.

I simplified my code to make a point here, in my code a got a method returning a string

public String getString() { ... }
...
sb.append(getString());
...

getString() sometimes returns null ; now I have to test it if I want to use a StringBuilder !!!!

Furthermore, let's clarify my question here: how can I get StringBuilder.append() to accept, in an elegant way, a null string, and not convert it to the literal string "null".
By elegant I mean I don't want to get the string, test if it is null and only then append it. I am looking for an elegant oneliner.

How come?

Its clearly written in docs

The characters of the String argument are appended, in order, increasing the length of this sequence by the length of the argument. If str is null, then the four characters "null" are appended.

So please put a null check before append.

That's just the way it is. null is appended as "null" . Similarly, when you print null with System.out.println(null) you print "null" .

The way to avoid that is that method that returns string getString() checks for null :

public String getString() {
    ...
    if (result == null) {
        return "";
    }
}

It behaves like this, because null isn't an empty String as you think of it. Empty String would be new String(""); . Basically append() method appends "null" if it gets null value as a parameter.

EDIT
My previous answer was not reflecting the appropriate reason for such behaviour of StringBuilder as asked by OP. Thanks to @Stephen C for pointing out that

I expect that appending a null String will not append at all!!

But it is appending. The reason for such behaviour of StringBuilder is hidden in implementation detail of append(Object obj) method which takes us to AbstractStringBuilder#append(String str) method which is defined as follows:

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null"; -->(1)
    //.......
    return this;
}

It clearly specifying that if the input String is null then it is changed to String literal "null" and then it processes further.

How can I get StringBuilder.append() to accept, in an elegant way, a null string, and not convert it to the literal string "null".

You need to check the given String for null explicitly and then proceed. For example:

String s = getString();
StringBuffer buf = new StringBuffer();
//Suppose you want "Hello "<value of s>" world"
buf.append("Hello ");
buf.append(s==null?" world" : s+" world");

AbstractStringBuilder class appends an object through String.valueOf(obj) method which in turn converts NULL into string literal "null". Therefor there is no inbuilt method to help you here. You have to either use ternary operator within append method or write a utility method to handle it, as others suggested.

This will work for you

public static String getString(StringBuilder sb, String str) {
    return sb.append(str == null ? "" : str).toString();
}

What about writing an utility method like

public static void appendString(StringBuilder sb, String st) {
    sb.append(st == null ? "" : st);
}

or this the ternary operator is very handy.

String nullString = null;
StringBuilder sb = new StringBuilder();
sb.append("Hello");
if (nullString != null) sb.append(nullString);
sb.append(" World!");
Log.d("Test", sb.toString());

There! I did it in one line :)

One line?

sb.append((getString()!=null)?getString():"");

done. But is pointless as have to call getString() twice

As was suggested build check into getString() method

You can also write decorator for StringBuilder, which can check whatever you want:

class NotNullStringBuilderDecorator {

    private StringBuilder builder;

    public NotNullStringBuilderDecorator() {
        this.builder = new StringBuilder();
    }

    public NotNullStringBuilderDecorator append(CharSequence charSequence) {
        if (charSequence != null) {
            builder.append(charSequence);
        }

        return this;
    }

    public NotNullStringBuilderDecorator append(char c) {
        builder.append(c);

        return this;
    }

    //Other methods if you want

    @Override
    public String toString() {
        return builder.toString();
    }
}

Example of usage:

NotNullStringBuilderDecorator sb = new NotNullStringBuilderDecorator();
sb.append("Hello");
sb.append((String) null);
sb.append(" World!");

System.out.println(sb.toString());

With this solution you have not to change POJO classes.

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