StringBuilder voegt null toe als "null"

Hoe kan dat?

    StringBuilder sb = new StringBuilder();

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

produceert

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

Ik verwacht dat het toevoegen van een null -reeks helemaal niet zal toevoegen !!
BTW, de cast naar String is nodig omdat StringBuilder.append() veel overbelaste versies heeft.

Ik vereenvoudigde mijn code om hier een punt te maken, in mijn code kreeg ik een methode die een string retourneerde

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

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

Laten we verder mijn vraag hier verduidelijken: hoe kan ik StringBuilder.append() krijgen om op een elegante manier een nul-string te accepteren en niet omzetten in de letterlijke reeks "null".
Met elegant bedoel ik dat ik de string niet wil krijgen, testen of het null is en pas dan toevoegen. Ik ben op zoek naar een elegante oneliner.

5
toegevoegd de auteur Stephen C, de bron

10 antwoord

How come?

Its clearly written in docs

De tekens van het argument String worden toegevoegd, in volgorde, waarbij de lengte van deze reeks wordt verlengd met de lengte van het argument. Als str nul is, worden de vier tekens "null" toegevoegd.

Dus doe alsjeblieft een nulcontrole voordat je het toevoegt.

5
toegevoegd
Ok, het staat in de documentatie. Maar is het mij juist dat het heel contra-intuïtief is? Ik heb geleerd dat een null-string een string is die niet bestaat. En zonder een discussie te beginnen, snap ik niet waarom ze het op die manier deden. Op het moment klop ik met mijn hoofd op het bureau.
toegevoegd de auteur ilomambo, de bron
@LastFreeNickname Niet echt, als een string null is, wil ik/verwacht ik niets te zien. Als ik een foutopsporingsprogramma gebruik, wil ik de variabele inspecteren en de waarde ervan zien als null . Het lijkt nog niet zo lang geleden dat de professor in een algebra-cursus zei dat er een speciaal symbool is om een ​​lege verzameling aan te duiden, een verzameling zonder elementen, die de analogie is van een nul-reeks. Als iets wordt weergegeven voor een lege reeks, wordt de consistentie gebroken met dezelfde definitie van null . Maar dit huilt om gemorste melk, op een dag hoop ik de reden te leren waarom.
toegevoegd de auteur ilomambo, de bron
Ik denk dat je een lege en een lege string verwart. Zoals u zegt (String) is null een String die niet bestaat, die wordt weergegeven met "null" in het String-domein. Aan de andere kant heeft de lege String "" niet-verrassend de representatie "". Wanneer u een String-variabele foutopsporing uitvoert of wilt afdrukken, wilt u in feite zien dat deze naar nul verwijst, dus het is logisch.
toegevoegd de auteur LastFreeNickname, de bron

Het is niet anders. null is toegevoegd als "null" . Op dezelfde manier drukt u "null" af wanneer u null met System.out.println (null) afdrukt.

De manier om dat te voorkomen, is die methode die string getString() controles voor null retourneert:

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

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

Ik verwacht dat het toevoegen van een null-reeks helemaal niet zal toevoegen !!

Maar het is toevoegen. De reden voor dergelijk gedrag van StringBuilder is verborgen in de implementatiedetails van toevoegen (Object obj) methode die ons meeneemt naar AbstractStringBuilder # append (String str) methode die als volgt is gedefinieerd:

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

Het geeft duidelijk aan dat als de invoer String null is, deze wordt gewijzigd in String literal "null" en vervolgens verder wordt verwerkt.

Hoe kan ik StringBuilder.append() ontvangen om op een elegante manier een nul-tekenreeks te accepteren en niet omzetten in de letterlijke tekenreeks "null".

U moet de gegeven String voor null expliciet controleren en dan doorgaan. Bijvoorbeeld:

String s = getString();
StringBuffer buf = new StringBuffer();
//Suppose you want "Hello "" world"
buf.append("Hello ");
buf.append(s==null?" world" : s+" world");
2
toegevoegd
Strikt genomen is de JLS hier niet definitief voor. De JLS specificeert eigenlijk de semantiek van de "+" operator. Je zou kunnen stellen dat het een gemakkelijk toeval is dat StringBuilder.append (null) het vereiste gedrag implementeert. (Ik weet zeker dat het geen toeval is, maar je begrijpt mijn punt ...)
toegevoegd de auteur Stephen C, de bron
@StephenC: Ja je hebt gelijk..Mijn fout ...
toegevoegd de auteur Vishal K, de bron

Het gedraagt ​​zich als volgt, want null is geen lege tekenreeks als u eraan denkt. Leeg String is nieuwe tekenreeks (""); . In principe voegt de methode append() toe "null" als deze de waarde null krijgt als parameter.

2
toegevoegd
Ik heb niet gezegd "lege string" Ik zei "een string die niet bestaat"
toegevoegd de auteur ilomambo, de bron

Dit zal voor u werken

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

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
toegevoegd

Hoe zit het met het schrijven van een utility-methode zoals

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

of dit is de ternaire operator erg handig.

0
toegevoegd

Je kunt ook een decorateur voor StringBuilder schrijven, die kan controleren wat je wilt:

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

Voorbeeld van gebruik:

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

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

Met deze oplossing hoeft u de POJO-klassen niet te wijzigen.

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

Er! Ik deed het in één rij :)

0
toegevoegd
:-) geen vraag, het is heel elegant :-)
toegevoegd de auteur ilomambo, de bron

Een lijn?

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

gedaan. Maar het is zinloos om getString() twee keer te bellen

Zoals is gesuggereerd, moet u de methode getString() controleren

0
toegevoegd