Вы используете фигурные скобки для дополнительного обзора? [закрытый]

Что такое 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 ).

38
задан Community 23 May 2017 в 12:02
поделиться

12 ответов

Я делаю, если я использую ресурс, который я хочу освободить в определенное время, например:

void myfunction()
{
  {
  // Open serial port
     SerialPort port("COM1", 9600);
     port.doTransfer(data);
  } // Serial port gets closed here.

  for(int i = 0; i < data.size(); i++)
     doProcessData(data[i]);
  etc...
}
50
ответ дан Adam Pierce 27 November 2019 в 03:00
поделиться

Это имеет свое место, но я не думаю, что выполнение его так, чтобы $foo мог быть одной переменной здесь и различной переменной там в той же функции или другом (логичный, а не лексический) объем, является хорошей идеей. Даже при том, что компилятор может понять, что отлично, это кажется слишком вероятным для создания жизни трудной для людей, пытающихся считать код.

0
ответ дан Dave Sherohman 27 November 2019 в 03:00
поделиться

Я соглашаюсь с agartzke. Если Вы чувствуете, что необходимо сегментировать большие логические блоки кода для удобочитаемости, необходимо полагать, что рефакторинг очищает занятых и нарушенных участников.

0
ответ дан Peter 27 November 2019 в 03:00
поделиться

Да, я использую эту технику из-за RAII. Я также использую эту технику в плоскости C, так как это приближает переменные вместе. Конечно, я должен думать о разбивании функций еще больше.

Одна вещь я делаю, который, вероятно, стилистически спорен, помещается вводная изогнутая фигурная скобка на строке объявления или исправляет комментарий о нем. я хочу уменьшить количество потраченного впустую вертикального пространства. Это основано на рекомендации Руководства по стилю C++ Google. .

/// c++ code
/// references to boost::test
BOOST_TEST_CASE( curly_brace )
{
  // init
  MyClass instance_to_test( "initial", TestCase::STUFF ); {
    instance_to_test.permutate(42u);
    instance_to_test.rotate_left_face();
    instance_to_test.top_gun();
  }
  { // test check
    const uint8_t kEXP_FAP_BOOST = 240u;
    BOOST_CHECK_EQUAL( instance_to_test.get_fap_boost(), kEXP_FAP_BOOST);
  }
}
1
ответ дан piyo 27 November 2019 в 03:00
поделиться

Я только использую его, когда я должен выпустить что-то посредством RAII и даже тогда только, когда это уже должно быть выпущено, я возможно могу (выпуск блокировки, например).

5
ответ дан Jasper Bekkers 27 November 2019 в 03:00
поделиться

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

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

Лично я ненавижу простые плавающие/повисшие фигурные скобки (хотя поэтому мы - строгий магазин отступа стиля баннера), и я ненавижу маркер комментария:

// yuk!
some code
{
scoped code
}
more code

// also yuk!
some code
/* do xyz */ {
    scoped code
    }
some more code

// this I like
some code
DoXyz: {
    scoped code
    }
some more code

Мы рассмотрели использование, "если (верный) {" потому что спецификация Java конкретно говорит, они будут оптимизированы далеко в компиляции (как будет все содержание, если (ложь) - это будет функция отладки), но я ненавидел это в нескольких местах, я попробовал его.

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

3
ответ дан Lawrence Dol 27 November 2019 в 03:00
поделиться

Это может быть благо для генераторов кода. Предположим, что у Вас есть Embedded SQL (ESQL) компилятор; это могло бы хотеть преобразовать SQL-оператор в блок кода, для которого нужны локальные переменные. При помощи блока это может снова использовать имена фиксированной переменной много раз, вместо того, чтобы иметь необходимость создать все переменные с отдельными именами. Предоставленный, это не слишком твердо, но это более твердо, чем необходимый.

6
ответ дан Jonathan Leffler 27 November 2019 в 03:00
поделиться

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

#if defined( UNIX )
    if( some unix-specific condition )
#endif
    {
        // This code should always run on Windows but 
        // only if the above condition holds on unix
    }

Код, созданный для Windows, не видит если, только фигурные скобки. Это намного более ясно, чем:

#if defined( UNIX )
    if( some unix-specific condition ) {
#endif
        // This code should always run on Windows but 
        // only if the above condition holds on unix
#if defined( UNIX )
    }
#endif
11
ответ дан Graeme Perrow 27 November 2019 в 03:00
поделиться

C++ :

Иногда необходимо представить дополнительный уровень фигурной скобки объема для многократного использования имен переменной, когда имеет смысл делать так:

switch (x) {
    case 0:
        int i = 0;
        foo(i);
        break;
    case 1:
        int i = 1;
        bar(i);
        break;
}

код выше не компилирует. Необходимо сделать его:

switch (x) {
    case 0:
        {
            int i = 0;
            foo(i);
        }
        break;
    case 1:
        {
            int i = 1;
            bar(i);
        }
        break;
}
15
ответ дан J Blaz 27 November 2019 в 03:00
поделиться

Наиболее распространенное "нестандартное" использование обзора этого, которое я использую регулярно, должно использовать ограниченное по объему взаимное исключение.

void MyClass::Somefun()
{
    //do some stuff
    {
        // example imlementation that has a mutex passed into a lock object:
        scopedMutex lockObject(m_mutex); 

        // protected code here

    } // mutex is unlocked here
    // more code here
}

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

16
ответ дан Marcin 27 November 2019 в 03:00
поделиться

Я не использовал бы фигурные скобки с этой целью по паре причин.

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

  2. фигурные скобки Представления для обзора для многократного использования имен переменной только собирается привести к беспорядку и проблеме в коде.

Просто мои 2 цента, но я видел много этих типов вещей в других материалах лучшей практики.

40
ответ дан abatishchev 27 November 2019 в 03:00
поделиться

Как другие сказали, это довольно распространено в C++ из-за всесильного RAII (приобретение ресурса является инициализацией), идиома/шаблон.

Для программистов Java (и возможно C#, я не знаю) это будет внешним понятием, потому что основанные на "куче" объекты и GC уничтожают RAII. По моему скромному мнению, способность поместить объекты на стек является самым большим единственным преимуществом C++ по Java и заставляет правильно написанный C++ кодировать НАМНОГО более чистый, чем правильно написанный код Java.

6
ответ дан Drew Hall 27 November 2019 в 03:00
поделиться
Другие вопросы по тегам:

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