Как работает StringBuffer? [Дубликат]

Что вы можете сделать по этому поводу?

Здесь есть много хороших ответов, объясняющих, что такое пустая ссылка и как ее отладить. Но очень мало о том, как предотвратить проблему или, по крайней мере, сделать ее легче поймать.

Проверить аргументы

Например, методы могут проверять разные аргументы, чтобы увидеть, null и выбросить ArgumentNullException, исключение, явно созданное для этой конкретной цели.

Конструктор для ArgumentNullException даже принимает имя параметра и сообщение как аргументы, чтобы вы могли точно сказать разработчику, что проблема.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

Использовать инструменты

Есть также несколько библиотек, которые могут помочь. Например, «Resharper» может предоставить вам предупреждения во время написания кода, особенно если вы используете их атрибут: NotNullAttribute

В разделе «Контракты кода Microsoft» вы используете синтаксис, например Contract.Requires(obj != null), который дает вам проверку выполнения и компиляцию: Представление кодовых контрактов .

Существует также «PostSharp», который позволит вам просто использовать такие атрибуты:

public void DoSometing([NotNull] obj)

Сделав это и сделав PostSharp частью вашего процесса сборки, obj будет проверяться на нуль во время выполнения. См. Ошибка проверки PostSharp

Решение для простого кода

Или вы всегда можете использовать свой собственный подход, используя простой старый код. Например, вот структура, которую вы можете использовать, чтобы поймать нулевые ссылки. Он моделируется после той же концепции, что и Nullable:

[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull where T: class
{
    private T _value;

    public T Value
    {
        get
        {
            if (_value == null)
            {
                throw new Exception("null value not allowed");
            }

            return _value;
        }
        set
        {
            if (value == null)
            {
                throw new Exception("null value not allowed.");
            }

            _value = value;
        }
    }

    public static implicit operator T(NotNull notNullValue)
    {
        return notNullValue.Value;
    }

    public static implicit operator NotNull(T value)
    {
        return new NotNull { Value = value };
    }
}

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

NotNull person = null; // throws exception
NotNull person = new Person(); // OK
NotNull person = GetPerson(); // throws exception if GetPerson() returns null

NotNull неявно отбрасывается в и из T, поэтому вы можете использовать его в любом месте, где это необходимо. Например, вы можете передать объект Person методу, который принимает значение NotNull:

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull person)
{
    Console.WriteLine(person.Value.Name);
}

Как вы можете видеть выше, как с помощью nullable, вы получите доступ к базовому значению через Value имущество. Кроме того, вы можете использовать явный или неявный листинг, вы можете увидеть пример с возвращаемым значением ниже:

Person person = GetPerson();

public static NotNull GetPerson()
{
    return new Person { Name = "John" };
}

Или вы даже можете использовать его, когда метод просто возвращает T (в этом случае Person), выполнив бросок. Например, следующий код будет похож на код выше:

Person person = (NotNull)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

Объединить с Extension

Объединить NotNull с методом расширения, и вы можете охватить еще больше ситуаций. Вот пример того, как может выглядеть метод расширения:

[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
    public static T NotNull(this T @this) where T: class
    {
        if (@this == null)
        {
            throw new Exception("null value not allowed");
        }

        return @this;
    }
}

И вот пример того, как он может быть использован:

var person = GetPerson().NotNull();

GitHub

Для вашей справки я сделал код выше, доступный на GitHub, вы можете найти его по адресу:

https://github.com/luisperezphd/NotNull

Функция родственного языка

В C # 6.0 был введен «оператор с нулевым условием», который немного помогает в этом. С помощью этой функции вы можете ссылаться на вложенные объекты, и если какой-либо из них null, все выражение возвращает null.

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

var address = country?.State?.County?.City;

Представьте, что country является объектом типа Country, который имеет свойство, называемое State и т. Д. Если country, State, County или City - null, то address will be null . Therefore you only have to check whether адрес is null`.

Это отличная функция, но она дает вам меньше информации. Это не делает очевидным, какой из 4 является нулевым.

Встроенный как Nullable?

C # имеет красивую стенографию для Nullable, вы можете сделать что-то нулевое помещая знак вопроса после такого типа int?.

Было бы неплохо, если бы у C # было что-то вроде структуры NotNull выше и имела аналогичную стенографию, может быть, восклицательный знак (!), чтобы вы могли написать что-то вроде: public void WriteName(Person! person).

14
задан xdevel2000 6 July 2010 в 08:17
поделиться

7 ответов

EDIT: Извинения. Ниже приведена информация о .NET StringBuilder и не имеет строгого отношения к исходному вопросу.

http://johnnycoder.com/blog/2009/01/ 05 / stringbuilder-required-capacity-algorithm /

StringBuilder выделяет пространство для подстрок, которые вы могли бы добавить к нему (подобно тому, как List создает пространство, которое он обертывает). Если вам нужна фактическая длина строки, используйте StringBuilder.Length.

1
ответ дан Alex Humphrey 1 September 2018 в 07:53
поделиться

Вот логика: если вы определяете новый экземпляр класса StringBuilder без конструктора, например new StringBuilder();, емкость по умолчанию равна 16. Конструктор может быть либо int, либо String. Для конструктора String значение по умолчанию рассчитывается следующим образом:

int newCapacity = string.length() + 16;

Для конструктора int мощность вычисляется так же

int newCapacity = intSpecified + 16;

. Если новый String добавляется к StringBuilder, а новая длина String больше текущей емкости, тогда мощность вычисляется следующим образом:

int newCapacity = (oldCapacity + 1) * 2;
1
ответ дан Ayokunle Paul 1 September 2018 в 07:53
поделиться

При добавлении к StringBuilder происходит следующая логика:

if (newCount > value.length) {
    expandCapacity(newCount);
}

, где newCount - количество требуемых символов, а value.length - текущий размер буфера.

expandCapacity просто увеличивает размер резервной копии char[]

Метод ensureCapacity() является общедоступным способом вызова expandCapacity(), и его документы говорят:

Обеспечивает, чтобы емкость была как минимум равна указанному минимуму. Если текущая емкость меньше аргумента, то новый внутренний массив выделяется с большей пропускной способностью. Новая емкость больше:

  • Аргумент minimumCapacity.
  • Дважды старая емкость плюс 2.

Если Аргумент minimumCapacity неположителен, этот метод не принимает никаких действий и просто возвращает.

12
ответ дан Bozho 1 September 2018 в 07:53
поделиться

Из API:

Каждый построитель строк имеет емкость. Пока длина символьной последовательности, содержащейся в построителе строк, не превышает емкость, нет необходимости выделять новый внутренний буфер. Если внутренний буфер переполняется, он автоматически становится больше.

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

int len = str.length();
int newCount = count + len;
if (newCount > value.length)
  expandCapacity(newCount);

Когда к нему добавляются данные, превышающие его емкость, он изменяется в соответствии со следующей формулой:

void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
    if (newCapacity < 0) {
        newCapacity = Integer.MAX_VALUE;
    } else if (minimumCapacity > newCapacity) {
    newCapacity = minimumCapacity;
}
    value = Arrays.copyOf(value, newCapacity);
}

Дополнительную информацию см. В файле src.zip, который поставляется вместе с JDK. (Над фрагментами, взятыми из 1.6 JDK)

1
ответ дан Catchwa 1 September 2018 в 07:53
поделиться

Вы можете войти в код JDK и посмотреть, как он работает, он основан на массиве char: new char[capacity], он похож на работу ArrayList ( Когда использовать LinkedList над ArrayList? ). Оба используют массивы как «эффективные аппаратные средства», трюк заключается в том, чтобы выделить большой кусок памяти и работать в нем до тех пор, пока у вас не закончится память, и для продолжения (развернуть / увеличить) понадобится следующий большой кусок.

0
ответ дан Community 1 September 2018 в 07:53
поделиться

Я попытаюсь объяснить это с помощью некоторого примера.

public class StringBuilderDemo {
     public static void main(String[] args) {
         StringBuilder sb = new StringBuilder();
         System.out.println(sb.length());
         System.out.println(sb.capacity());
     }
}

length() - длина последовательности символов в построителе, так как этот stringbuilder не содержит никакого содержимого, его длина будет 0.

capacity() - количество выделенных пространств символов. Когда вы пытаетесь построить stringbuilder с пустым содержимым, по умолчанию он принимает размер инициализации как length + 16, который равен 0 + 16. поэтому емкость вернет здесь 16.

Примечание. Емкость, возвращаемая методом capacity (), всегда больше или равна длине (обычно больше) и автоматически расширяется по мере необходимости, чтобы

Логика функции емкости:

  1. Если вы не инициализируете stringbuilder каким-либо контентом, емкость по умолчанию будет считаться 16 символами .
  2. Если вы инициализируете stringbuilder любым контентом, тогда емкость будет содержать длину контента + 16.
  3. Когда вы добавляете новый контент в объект строковой сборки, если текущей емкости недостаточно для выполнения новое значение, то оно будет увеличиваться на (предыдущая емкость массива + 1) * 2.

Этот анализ берет из фактического кода StringBuilder.java

11
ответ дан Dev4World 1 September 2018 в 07:53
поделиться

Эта функция делает что-то другое, чем вы ожидаете, - это дает максимальное количество символов, которые может храниться в памяти экземпляра StringBuilder.

String Builder должен прочитать

3
ответ дан InsertNickHere 1 September 2018 в 07:53
поделиться
Другие вопросы по тегам:

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