Строка к Интервалу в Java - Вероятные неправильные данные, должен избежать исключений

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

37
задан Chris Cudmore 3 December 2010 в 15:41
поделиться

12 ответов

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

Могло бы также быть полезным (в зависимости от приложения) для входа плохого входа, таким образом, можно проследить.

16
ответ дан Steve B. 27 November 2019 в 04:34
поделиться

Поместите некоторых если операторы перед ним. если (пустой указатель! = userdata)

-5
ответ дан arinte 27 November 2019 в 04:34
поделиться

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

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

, Если Вы не хотите иметь дело за исключением, просто оберните его в RuntimeException (или производный класс), и оно позволит Вам игнорировать исключение в своем коде (и уничтожить Ваше приложение, когда оно произойдет; это прекрасно слишком иногда).

Некоторые примеры того, как я обработал бы исключения NumberFormat: В данных конфигурации веб-приложения:

loadCertainProperty(String propVal) {
  try
  {
    val = Integer.parseInt(userdata);
    return val;
  }
  catch (NumberFormatException nfe)
  { // RuntimeException need not be declared
    throw new RuntimeException("Property certainProperty in your configuration is expected to be " +
                               " an integer, but was '" + propVal + "'. Please correct your " +
                               "configuration and start again");
    // After starting an enterprise application the sysadmin should always check availability
    // and can now correct the property value
  }
}

В GUI:

public int askValue() {
  // TODO add opt-out button; see Swing docs for standard dialog handling
  boolean valueOk = false;
  while(!valueOk) {
    try {
      String val = dialog("Please enter integer value for FOO");
      val = Integer.parseInt(userdata);
      return val; 
    } catch (NumberFormatException nfe) {
      // Ignoring this; I don't care how many typo's the customer makes
    }
  }
}

В веб-форме: возвратите форму пользователю с полезным сообщением об ошибке и шансом исправить. Большинство платформ предлагает стандартизованный способ проверки.

-2
ответ дан extraneon 27 November 2019 в 04:34
поделиться

Если можно избежать, чтобы исключения путем тестирования заранее как Вы сказали (isParsable ()), это могло бы быть лучше - но не все библиотеки были разработаны с этим в памяти.

я использовал Ваш прием, и он сосет, потому что отслеживания стека в моей встроенной системе печатаются независимо от того, если Вы ловите их или нет: (

-1
ответ дан Bill K 27 November 2019 в 04:34
поделиться

Вы могли использовать Целое число, которое может быть установлено в NULL, если у Вас есть плохое значение. При использовании java 1.6 он предоставит автоматическую упаковку/распаковывание Вам.

0
ответ дан Milhous 27 November 2019 в 04:34
поделиться

Вышеупомянутый код плох, потому что это эквивалентно как следующее.

// this is bad
int val = Integer.MIN_VALUE;
try
{
   val = Integer.parseInt(userdata);
}
catch (NumberFormatException ignoreException) { }

исключение проигнорировано полностью. Кроме того, волшебный маркер плох, потому что пользователь может передать в-2147483648 (Целое число. MIN_VALUE).

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

private boolean isUserValueAcceptable(String userData)
{
   return (    isNumber(userData)    
          &&   isInteger(userData)   
          &&   isBetween(userData, Integer.MIN_VALUE, Integer.MAX_VALUE ) 
          );
}

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

-1
ответ дан mjlee 27 November 2019 в 04:34
поделиться

Вот то, как я делаю это:

public Integer parseInt(String data) {
  Integer val = null;
  try {
    val = Integer.parseInt(userdata);
  } catch (NumberFormatException nfe) { }
  return val;
}

Тогда пустой указатель сигнализирует о недопустимых данных. Если Вы хотите значение по умолчанию, Вы могли бы изменить его на:

public Integer parseInt(String data,int default) {
  Integer val = default;
  try {
    val = Integer.parseInt(userdata);
  } catch (NumberFormatException nfe) { }
  return val;
}
2
ответ дан noah 27 November 2019 в 04:34
поделиться

Я собираюсь вновь заявить о мнении, которое stinkyminky высказывал к нижней части сообщения:

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

, Как только Вы знаете о надлежащей проверке ввода данных пользователем, тогда безопасно проанализировать его и проигнорировать, зарегистрировать или преобразовать в RuntimeException NumberFormatException.

Примечание, что этот подход требует, чтобы Вы рассмотрели свою модель в двух частях: бизнес-модель (Где мы на самом деле заботимся о наличии значений в международном или формате плавающем) и модель пользовательского интерфейса (где мы действительно хотим позволить пользователю вставлять независимо от того, что они хотят).

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

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

Обязательные библиотеки как Привязка JGoodies и JSR 295 делают этот вид вещи намного легче реализовать, чем это могло бы звучать - и много веб-платформ обеспечивают конструкции, которые отдельный пользователь ввел от фактической бизнес-модели, только заполнив бизнес-объекты после того, как проверка завершена.

С точки зрения проверки конфигурационных файлов (другой вариант использования представил в некоторых комментариях), это - одна вещь определить значение по умолчанию, если конкретное значение не определяется вообще - но если данные отформатированы неправильно (кто-то вводит, 'о', вместо 'нуля' - или они скопировали с MS Word, и все обратные галочки получили броский unicode символ), тогда своего рода системная обратная связь необходима (даже если это просто приводит приложение к сбою путем выдачи исключения на этапе выполнения).

3
ответ дан Kevin Day 27 November 2019 в 04:34
поделиться

Я уверен, что это - невоспитанность, но у меня есть ряд статических методов для класса Утилит, которые делают вещи как Utilities.tryParseInt(String value), который возвращается 0, если Строка unparseable и Utilities.tryParseInt(String value, int defaultValue), который позволяет Вам определять значение, чтобы использовать, если parseInt() выдает исключение.

я полагаю, что существуют времена, когда возврат известного значения на плохом входе совершенно приемлем. Очень изобретенный пример: Вы просите у пользователя дату в формате YYYYMMDD, и они дают Вам плохой вход. Может быть совершенно приемлемо сделать что-то как Utilities.tryParseInt(date, 19000101) или Utilities.tryParseInt(date, 29991231); в зависимости от требований программы.

6
ответ дан Grant Wagner 27 November 2019 в 04:34
поделиться

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

11
ответ дан asterite 27 November 2019 в 04:34
поделиться

Поскольку пользователь снабдил данными, Integer.parseInt обычно является неправильным методом, потому что это не поддерживает internationisation. java.text пакет является Вашим (подробным) другом.

try {
    NumberFormat format = NumberFormat.getIntegerInstance(locale);
    format.setParseIntegerOnly(true);
    format.setMaximumIntegerDigits(9);
    ParsePosition pos = new ParsePosition(0);
    int val = format.parse(str, pos).intValue();
    if (pos.getIndex() != str.length()) {
        // ... handle case of extraneous characters after digits ...
    }
    // ... use val ...
} catch (java.text.ParseFormatException exc) {
    // ... handle this case appropriately ...
}
17
ответ дан Tom Hawtin - tackline 27 November 2019 в 04:34
поделиться

Я думаю, что лучшая практика является кодом, который Вы показываете.

я не пошел бы для regex альтернативы из-за издержек.

1
ответ дан Shimi Bandiel 27 November 2019 в 04:34
поделиться
Другие вопросы по тегам:

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