StringBuilder acrescenta null como "null"

Por quê?

    StringBuilder sb = new StringBuilder();

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

Produz

06-25 18: 24: 24.354: D/Teste (20740): Mundo do Inferno!

Espero que acrescentar uma null String não seja anexada de forma alguma !!
BTW, o elenco para String é necessário porque StringBuilder.append() tem muitas versões sobrecarregadas.

Eu simplifiquei meu código para fazer um ponto aqui, no meu código um método que retorna uma string

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

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

Além disso, vamos esclarecer minha pergunta aqui: como posso obter o StringBuilder.append() para aceitar, de uma maneira elegante, uma string nula, e não convertê-la para a string literal "null". > Por elegante quero dizer que eu não quero pegar a string, testar se ela é null e só então anexá-la. Eu estou procurando um oneliner elegante.

5
adicionado o autor Stephen C, fonte

10 Respostas

How come?

Its clearly written in docs

Os caracteres do argumento String são acrescentados, em ordem, aumentando o comprimento dessa seqüência pelo comprimento do argumento. Se str for nulo, os quatro caracteres "null" serão anexados.

Então, por favor, coloque uma verificação nula antes de acrescentar.

5
adicionado
Ok, está escrito na documentação. Mas é só isso que eu sou muito contra-intuitivo? Eu aprendi que uma string nula é uma string que não existe. E sem abrir uma discussão, eu simplesmente não entendo porque eles fizeram dessa maneira. Agora estou batendo com a cabeça na mesa.
adicionado o autor ilomambo, fonte
@LastFreeNickname Na verdade, quando uma string é null , não quero/espero ver nada. Se eu usar um depurador, quero inspecionar a variável e ver seu valor como null . Parece não faz muito tempo que em um curso de álgebra o professor disse que há um símbolo especial para significar um conjunto vazio, um conjunto sem nenhum elemento, que é o análogo a uma string nula. Mostrar algo para uma string nula está quebrando a consistência com a mesma definição de null . Mas isso é chorar por leite derramado, algum dia espero aprender o motivo.
adicionado o autor ilomambo, fonte
Eu acho que você está confundindo uma string nula e vazia. Como você diz (String) null é uma String que não existe, que é representada por "null" no domínio String. Por outro lado, a String vazia "" não surpreendentemente tem a representação "". Quando você depura ou imprime alguma variável String, você quer realmente ver que ela está apontando para null, então faz sentido.
adicionado o autor LastFreeNickname, fonte

É assim que é. null é anexado como "null" . Da mesma forma, quando você imprime null com System.out.println (null) , você imprime "null" .

A maneira de evitar isso é que o método que retorna a string getString() procura por null :

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

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

Espero que o acréscimo de uma string nula não seja anexado de maneira alguma !!

Mas é acrescentar. A razão para tal comportamento do StringBuilder está escondida nos detalhes da implementação do método append (Object obj) que nos leva a AbstractStringBuilder # append (String str) método que é definido da seguinte forma:

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

Ele está claramente especificando que se a entrada String for nula, ela será alterada para String literal "null" e, em seguida, será processada posteriormente.

Como posso obter StringBuilder.append() para aceitar, de uma maneira elegante, uma string nula, e não convertê-la para a string literal "null".

Você precisa verificar o String para null explicitamente e depois prosseguir. Por exemplo:

String s = getString();
StringBuffer buf = new StringBuffer();
//Suppose you want "Hello "" world"
buf.append("Hello ");
buf.append(s==null?" world" : s+" world");
2
adicionado
Estritamente falando, o JLS não é definitivo para isso. O JLS está, na verdade, especificando a semântica do operador "+". Você poderia argumentar que é uma coincidência conveniente que StringBuilder.append (null) implemente o comportamento necessário. (Tenho certeza que não é uma coincidência, mas você entendeu ...)
adicionado o autor Stephen C, fonte
@StephenC: Sim, você está certo ... Meu erro ..
adicionado o autor Vishal K, fonte

Ele se comporta assim, porque null não é uma String vazia como você pensa. Empty String seria new String (""); . Basicamente, o método append() acrescenta "null" se obtiver valor null como parâmetro.

2
adicionado
Eu não disse "string vazia" Eu disse "uma string que não existe"
adicionado o autor ilomambo, fonte

Isso vai funcionar para você

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

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.

1
adicionado

Que tal escrever um método utilitário como

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

ou isto o operador ternário é muito útil.

0
adicionado

Você também pode escrever um decorador para o StringBuilder, que pode verificar o que você quiser:

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

Exemplo de uso:

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

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

Com esta solução, você não precisa alterar as classes do POJO.

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

Lá! Eu fiz isso em uma linha :)

0
adicionado
:-) sem dúvida é muito elegante :-)
adicionado o autor ilomambo, fonte

Uma linha?

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

feito. Mas é inútil ter que chamar getString() duas vezes

Como foi sugerido, faça um check no método getString()

0
adicionado