Хорошим местом для начала является JavaDocs . Они охватывают это:
Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:
- Вызов метода экземпляра нулевого объекта.
- Доступ или изменение поля нулевого объекта.
- Выполнение длины null, как если бы это был массив.
- Доступ или изменение слотов с нулевым значением, как если бы это был массив.
- Бросать нуль, как если бы это было значение Throwable.
Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.
blockquote>Также, если вы попытаетесь использовать нулевую ссылку с
synchronized
, который также выдаст это исключение, за JLS :SynchronizedStatement: synchronized ( Expression ) Block
blockquote>
- В противном случае, если значение выражения равно null,
NullPointerException
.Как это исправить?
Итак, у вас есть
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 = "";
Либо метод
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 ).
Сравнительные тесты Производительности
Catch exception:
10,000 good: 63,668 ticks
10,000 bad: 6,435,609 ticks
Regex Pre-Screen:
10,000 good: 637,633 ticks
10,000 bad: 717,894 ticks
COM Interop CLSIDFromString
10,000 good: 126,120 ticks
10,000 bad: 23,134 ticks
Межглавный (Самый Быстрый) Ответ COM:
/// <summary>
/// Attempts to convert a string to a guid.
/// </summary>
/// <param name="s">The string to try to convert</param>
/// <param name="value">Upon return will contain the Guid</param>
/// <returns>Returns true if successful, otherwise false</returns>
public static Boolean TryStrToGuid(String s, out Guid value)
{
//ClsidFromString returns the empty guid for null strings
if ((s == null) || (s == ""))
{
value = Guid.Empty;
return false;
}
int hresult = PInvoke.ObjBase.CLSIDFromString(s, out value);
if (hresult >= 0)
{
return true;
}
else
{
value = Guid.Empty;
return false;
}
}
namespace PInvoke
{
class ObjBase
{
/// <summary>
/// This function converts a string generated by the StringFromCLSID function back into the original class identifier.
/// </summary>
/// <param name="sz">String that represents the class identifier</param>
/// <param name="clsid">On return will contain the class identifier</param>
/// <returns>
/// Positive or zero if class identifier was obtained successfully
/// Negative if the call failed
/// </returns>
[DllImport("ole32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = true)]
public static extern int CLSIDFromString(string sz, out Guid clsid);
}
}
<час> Нижняя строка: Если необходимо проверить, является ли строка гуидом, и Вы заботитесь о производительности, используете COM Interop.
, Если необходимо преобразовать гуид в Строковом представлении к Гуиду, используйте
new Guid(someString);
bool IsProbablyGuid(string s)
{
int hexchars = 0;
foreach(character c in string s)
{
if(IsValidHexChar(c))
hexchars++;
}
return hexchars==32;
}
Выполните потенциальный GUID, хотя RegEx или некоторый пользовательский код, который делает проверку работоспособности для обеспечения strig, по крайней мере, похожи на GUID и состоят только из допустимых символов (и возможно что это, кажется, соответствует полному формату). Если это не передаст возврат проверки работоспособности ошибка то - это, вероятно, избавится от подавляющего большинства недопустимых строк.
Тогда преобразовывают строку, как Вы имеете выше, все еще ловя исключение для нескольких недопустимых строк, которые проходят через проверку работоспособности.
Jon Skeet сделал анализ для чего-то подобного для парсинга Ints (прежде чем TryParse был в Платформе): Проверка, если строка может быть преобразована в Int32
Однако как AnthonyWJones, указала, что Вы, вероятно, не должны волноваться об этом.
Насколько я знаю, существует не что-то как Гуид. TryParse в mscrolib. Согласно Опорному источнику, тип Гуида имеет мегасложного конструктора, который проверяет все виды форматов гуида и пытается проанализировать их. Нет никакого вспомогательного метода, который можно назвать, даже через отражение. Я думаю, что необходимо искать сторонние синтаксические анализаторы Гуида или записать собственное.
Ну, вот regex, в котором Вы будете нуждаться...
^[A-Fa-f0-9]{32}$|^({|\\()?[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}(}|\\))?$|^({)?[0xA-Fa-f0-9]{3,10}(, {0,1}[0xA-Fa-f0-9]{3,6}){2}, {0,1}({)([0xA-Fa-f0-9]{3,4}, {0,1}){7}[0xA-Fa-f0-9]{3,4}(}})$
, Но это только для начинающих. Необходимо будет также проверить, что различные части, такие как дата/время в допустимых диапазонах. Я не могу вообразить этот являющийся немного быстрее, чем метод попытки/выгоды, который Вы уже обрисовали в общих чертах. Надо надеяться, Вы не получаете это много недопустимых GUID для гарантирования этого типа проверки!
Interop медленнее, чем просто ловля исключения:
В счастливом пути, с 10 000 Гуидов:
Exception: 26ms
Interop: 1,201ms
В несчастном пути:
Exception: 1,150ms
Interop: 1,201ms
Это более последовательно, но это также последовательно медленнее. Кажется мне, Вы были бы более обеспеченным конфигурированием Вашего отладчика, чтобы только повредиться на необработанных исключениях.
Я, по крайней мере, переписал бы его как:
try
{
value = new Guid(s);
return true;
}
catch (FormatException)
{
value = Guid.Empty;
return false;
}
Вы не хотите говорить "недопустимый GUID" относительно SEHException, ThreadAbortException или другого фатального или несвязанного материала.
Обновление : Запуск с.NET 4.0, существует новый набор методов, доступных для Гуида:
Действительно, те должны использоваться (если только для факта, что они "наивно" не реализованы с помощью выгоды попытки внутренне).
Вы не собираетесь любить это, но что заставляет Вас думать, что ловля исключения будет медленнее?
, Сколько неудачных попыток проанализировать GUID Вы ожидаете по сравнению с успешными?
Мой совет является использованием функция, Вы только что создали и представляете свой код. Если Вы находите, что эта функция является истинно горячей точкой тогда , фиксируют его, но не прежде.
В то время как это верно, что использование ошибок является более дорогим, большинство людей полагает, что большинство их GUID будет компьютером, сгенерированным, таким образом, TRY-CATCH
не является слишком дорогим, так как это только генерирует стоимость на CATCH
. Можно доказать это себе с простым тестом два (пользовательская общественность, никакой пароль).
Здесь Вы идете:
using System.Text.RegularExpressions;
/// <summary>
/// Validate that a string is a valid GUID
/// </summary>
/// <param name="GUIDCheck"></param>
/// <returns></returns>
private bool IsValidGUID(string GUIDCheck)
{
if (!string.IsNullOrEmpty(GUIDCheck))
{
return new Regex(@"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$").IsMatch(GUIDCheck);
}
return false;
}
если TypeOf ctype (myvar, Object) является Guid, то .....
из соображений удобства использования - всплывает отладчик
Если вы собираетесь использовать метод try / catch, вы можете добавить атрибут [System.Diagnostics.DebuggerHidden], чтобы убедиться, что отладчик не работает. не сломается, даже если вы настроили его на разрыв при броске.
ctor Guid в значительной степени является скомпилированным регулярным выражением, поэтому вы получите точно такое же поведение без накладных расходов на исключение.
Еще более крутым решением было бы динамическое инструментирование метода, заменяя «бросать новый» на лету.
I had a similar situation and I noticed that almost never was the invalid string 36 characters long. So based on this fact, I changed your code a little to get better performance while still keeping it simple.
public static Boolean TryStrToGuid(String s, out Guid value)
{
// this is before the overhead of setting up the try/catch block.
if(value == null || value.Length != 36)
{
value = Guid.Empty;
return false;
}
try
{
value = new Guid(s);
return true;
}
catch (FormatException)
{
value = Guid.Empty;
return false;
}
}
Private Function IsGuidWithOptionalBraces(ByRef strValue As String) As Boolean
If String.IsNullOrEmpty(strValue) Then
Return False
End If
Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^[\{]?[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}[\}]?$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function
Private Function IsGuidWithoutBraces(ByRef strValue As String) As Boolean
If String.IsNullOrEmpty(strValue) Then
Return False
End If
Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function
Private Function IsGuidWithBraces(ByRef strValue As String) As Boolean
If String.IsNullOrEmpty(strValue) Then
Return False
End If
Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^\{[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}\}$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function
Я голосую за ссылку GuidTryParse, опубликованную выше Джоном или аналогичное решение (IsProbablyGuid). Я напишу такой же для моей библиотеки преобразования.
Я думаю, что это совершенно неуместно, что этот вопрос должен быть таким сложным. «Есть» или «как» ключевое слово было бы прекрасно, ЕСЛИ Guid мог быть нулевым. Но по какой-то причине, даже если SQL Server это устраивает, .NET - нет. Почему? В чем ценность Guid.Empty? Это просто глупая проблема, созданная дизайном .NET, и меня действительно беспокоит, когда соглашения языка действуют сами по себе. На данный момент наиболее эффективным ответом было использование COM-взаимодействия, потому что Framework не справляется с этим изящно? "Может ли эта строка быть GUID?" должен быть вопрос, на который легко ответить.
Можно полагаться на сгенерированное исключение, пока приложение не появится в Интернете. В этот момент я просто настроился на атаку отказа в обслуживании. Даже если меня не «атаковали», я знаю, что какой-то Yahoo собирается обезглавить URL-адрес, или, возможно, мой отдел маркетинга отправит неверную ссылку,
Как только .net 4.0 станет доступен, вы можете использовать Guid.TryParse()
.