Строка по сравнению с StringBuilder

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

208
задан Peter Mortensen 12 July 2013 в 23:06
поделиться

19 ответов

Да, различие в производительности является значительным. См. статью KB" , Как улучшить выполнение конкатенации строк в Визуальном C#".

я всегда пытался кодировать для ясности сначала, и затем оптимизировать для производительности позже. Это намного легче, чем выполнение его наоборот! Однако видевший огромное различие в производительности в моих приложениях между этими двумя, я теперь думаю об этом немного более тщательно.

К счастью, это относительно просто для выполнения анализа производительности кода для наблюдения, где Вы проводите время, и затем изменить его для использования StringBuilder при необходимости.

228
ответ дан BartoszKP 23 November 2019 в 04:41
поделиться

StringBuilder будет работать лучше от точки зрения памяти. Что касается обработки, разница во времени выполнения может быть незначительной.

-2
ответ дан DevelopingChris 23 November 2019 в 04:41
поделиться

Мой подход должен был всегда использовать StringBuilder при конкатенации 4 или больше строк ИЛИ Когда я не знаю, как может, конкатенации должны произойти.

Хорошая похожая статья производительности о нем здесь

0
ответ дан Peter Mortensen 23 November 2019 в 04:41
поделиться

Как правило ползунка, если я должен установить значение строки несколько раз, или если существуют, любой добавляет к строке, то это должен быть строковый разработчик. Я видел приложения, которые я записал в прошлом прежде, чем узнать о строковых разработчиках, которые имели огромный след памяти, который просто, кажется, продолжает расти и расти. Изменение этих программ для использования строкового разработчика значительно сократило использование памяти. Теперь я клянусь строковым разработчиком.

0
ответ дан Peter Mortensen 23 November 2019 в 04:41
поделиться

При выполнении большой конкатенации строк используйте StringBuilder. Когда Вы конкатенируете со Строкой, Вы создаете новую Строку каждый раз, израсходовав больше памяти.

Alex

0
ответ дан Alex Fort 23 November 2019 в 04:41
поделиться

StringBuilder, вероятно, предпочтителен. Причина состоит в том, что это выделяет больше места, чем в настоящее время необходимый (Вы определяете номер символов) уезжать, комната для будущего добавляет. Тогда будущие добавляют, которые помещаются в текущий буфер, не требуют никакого выделения памяти или сборки "мусора", которая может быть дорогой. В целом я использую StringBuilder для сложной строки concatentation или нескольких форматирование, затем преобразовываю в нормальную Строку, когда данные завершены, и я хочу неизменный объект снова.

0
ответ дан deemer 23 November 2019 в 04:41
поделиться

Конкатенация строк будет стоить Вам больше. В Java можно использовать или StringBuffer или StringBuilder на основе потребности. Если Вы хотите синхронизируемую, и ориентированную на многопотоковое исполнение реализацию, пойдите для StringBuffer. Это будет быстрее, чем Конкатенация строк.

, Если Вам не нужна синхронизируемая или Ориентированная на многопотоковое исполнение реализация, пойдите для StringBuilder. Это будет быстрее, чем Конкатенация строк и также быстрее, чем StringBuffer, поскольку их не synchorization наверху.

1
ответ дан raffimd 23 November 2019 в 04:41
поделиться

Строка и StringBuilder на самом деле оба неизменны, StringBuilder создал в буферах, которые позволяют его размеру управляться более эффективно. То, когда StringBuilder должен изменить размеры, - когда он перераспределен на "куче". По умолчанию это измерено к 16 символам, можно установить это в конструкторе.

, например,

сурьма StringBuilder = новый StringBuilder (50);

1
ответ дан capgpilk 23 November 2019 в 04:41
поделиться

В дополнение к предыдущим ответам первая вещь я всегда делаю, когда размышление о проблемах как это должно создать маленькое тестовое приложение. В этом приложении выполните некоторый тест синхронизации для обоих сценариев и лично убедитесь, которые более быстры.

, по моему скромному мнению, добавляя 500 + строковые записи должны определенно использовать StringBuilder.

1
ответ дан RichS 23 November 2019 в 04:41
поделиться

Я видел значительное увеличение производительности от использования EnsureCapacity(int capacity) вызов метода на экземпляре StringBuilder перед использованием его для любого строкового устройства хранения данных. Я обычно называю это на строке кода после инстанцирования. Это имеет тот же эффект, как будто Вы инстанцируете StringBuilder как это:

var sb = new StringBuilder(int capacity);

Этот вызов выделяет необходимую память заранее, которая вызывает меньше выделений памяти приблизительно во время Append() операции. Необходимо высказать образованное предположение на том, в каком количестве памяти Вы будете нуждаться, но для большинства приложений это не должно быть слишком трудно. Я обычно допускаю ошибку на стороне немного слишком много памяти (мы говорим 1k или так).

2
ответ дан Dawid Ferenczy Rogožan 23 November 2019 в 04:41
поделиться

Используя строки для конкатенации может привести к сложности во время выполнения на порядке O(n^2).

, Если Вы используете StringBuilder, существует намного меньше копирования памяти, которая должна быть сделана. С StringBuilder(int capacity) можно увеличить производительность, если можно оценить, как большой финал String будет. Даже если Вы не точны, необходимо будет, вероятно, только вырастить способность StringBuilder пару раз, который может помочь производительности также.

2
ответ дан Dawid Ferenczy Rogožan 23 November 2019 в 04:41
поделиться

Я полагаю, что StringBuilder быстрее, если у Вас есть больше чем 4 строки, необходимо добавить вместе. Плюс он может сделать некоторые прохладные вещи как AppendLine.

2
ответ дан Gilligan 23 November 2019 в 04:41
поделиться

StringBuilder лучше для создания строки от многих непостоянных значений.

при создании строки от большого количества постоянных величин, таких как несколько строк значений в HTML или XML-документе или других блоках текста, можно сойти с рук просто добавление к той же строке, потому что почти все компиляторы делают "сворачивание констант", процесс сокращения дерева синтаксического анализа, когда у Вас есть набор постоянного управления (это также используется, когда Вы пишете что-то как int minutesPerYear = 24 * 365 * 60). И для простых случаев с непостоянными значениями, добавленными друг другу, компилятор.NET уменьшит Ваш код до чего-то подобного тому, что StringBuilder делает.

, Но когда Ваш добавлять не сможет быть уменьшен до чего-то более простого компилятором, Вы захотите StringBuilder. Как fizch указывает, это, более вероятно, произойдет в цикле.

3
ответ дан Dawid Ferenczy Rogožan 23 November 2019 в 04:41
поделиться

StringBuilder сокращает количество выделений и присвоений по стоимости используемой дополнительной памяти. Используемый правильно, это может полностью устранить необходимость компилятора для выделения больших и больших строк много раз, пока результат не найден.

string result = "";
for(int i = 0; i != N; ++i)
{
   result = result + i.ToString();   // allocates a new string, then assigns it to result, which gets repeated N times
}

по сравнению с

String result;
StringBuilder sb = new StringBuilder(10000);   // create a buffer of 10k
for(int i = 0; i != N; ++i)
{
   sb.Append(i.ToString());          // fill the buffer, resizing if it overflows the buffer
}

result = sb.ToString();   // assigns once
8
ответ дан Harsh 23 November 2019 в 04:41
поделиться

Этот сравнительный тест показывает, что регулярная конкатенация быстрее при объединении 3 или меньшего количества строк.

http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/

StringBuilder может сделать очень существенное улучшение в использовании памяти, особенно в Вашем случае добавления 500 строк вместе.

Рассматривают следующий пример:

string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
    buffer += i.ToString();
}
return buffer;

, Что происходит в памяти? Следующие строки создаются:

1 - "The numbers are: "
2 - "0"
3 - "The numbers are: 0"
4 - "1"
5 - "The numbers are: 01"
6 - "2"
7 - "The numbers are: 012"
8 - "3"
9 - "The numbers are: 0123"
10 - "4"
11 - "The numbers are: 01234"
12 - "5"
13 - "The numbers are: 012345"

Путем добавления тех пяти чисел до конца строки мы создали 13 строковых объектов! И 12 из них были бесполезны! Ничего себе!

StringBuilder решает эту проблему. Это не "изменяемая строка", как мы часто слышим (, все строки в.NET неизменны ). Это работает путем хранения внутреннего буфера, массива символа. Вызов Добавляет (), или AppendLine () добавляет строку к вакууму в конце массива символов; если массив является слишком небольшим, он создает новый, больший массив и копирует буфер там. Таким образом в примере выше, StringBuilder, возможно, только понадобился бы единый массив для содержания всех 5 дополнений к строке - в зависимости от размера ее буфера. Можно сказать StringBuilder, насколько большой его буфер должен быть в конструкторе.

23
ответ дан Matt Trunnell 23 November 2019 в 04:41
поделиться

StringBuilder предпочтителен , ЕСЛИ Вы делаете несколько циклов, или подцепляет Вашу передачу кода на вилку... однако, для Чистой производительности, если можно сойти с рук ЕДИНСТВЕННЫЙ строковое объявление, тогда это намного более производительно.

, Например:

string myString = "Some stuff" + var1 + " more stuff"
                  + var2 + " other stuff" .... etc... etc...;

более производительно, чем

StringBuilder sb = new StringBuilder();
sb.Append("Some Stuff");
sb.Append(var1);
sb.Append(" more stuff");
sb.Append(var2);
sb.Append("other stuff");
// etc.. etc.. etc..

В этом случае, StringBuild можно было считать более удобным в сопровождении, но не более производителен, чем единственное строковое объявление.

9 раз из 10, хотя... используют строкового разработчика.

На ноте стороны: представьте в виде строки +, var также более производителен что строка. Подход формата (обычно), который использует StringBuilder внутренне (когда в сомнении... проверяют отражатель!)

28
ответ дан calebjenkins 23 November 2019 в 04:41
поделиться

Для разъяснения то, что Gillian сказала приблизительно 4 строки, если у Вас есть что-то вроде этого:

string a,b,c,d;
 a = b + c + d;

тогда это быстрее использовало бы строки и плюс оператор. Это вызвано тем, что (как Java, как Eric указывает), это внутренне использует StringBuilder автоматически (На самом деле, это использует примитив, который StringBuilder также использует)

Однако, если то, что Вы делаете, ближе к:

string a,b,c,d;
 a = a + b;
 a = a + c;
 a = a + d;

Тогда необходимо явно использовать StringBuilder..Net, автоматически не создает StringBuilder здесь, потому что это было бы бессмысленно. В конце каждой строки "a" должен быть (неизменной) строкой, таким образом, это должно было бы создать и расположить StringBuilder на каждой строке. Для скорости необходимо было бы использовать тот же StringBuilder, пока Вы не сделаны, создав:

string a,b,c,d;
StringBuilder e = new StringBuilder();
 e.Append(b);
 e.Append(c);
 e.Append(d);
 a = e.ToString();
54
ответ дан James Curran 23 November 2019 в 04:41
поделиться

В.NET StringBuilder еще быстрее, чем добавление строк. Я вполне уверен, что в Java, они просто создают StringBuffer под капотом, когда Вы добавляете строки, таким образом, существует, не действительно различие. Я не уверен, почему они еще не сделали этого в.NET.

2
ответ дан Eric Z Beard 23 November 2019 в 04:41
поделиться
2
ответ дан 23 November 2019 в 04:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: