StringBuilder додає null як "null"

Як?

    StringBuilder sb = new StringBuilder();

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

Виробляє

06-25 18: 24: 24.354: D/Test (20740): Хеллонул світ!

Я сподіваюся, що додавання рядка null взагалі не додаватиметься!
До речі, приведення до String необхідно, оскільки StringBuilder.append() має багато перевантажених версій.

Я спростив свій код, щоб зробити точку тут, в моєму коді отримав метод повернення рядка

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

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

Більш того, давайте розберемо моє питання тут: як я можу отримати StringBuilder.append() елегантним способом прийняти нульовий рядок, а не перетворити його в літеральний рядок "null". > Під елегантним я маю на увазі, що я не хочу отримувати рядок, перевіряти, чи є null , і тільки потім додати його. Я шукаю елегантний oneliner.

5
можливі дублікати значень StringBuilder append() і null
додано Автор Stephen C, джерело

10 Відповіді

How come?

Its clearly written in docs

Символи аргументу String додаються в порядку, збільшуючи довжину цієї послідовності за довжиною аргументу. Якщо str є нульовим, то додаються чотири символи "null".

Тому, будь ласка, поставте нульову перевірку перед додаванням.

5
додано
Добре, це написано в документації. Але, це тільки мені це дуже counterintuitive? Я дізнався, що нульовий рядок - це рядок, який не існує. І не відкриваючи дискусії, я просто не розумію, чому вони так робили. Зараз я стукаю головою по столу.
додано Автор ilomambo, джерело
@LastFreeNickname Не дійсно, коли рядок null не хоче/нічого не бачу. Якщо я використовую відладчик, я хочу перевірити змінну і побачити її значення як null . Здається, не так давно, що в курсі алгебри професор сказав, що є спеціальний символ для позначення порожнього набору, набір без елементів взагалі, який є аналогом нульового рядка. Показ щось для нульового рядка порушує узгодженість з тим самим визначенням null . Але це плаче над пролитою молоком, коли-небудь я сподіваюся дізнатися причину.
додано Автор ilomambo, джерело
Я думаю, що ви заплутали нуль і порожній рядок. Як ви говорите (String) null - це рядок, який не існує, який представлений "null" в домені String. З іншого боку, порожній "" рядок не дивно має представлення "". Коли ви налагоджуєте або друкуєте будь-яку змінну String, ви хочете побачити, що вона вказує на null, тому має сенс.
додано Автор LastFreeNickname, джерело

Це просто так. null додається як "null" . Аналогічно, коли ви друкуєте null з System.out.println (null) , ви друкуєте "null" .

Щоб уникнути цього методу, який повертає рядки getString() для перевірки null

public String getString() {
    ...
    if (result == null) {
        return "";
    }
}
4
додано

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

Я сподіваюся, що додавання нульового рядка взагалі не додаватиметься!

Але це додає. Причина такої поведінки StringBuilder прихована в деталях реалізації методу append (Object obj) , який веде до AbstractStringBuilder # append (String str) метод, який визначається наступним чином:

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

Він чітко визначає, що якщо вхід String є нульовим, то він змінюється на лінійний рядок "null", а потім обробляється далі.

Як я можу отримати StringBuilder.append() елегантним способом прийняти нульовий рядок, а не перетворити його на літеральний рядок "null".

Потрібно перевірити вказаний String для null , а потім продовжити. Наприклад:

String s = getString();
StringBuffer buf = new StringBuffer();
//Suppose you want "Hello "" world"
buf.append("Hello ");
buf.append(s==null?" world" : s+" world");
2
додано
Строго кажучи, JLS не є остаточним для цього. JLS фактично визначає семантику оператора "+". Можна стверджувати, що це зручне збіг, що StringBuilder.append (null) реалізує необхідну поведінку. (Я впевнений, що це не випадковість, але ви зрозуміли мою думку ...)
додано Автор Stephen C, джерело
@StephenC: Так, ви праві .. Моя помилка ..
додано Автор Vishal K, джерело

Він веде себе так, оскільки null не є порожнім String , як ви думаєте про нього. Порожній String буде new String (""); . В основному метод append() додає "null" , якщо він отримує значення null як параметр.

2
додано
Я не сказав "порожній рядок", я сказав "рядок, який не існує"
додано Автор ilomambo, джерело

Це допоможе вам

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

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
додано

Як щодо написання утиліти

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

або цей тернарний оператор дуже зручний.

0
додано

Можна також написати декоратор для StringBuilder, який може перевіряти, що ви хочете:

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

Приклад використання:

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

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

За допомогою цього рішення ви не повинні змінювати класи POJO.

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

Там! Я зробив це в одному рядку:)

0
додано
:-) немає питання це дуже елегантно :-)
додано Автор ilomambo, джерело

Один рядок?

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

зроблено. Але це не має сенсу, тому що потрібно двічі викликати getString()

Як було запропоновано перевірити збирання в метод getString()

0
додано
ІТ КПІ - Java
ІТ КПІ - Java
436 учасників

android_jobs_ua
android_jobs_ua
120 учасників

Публикуем вакансии и запросы на поиск работы по направлению Android. Здесь всё: full-time, part-time, remote и разовые подработки.

Mobile Dev Jobs UA
Mobile Dev Jobs UA
20 учасників

Публикуем вакансии и запросы на поиск работы по направлению iOS, Android, Xamarin, RN и т.д.