Предисловие
Нулевые указатели - наиболее распространенные и раздражающие исключения, которые мы ненавидим. Чтобы не допустить исключений нулевых указателей, вы не должны писать много не нулевых суждений в вашем кодексе.
Java 8 представляет новый необязательный класс. Чтобы избежать возникновения нулевых указателей, нет необходимости писать большое количество суждений if(obj!=null) , если вам нужно загружать данные в необязательные, это контейнер, который завершает объект.
Говорят, что ни один программист, который столкнулся с исключением нулевого указателя, не является программистом Java, и NULL действительно вызвал много проблем. Java 8 представляет новый класс под названием java.util.Optional , чтобы избежать многих проблем, вызванных NULL.
Давайте посмотрим, какой вред может причинить нулевую ссылку. Сначала создайте класс компьютер, структура показана на рисунке ниже:
Что происходит, когда мы называем следующий код?
String version = computer.getSoundCard (). GetUSB (). GetVersion ();
Приведенный выше код, кажется, в порядке, но многие компьютеры (такие как Raspberry Pi) на самом деле не имеют звуковых карт, поэтому вызов метода getSoundcard() определенно вызовет исключение NULL Pointer.
Регулярный, но плохой метод - вернуть нулевую ссылку, чтобы указать, что у компьютера нет звуковой карты, но это означает, что метод getUSB () будет вызван на пустой ссылке, которая, очевидно, будет выбросить исключение управления во время работы программы, что приведет к прекращению работы программы. Подумайте об этом, как неловко появляться внезапно, когда ваша программа работает на клиентском компьютере?
Великая информатика, Тони Хоар, однажды написал: «Я думаю, что в 1965 году были созданы цитаты с нулевыми цитатами, что привело к потерям в миллиард долларов. Самое большое искушение для меня при использовании цитат NULL было так, что это было легко реализовать».
Итак, как мы можем избежать исключений по нулевым указателям при запуске программы? Вы должны быть настороже и постоянно проверять возможные нулевые указатели, например:
String version = "Неизвестно"; if (computer! = null) {soundcard soundcard = computer.getSoundCard (); if (soundcard! = null) {usb usb = soundcard.getusb (); if (usb! = null) {version = usb.getversion (); }}} Тем не менее, вы можете видеть, что приведенный выше код имеет слишком много нулевых проверок, и вся структура кода становится очень уродливой. Но мы должны использовать это суждение, чтобы гарантировать, что при запуске система не будет нулевых указателей. Просто раздражает судить, есть ли много таких пустых ссылок в нашем бизнес -коде, и это также приводит к плохой читабельности нашего кода.
Если вы забудете проверить, является ли значение пустым, нулевые ссылки также имеют большие потенциальные проблемы. В этой статье я докажу, что использование нулевых ссылок в качестве представления, где значений не существует, является плохим способом. Нам нужна лучшая модель, которая указывает на то, что значение не существует, вместо того, чтобы снова использовать нулевые ссылки.
Java 8 представила новый класс под названием java.util.Optional<T> , который был вдохновлен языком Haskell и Scala Language. Этот класс может содержать произвольное значение, как показано на рисунке и коде ниже. Вы можете думать о необязательном как о значении, которое может содержать значение. Если необязательно не содержит значения, то оно пусто, как показано на рисунке ниже.
Public Class Computer {private необязательный <SoundCard> SoundCard; public oppution <soundCard> getOundCard () {...} ...} открытый класс SoundCard {private необязательный <USB> USB; Публичный необязательный <usb> getusb () {...}} открытый класс USB {public String getVersion () {...}} Приведенный выше код показывает, что компьютер может заменить звуковую карту (звуковая карта может существовать или не существовать). Звуковая карта также может включать USB -порт. Это метод улучшения, и модель может более четко отразить, что данного значения может не существовать.
Но как справиться с Optional<Soundcard> ? В конце концов, вы хотите получить номер порта USB. Это очень просто. Необязательный класс содержит некоторые методы, чтобы справиться с тем, существует ли значение. По сравнению с нулевыми ссылками, необязательный класс заставляет вас справиться, связано ли значение, что избегает исключений нулевого указателя.
Следует отметить, что необязательный класс не заменяет нулевые ссылки. Напротив, чтобы упростить разработанную API для понимания, когда вы видите подпись функции, вы можете определить, может ли значение, которое нужно передавать функции, не может существовать. Это побуждает вас открыть необязательный класс для обработки фактического значения.
Принять необязательный режим
Сказав так много, давайте посмотрим на какой -то код! Давайте сначала посмотрим, как использовать необязательный для переписывания традиционного нулевого определения ссылок. В конце этой статьи вы поймете, как использовать необязательный.
String name = computer.flatmap (computer :: getoundCard) .flatmap (soundcard :: getusb) .map (usb :: getVersion) .orelse ("Неизвестно"); Создать дополнительные объекты
Можно создать пустой необязательный объект:
Необязательный <SoundCard> sc = необязательный. EMPTY ();
Далее следует создать необязательные, содержащие не нулевые значения:
SoundCard SoundCard = new SoundCard (); необязательный <SoundCard> sc = необязательный.of (SoundCard);
Если звуковая карта является нулевой, исключение NULL Pointer будет сброшено немедленно (это лучше, чем просто бросить ее, когда вы получите атрибут звуковой карты).
Используя ofnullable, вы можете создать дополнительный объект, который может содержать нулевые ссылки:
Необязательный <SoundCard> sc = необязательный. Офил (SoundCard);
Если звуковая карта является нулевой ссылкой, дополнительный объект пуст.
Обработка значений в необязательных
Теперь, когда существует необязательный объект, вы можете вызвать соответствующий метод, чтобы справиться с тем, существует ли значение в дополнительном объекте. По сравнению с обнаружением нуля, мы можем использовать метод ifpresent (), например, это:
Необязательный <SoundCard> SoundCard = ...; SoundCard.ifpresent (System.out :: println);
Таким образом, нет необходимости делать норм -обнаружение. Если дополнительный объект пуст, то любая информация не будет напечатана.
Вы также можете использовать метод isPresent() чтобы увидеть, действительно ли необходимый объект действительно существует. Кроме того, существует также метод get (), который возвращает включенные значения в необязательный объект, если присутствует. В противном случае будет брошена noshelementexception. Эти два метода можно использовать вместе, например, следующее, чтобы избежать исключений:
if (soundcard.ispresent ()) {system.out.println (soundcard.get ());} Тем не менее, этот метод не рекомендуется (он не имеет улучшения по сравнению с обнаружением нуля). Ниже мы обсудим обычные способы работы.
Возвращает значения по умолчанию и связанные с ними операции
При столкновении с NULL регулярная операция заключается в возвращении значения по умолчанию, которое вы можете использовать для реализации тройного выражения:
SoundCard SoundCard = MayBesoundCard! = NULL? MaybesoundCard: New SoundCard ("basic_sound_card"); Если вы используете дополнительный объект, вы можете использовать orElse() для переопределения. Когда необязательно пуст orElse() может вернуть значение по умолчанию:
SoundCard SoundCard = maybesoundCard.orelse (новая звуковая карта ("defaut")); Точно так же, когда необязательно пуст, OrelSethrow () может использоваться для бросания исключений:
SoundCard SoundCard = maybesoundCard.orelsethrow (allodalStateException :: new);
Используйте фильтр, чтобы фильтровать конкретные значения
Мы часто называем метод объекта, чтобы судить его свойства. Например, вам может потребоваться проверить, является ли номер порта USB конкретным значением. По соображениям безопасности вам необходимо проверить, является ли медицинское использование, указывающее на USB, нулевой, а затем вызовать метод getVersion() , например, это:
USB USB = ...;; if (usb! = Null && "3.0" .equals (usb.getversion ())) {System.out.println ("OK");} Если вы используете необязательно, вы можете использовать функцию фильтра для переписывания:
Необязательно <USB> может быть USB = ...; возможно, USB.Filter (usb -> "3.0" .equals (usb.getVersion ()) .ifpresent (() -> system.out.println ("ok")); Метод фильтра требует предиката напротив в качестве параметра. Если значение в необязательных существует и удовлетворяет прогнозированию, функция фильтра вернет значение, которое удовлетворяет условию; В противном случае будет возвращен пустой необязательный объект.
Используйте метод карты для извлечения и преобразования данных
Общим шаблоном является извлечение некоторых свойств объекта. Например, для объекта звуковой карты вам может потребоваться получить его объект USB, а затем определить его номер версии. Обычно наша реализация такая:
if (soundcard! = null) {usb usb = soundcard.getusb (); if (usb! = null && "3.0" .equals (usb.getversion ()) {System.out.println ("OK");}} Мы можем использовать метод MAP для переопределения этого обнаружения NULL, а затем извлечь объект типа объекта.
Необязательно <USB> usb = maybesoundcard.map (soundcard :: getusb);
Это то же самое, что и использование функции карты с использованием потока. Использование потока требует передачи функции в качестве параметра к функции карты, а функция передачи будет применена к каждому элементу в потоке. При потоковом пространстве и времени ничего не происходит.
Значение, содержащееся в необязательном, будет преобразовано функцией, пройденной (вот функция, которая получает USB от звуковой карты). Если необязательный объект является пространственным время, ничего не произойдет.
Затем мы объединяем метод карты и метод фильтра для фильтрации звуковых карт с номером версии USB, а не 3.0.
maybesoundcard.map (soundcard :: getusb) .filter (usb -> "3.0" .equals (usb.getversion ()) .ifpresent (() -> system.out.println ("ok")); Таким образом, наш код начинает выглядеть немного похоже на то, что мы дали в начале, без обнаружения нуля.
Прохождение дополнительного объекта с использованием функции плоской карты
Теперь был введен пример того, как рефакторировать код с использованием необязательного. Итак, как мы должны реализовать следующий код безопасным образом?
String version = computer.getSoundCard (). GetUSB (). GetVersion ();
Обратите внимание, что приведенный выше код извлекает другой объект из одного объекта, который может быть реализован с использованием функции карты. В предыдущей статье мы настроили Optional<Soundcard> на компьютере, а SoundCard содержит Optional<USB> , поэтому мы можем репроектировать код таким образом
String version = computer.map (computer :: getoundCard) .map (soundcard :: getusb) .map (usb :: getVersion) .orelse ("Неизвестно"); К сожалению, приведенный выше код собирает ошибки, так почему? Компьютерная переменная имеет тип Optional<Computer> , поэтому у нее нет проблем, вызывая функцию карты. Тем не менее, метод getSoundcard() возвращает Optional<Soundcard> , который возвращает объект типа Optional<Optional<Soundcard>> . После того, как вторая функция карты вызвана, вызов функции getUSB() становится незаконным.
На следующем рисунке описывается этот сценарий:
Реализация исходного кода функции карты заключается в следующем:
public <u> необязательный <u> map (function <? Super T ,? extends u> mapper) {objects.requirenonlull (mapper); if (! ispresent ()) return yate (); else {return optainAl.ofnullable (mapper.apply (value)); }} Можно видеть, что функция карты снова будет называть Optional.ofNullable() , что приведет к возврату Optional<Optional<Soundcard>>
Необязательно предоставляет функцию Flatmap, которая предназначена для преобразования значения дополнительного объекта (например, операции карты), а затем сжимать двухуровневый необязательный в один. На следующем рисунке показана разница между дополнительными объектами в преобразовании типа, вызывая карту и плоскую карту:
Итак, мы можем написать это:
String version = computer.flatmap (computer :: getoundCard) .flatmap (soundcard :: getusb) .map (usb :: getVersion) .orelse ("Неизвестно"); Первая плоская карта гарантирует, что возврат является Optional<Soundcard> а не Optional<Optional<Soundcard>> , а вторая плоская карта реализует ту же функцию, так что возвращение является Optional<USB> . Обратите внимание, что map() называется третий раз, потому что getVersion() возвращает строковый объект вместо необязательного объекта.
Мы, наконец, переписываем уродливый код вложенных нулевых проверок, которые мы только начали использовать, что очень читаемо, а также избегает возникновения исключений нулевого указателя.
Суммировать
В этой статье мы принимаем новый класс java.util.Optional<T> , предоставленный Java 8. Первоначальное намерение этого класса состоит не в том, чтобы заменить нулевые ссылки, а для того, чтобы помочь дизайнерам разработать лучшие API. Просто прочитайте подпись функции и узнайте, принимает ли функция значение, которое может существовать или не существовать. Кроме того, необязательно заставляет вас включить необязательно, а затем обрабатывать, существует ли значение, что заставляет ваш код избежать потенциальных исключений нулевого указателя.
Хорошо, вышеупомянутое содержимое этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.