2015-09-08 3 views
1

В Java объекты по умолчанию инициализируются до null.Написание кода без использования пула

Недавно я наткнулся на этот ответ, делая исследование обработки NPE правильно: https://softwareengineering.stackexchange.com/a/187225

Ниже мой основной вынос от должности:

Если вы не установите переменную NULL вам никогда не может иметь неожиданный нуль.

Не допускать нулевые параметры

Я задавался вопросом, как справиться с этим в Java и Android. Многие из отчетов о сбоях, которые я вижу на панели инструментов разработчика, это NPE, и я заметил, что в своем коде я использую null, чтобы проверить, могу ли я продолжить операцию.

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

Например, при использовании API Карт Google необходимо объявить объект GoogleMap. Способ, которым я в настоящее время настроен, - объявить переменную как член моего Activity, а затем инициализировать ее во время onCreate(). К сожалению, в течение onResume(), когда я звоню .clear() на GoogleMap, изредка поле будет null. Я не могу воспроизвести эту ошибку в своей собственной среде, что привело меня к тому, что я больше занимался обработкой NPE.

В другом (очень популярном) поле здесь: Avoiding != null statements, В верхнем и принятом ответе предлагаются три стратегии для решения этой проблемы.

  1. assert заявление. На первый взгляд, это больше похоже на код unit-testing/debug, тем более что Java игнорирует assert по умолчанию.
  2. Null объект шаблон. Это, вероятно, самый привлекательный из представленных решений, поскольку он заканчивается тем, что выглядит и чувствует себя чище. Однако, работая с внешними библиотеками, я не уверен, что это вариант. Расширение внешней библиотеки кажется беспорядочным.
  3. Попытка/улов. Это просто сложно. Так как null настолько распространен в Java, этот код в конечном итоге плотно переплетается с try/catch для всего, что может быть нулевым, или заканчивается тем, что блокировки кода блокированы, что ошибки ловушки не позволят значительно повысить точность обработки последствий ,

Вопрос в том, есть ли другой вариант? Может быть, парадигма кодирования, которую я могу использовать, или какой-то встроенный модуль, который может это исправить?

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

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

+0

Также проверьте [Дополнительно] (https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) «Конструкция», введенная (наконец) в Java 8 –

+0

Почему очистка карта сделает его нулевым? @ ɐuıɥɔɐɯ не эксперт Android, но не уверен, что вы можете использовать его в Android SDK – Dici

+0

Очистка карты не делает ее нулевой. По какой-то причине иногда отображение * уже имеет значение NULL, когда достигается оператор '.clear()'. – nukeforum

ответ

0

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

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

Утверждение, как правило, следует избегать. Это приводит к утверждению о завершении, если условие не выполняется. Другими словами, это не изящный выход. Оператор A! = Null достигает той же цели, что и утверждение, но с возможностью реагировать на условие, а не останавливать программу.

try/catch является мощным в тех случаях, когда вы можете столкнуться с условиями гонки. Это особенно полезно при обращении к асинхронным библиотекам и библиотекам, которые активно используют операции, зависящие от сети. В GoogleMaps есть много методов, которые извлекают обновленную информацию на основе нового местоположения или кадра представления, и в некоторых случаях вы можете попытаться сделать вызов против объекта, который управляется библиотекой, которая может быть обновлена ​​в середине. Я обычно делаю предположение о состоянии гонки, когда я не могу легко воспроизвести NPE.

И, наконец, я не вижу смысла в попытке избежать проверки! = Null. Он фиксирует и позволяет вам реагировать на все условия, при которых попытка/улов не подходит, и ничего не стоит. Все логические операции - это операции O (1). Вы должны использовать миллиард или более из них назад, чтобы увидеть даже 1 секунду снижения производительности. Не стоит устранять головную боль.

+0

Вы первый параграф ошибочны. Поля * определены * как null для ссылок, это не соображение. Переменные * не могут быть запрошены до [определенно назначенного] (https://docs.oracle.com/javase/specs/jls/se7/html/jls-16.html), как это предусмотрено компилятором, поэтому нет необходимости рассматривать значение до этого. – Andreas

+0

Если вы столкнетесь с условиями гонки, вы не правильно закодировали свою многопоточную логику. Ответ на этот вопрос не является попыткой. – Andreas

+0

У Андреаса есть некоторые действительно хорошие моменты в этом конкретном ответе, но я чувствую, что общая тема правильная и проходит несколько параллельно с ответом Андреаса. @Stephan, можете ли вы взвесить комментарии Андреаса либо в комментариях, либо в качестве редактирования ответа? Я хотел бы принять этот ответ, но я не хочу вводить в заблуждение будущего читателя, принимая ответ с потенциальными недостатками. – nukeforum

1

Я действительно не понимаю, почему проверка нуля считается чем-то плохим, так как для предотвращения исключений верхнего уровня используют @NonNull и @Nullable аннотации, статический анализ действительно помогает.

+0

Это очень помогает при проблемах с компиляцией «null», но, к сожалению, не помогает предотвратить проблемы во время выполнения, как описано в моем примере. – nukeforum

+0

Большинство классов от android sdk имеют методы, которые обозначены как NULL, и наоборот, не должны иметь большого значения. Но если вы работаете с другим кодом, нет простого решения, кроме обнаружения его во время выполнения. Я предлагаю вам не проверять все на null, потому что это немного накладные расходы. – dtx12

0

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

ошибка, не где NullPointerException был брошен, ошибка, раньше в вашем коде, где переменная была установлена ​​в null без вас ожидает, что это будет.

Я бы сказал, что ошибка является вы не ожидали значения быть null, так что ошибка именно там, где происходит NPE.

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

Это говорит о том, что null является излишним, и иногда заменяется на исключение. Но все зависит от обстоятельств.

Посмотрите на интерфейс BlockingQueue на Java. Чтобы удалить значение из очереди, вы можете позвонить по номеру remove(), который выдает исключение, если очередь пуста, или вы можете позвонить по номеру poll(), который возвращает null. Если вы ожидаете значения, используйте remove(). Если вы знаете, что в очереди может быть пустым, и что вы справитесь с этим, используйте poll(). Не используйте remove() с пробкой для управления потоком.

+0

Интересная интерпретация. Не считаете ли вы, что «нулевое» состояние полностью является решением ошибки, не ожидающей, что значение будет «null»? – nukeforum

+0

@nukeforum Если возвращаемое значение может быть «специальным», «нулевым» или «пустым», вам все равно придется его обрабатывать. Особое значение всегда должно быть хорошо документировано, и вызывающему абоненту, вероятно, всегда придется обращаться с ним по-другому. Пустой объект предотвращает NPE, но это не гарантирует, что ваш код правильно обрабатывает специальное значение. На самом деле это может иметь противоположный эффект, который появляется, когда он не работает, без ошибок. Использование Java 8 «Необязательный» или аналогичная конструкция pre-8 делает четкое различие между «нормальным» и «специальным», а вызывающий должен * действовать соответствующим образом. – Andreas

+0

> Если возвращаемое значение может быть «специальным», «нулевым» или «пустым», вам все равно придется его обрабатывать. Это именно то, с чем я столкнулся. Я стараюсь избегать проверки «null» везде, но если я не проверю, все, что я могу сделать, это проглотить NPE или потерпеть потерю данных через пустой или нулевой объект. 'BlockingQueue' выглядит интересным, но я думаю, что могу просто вернуться к'! = Null'. – nukeforum

0

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

bool isEquals(string name) 
    { 
     if(tempData == name.toUpperCase()) // if name is null,a null reference will be throw 

     //... 
    } 

Даже если вы не избавитесь от NPE и попытаться/поймать, вы можете быть уверенным, когда приложение не удалось, и это большой плюс.

Смежные вопросы