Является ли улавливание исключения нулевого указателя запахом кода?
недавно мой коллега написал в каком-то коде, чтобы поймать исключение нулевого указателя вокруг всего метода и вернуть один результат. Я указал, как могло быть любое количество причин для нулевого указателя, поэтому мы изменили его на защитную проверку для одного результата.
однако, ловить NullPointerException просто казалось мне неправильным. На мой взгляд, исключения нулевого указателя являются результатом плохого кода и не должны быть ожидаемым исключением в система.
есть ли случаи, когда имеет смысл поймать исключение нулевого указателя?
18 ответов:
да, подхватить какую-нибудь
RuntimeExceptionпочти всегда запах кода. Элемент C2 Wiki кажется, согласны.исключением, вероятно, будут некоторые специально защитные фрагменты кода, которые запускают в значительной степени случайный код из других модулей. Примерами для таких оборонительных сооружений были бы времени, ThreadPools / исполнители и система плагинов.
Я могу придумать ровно одно использование Для когда-либо поймать
NullPointerException:catch (NullPointerException) { ApplyPainfulElectricShockToProgrammer(); }
Мне иногда приходилось ловить исключение nullpointer из-за ошибки в третьей части библиотеки. Библиотеке мы бросили это исключение, и мы ничего не могли поделать.
в таком случае ОК, чтобы поймать его, иначе нет.
Это зависит.
насколько опытен этот сотрудник? Делает ли он это по невежеству/лени или для этого есть действительно веская причина? (как будто это главная нить выше всего остального и никогда не должна умирать? )
90% случаев перехвата исключения во время выполнения неверно, 99% перехвата исключения NullPointerException неверно ( если причина "я получал их много..." тогда весь программист ошибается, и вы должны смотреть заботиться о остальную часть кода он делает)
но при некоторых обстоятельствах ловить NullPointerException может быть приемлемым.
В общем, я думаю, что это запах кода; мне кажется, что защитные проверки лучше. Я бы расширил это, чтобы охватить большинство непроверенных исключений, за исключением циклов событий и т. д. которые хотят поймать все ошибки для отчетности / ведения журнала.
исключение, о котором я могу думать, было бы вокруг вызова библиотеки, которая не может быть изменена и которая может генерировать исключение нулевого указателя в ответ на некоторый сбой утверждения, который трудно предварительно проверить.
смешно
Я только что нашел то, что не должно быть сделано на работе:
public static boolean isValidDate(final String stringDateValue) { String exp = "^[0-9]{2}/[0-9]{2}/[0-9]{4}$"; boolean isValid = false; try { if (Pattern.matches(exp, stringDateValue)) { String[] dateArray = stringDateValue.split("/"); if (dateArray.length == 3) { GregorianCalendar gregorianCalendar = new GregorianCalendar(); int annee = new Integer(dateArray[2]).intValue(); int mois = new Integer(dateArray[1]).intValue(); int jour = new Integer(dateArray[0]).intValue(); gregorianCalendar = new GregorianCalendar(annee, mois - 1, jour); gregorianCalendar.setLenient(false); gregorianCalendar.get(GregorianCalendar.YEAR); gregorianCalendar.get(GregorianCalendar.MONTH); gregorianCalendar.get(GregorianCalendar.DAY_OF_MONTH); isValid = true; } } } catch (Exception e) { isValid = false; } return isValid; }baaad:)
разработчик хотел, чтобы календарь вызывал исключения такого рода:
java.lang.IllegalArgumentException: DAY_OF_MONTH at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2316) at java.util.Calendar.updateTime(Calendar.java:2260) at java.util.Calendar.complete(Calendar.java:1305) at java.util.Calendar.get(Calendar.java:1088)для аннулирования значений...
Да это работает, но это не очень хорошая практика...
создание исключения (особенно заполнение трассировки стека) стоит намного больше, чем просто проверка данных вручную без исключения...
это плохо, но он может производить оптимизированный байт-код.
Если Целое Число
iнеnullбольшую часть времени, а затем проверить снижает общую производительность. Сама проверка стоит 3 Инструкции (0-4). Весь случай после этого принимает 7 инструкций (0-14).public class IfNotNull { public Integer i; public String getIAsString() { if (i != null) { return i.toString(); } else { return ""; } } } public java.lang.String getIAsString(); Code: 0: aload_0 1: getfield #2 // Field i:Ljava/lang/Integer; 4: ifnull 15 7: aload_0 8: getfield #2 // Field i:Ljava/lang/Integer; 11: invokevirtual #3 // Method java/lang/Integer.toString:()Ljava/lang/String; 14: areturn // <- here we go 15: ldc #4 // String 17: areturnпосле EAFP подход, который распространен в мире Python. Элемент
nullдело будет дорогостоящим, но нам нужно только 4 Инструкции (0-7) дляnot nullслучае.public class TryCatch { public Integer i; public String getIAsString() { try { return i.toString(); } catch (NullPointerException npe) { return ""; } } } public java.lang.String getIAsString(); Code: 0: aload_0 1: getfield #2 // Field i:Ljava/lang/Integer; 4: invokevirtual #3 // Method java/lang/Integer.toString:()Ljava/lang/String; 7: areturn // <- here we go 8: astore_1 9: ldc #5 // String a 11: areturn Exception table: from to target type 0 7 8 Class java/lang/NullPointerExceptionкто знает, если JIT-компилятор может оптимизировать это?
Это конечно.
большую часть времени ваши переменные не должны быть нулевыми для начала. Многие новые языки выходят со встроенной поддержкой ненулевых ссылочных типов , то есть типов, которые гарантированно никогда не будут нулевыми.
для тех случаев, когда входящее значение может быть null, вам нужно сделать проверку. Но исключения-это определенно плохой способ сделать это.
оператор if принимает, возможно, три инструкции к выполнению и местные (то есть, вы делаете чек в том же месте, что вам нужна гарантия).
использование исключения, с другой стороны, может занять гораздо больше инструкций -- система пытается найти метод, терпит неудачу, просматривает таблицу исключений для соответствующего обработчика исключений, прыгает туда, выполняет обработчик и снова прыгает. Кроме того, проверка потенциально нелокальна. Если ваш код что-то вроде этого:
try return contacts.find("Mom").getEmail() catch (NullPointerException e) return nullвы не знаете, является ли NPE был брошен в "getEmail" или в "find".
техническое худшее решение для очень, очень распространенного шаблона, написанного более запутанным способом? Это не ранг, но это определенно плохо пахнет:/
единственное место, где вы должны поймать исключение NullPointerException (или, в частности, просто любой Throwable), находится на какой-то границе верхнего уровня или системы, так что ваша программа не полностью сбой и может восстановиться. Например, настройка страницы ошибок в интернете.xml предоставляет catch-all, чтобы веб-приложение могло восстанавливаться из исключения и уведомлять пользователя.
улавливание исключения нулевого указателя действительно зависит от контекста ... нужно стремиться избегать строгих абсолютных правил ... правила должны применяться в контексте-хотите поймать это исключение и поместить все программное обеспечение в какое - то стабильное состояние-ничего не делая или почти ничего. Все такие правила кодирования должны быть хорошо поняты
на этом этапе вы смотрите на свою трассировку аудита программного обеспечения ... что вы должны делать и обнаружить источник этого исключение.
идея о том, что исключение нулевого указателя никогда не должно возникать, должна быть проверена. Сначала сделайте статический анализ ... (что сложнее, если входит сторонний код / компоненты), а затем выполните исчерпывающий поиск пространства состояний с использованием соответствующих инструментов.
x
ловить NPEs (любой RTEs на самом деле) может быть необходимо, чтобы чисто завершить приложение на основе Swing-GUI.
edit: в этом случае это обычно делается через UncaughtExceptionHandler, хотя.
Как насчет этого:
try { foo.x = bar; } catch (NullPointerException e) { // do whatever needs to be done }как микро-оптимизация, когда foo может быть null, но почти никогда не бывает?
идея такова:
явная нулевая проверка принимает одну машинную инструкцию
С другой стороны, нулевая проверка во второй версии может быть выполнена, позволяя нулевому доступу произойти, ловя SIGSEGV и бросая исключение NullPointerException. Это бесплатно, если объект не НОЛЬ.
давно у меня было одно применение. Особенно глупая библиотека будет бросать NullPointerException при запросе объекта в коллекции по ключу, и объект не был найден. Не было никакого другого способа посмотреть вверх, кроме как с помощью ключа, и не было никакого способа проверить, существует ли объект.
некоторое время спустя мы загрузили поставщика и начали изменять библиотеку. Теперь библиотека выдает лучшее исключение (мое изменение) и имеет функцию проверки (чужое изменение).
конечно я всегда в конечном итоге ровно одна строка внутри блока try. Еще немного и я сам был бы виноват в плохом коде.
Я пытаюсь гарантировать результаты от моих интерфейсов, но если какая-то библиотека или чей-то код может привести к нулю в результате, и я ожидаю, что гарантия поймает его, возможно, будет жизнеспособной. Конечно, то, что вы делаете, как только поймаете его, зависит от вас. Иногда просто не имеет смысла проверять null, и если вы поймаете его, у вас есть какой-то другой метод решения проблемы, который может быть не так хорош, но выполняет работу.
что я говорю, это использовать исключения для того, что вы можете, его довольно хорошо функция языка.
Перехват исключения NullPointerException может быть полезен, если ваш метод вызывает внешний интерфейс (или API SOAP), и есть вероятность, что возвращаемое значение может быть Null. Кроме того, нет огромной выгоды для ловли этих исключений.
Это действительно зависит от определения интерфейса. Неструктурированная обработка NPE так же плоха, как перехват исключения или Throwable.
нули полезны для идентификации неинициализированного состояния, а не с помощью пустой строки или max_int или что-то еще. Как только место, где я регулярно использую null, находится в местах, где объект обратного вызова не имеет отношения.
Мне очень нравится аннотация @Nullable, предоставленная ГИС.
http://code.google.com/docreader/#p=google-guice&s=google-guice&t=UseNullable
для устранения возникновению исключительных ситуаций типа NullPointerException в ваша кодовая база, вы должны быть дисциплинированы о нулевых ссылках. Мы были успешный в этом, следуя и применение простого правила:
каждый параметр не является нулевым, если явно указать. компания Google Собрания библиотека и JSR-305 имеют простые API, чтобы получить нули под управление. Предварительное условие.checkNotNull может использоваться для быстрого сбоя, если значение null ссылка найдена, и @Nullable может используется для аннотирования параметра, который допускает значение null.
Guice запрещает null по умолчанию. Оно будет откажитесь вводить null, не справившись с a ProvisionException вместо этого. Если значение null допустимый вашим классом, вы можете аннотировать поле или параметр с помощью @Обнуляемого типа. Guice распознает любые @ Nullable аннотации, например Эде.УМД.цезий.findbugs.комментарии.Значение null или javax.аннотация.Значение null.
да в Java есть необходимость проверить NullPointerException.
бросается, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:
вызов метода экземпляра объекта null. Доступ или изменение поля нулевого объекта. Принимая длину null, как если бы это был массив. Доступ или изменение слотов null, как если бы это был массив. Выбрасывание null, как если бы это было выбрасываемое значение.
приложения должны выбрасывать экземпляры этого класса, чтобы указать на другое незаконное использование нулевого объекта.
исключение NullPointerException на других языках при чтении текстовых файлов (например, XML), записи которых не были проверены на правильный формат ASCII и формат записи.
Если программист новичок, он может иметь привычку ловить каждое исключение, которое останавливает его, чтобы получить конечный результат. Это не должно развлекать рецензентов кода.
ловить любое исключение RuntimeException плохо. Но если это действительно необходимо, то комментарий в коде будет действительно полезен для будущих программистов, которые будут работать над этим кодом. Если вы не можете написать разумный комментарий для ловли их, то вы должны избегать их. период.
Comments