Я действительно зациклился на ситуации, когда что-то может быть нулевым в Котлине. Когда значение не может быть нулевым – это понятно. Но как обращаться с ситуацией, когда по умолчанию значение может быть пустым. Взгляните на этот пример:
abstract class MapActivity: AppCompatActivity(), OnMapReadyCallback { lateinit var map: GoogleMap fun initializeMap() { val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment mapFragment.getMapAsync(this) } override fun onMapReady(map: GoogleMap?) { this.map = map //error here } }
Поэтому я должен справиться с такой ситуацией:
override fun onMapReady(map: GoogleMap?) { if (map != null) this.map = map }
Но что, если map равно null . Что мне делать в этом случае? Я столкнулся с этой проблемой при использовании java.
Хорошо, в java, если карта равна нулю, мы получим NPE.
И для меня NPE лучше, чем ничего. Программа падает, и это сигнал для меня, что-то не так, и я должен это исправить. Таким образом, я не могу даже проследить свою проблему и почему это происходит. Да, мы можем написать что-то вроде:
override fun onMapReady(map: GoogleMap?) { if (map != null) { this.map = map } else { Log.d("Activity","MapIsNull") } }
и есть какой-то смысл в этом коде, да. Но у меня все еще есть сомнения в том, что касается всей нулевой вещи безопасности. Например, безопасные звонки – это странная вещь, которая производит null и (на мой взгляд) heisenbugs или ошибки, которые трудно поймать.
Может кто-нибудь объяснить мне, что здесь происходит, и каковы наилучшие методы использования нулевой безопасности.
Я уверен, что эта вещь полезна, потому что я не такой умный, как ребята в JB
Документация OnMapReadyCallback прямо говорит о том, что он «предоставляет непустой экземпляр GoogleMap». Следовательно, тип параметра вашего метода onMapReady
должен использовать onMapReady
тип.
Обратите внимание, что при реализации интерфейса Java в Kotlin у вас есть выбор: объявлять параметры метода реализации как nullable или non-null. IDE отмечает их как nullable, потому что это безопасный по умолчанию, но вы можете изменить их на ненулевые, если это то, что вам нужно.
О работе с нулями: давайте представим, что вам нужно иметь метод fun onMapReady(map: GoogleMap?)
установил бы map
свойств класса.
У вас есть два варианта дизайна :
1) Ваше приложение не будет работать, если map
равна null
class A { lateinit var map: GoogleMap // never ever `null` fun onMapReady(map: GoogleMap?) { map = map!! // throws } fun onMapReady2(map: GoogleMap?) { map = map ?: throw Exception("in case you care for the exception") } }
2) Null
имеет для вас особое значение и в порядке:
class A { var map: GoogleMap? = null // map is not ready yet fun onMapReady(map: GoogleMap?) { map = map } }
Конечно, если ваш случай – это случай (1), и вы можете управлять API, то у вас никогда не должно быть нулевой map: GoogleMap?
приемника map: GoogleMap?
потому что это путает пользователя класса.
Я вижу два отдельных вопроса:
1. Нулевая обработка
2. Специфический синтаксис Kotlin для нулевой обработки
Во-первых, это не специфическая проблема котлина. Это зависит, и @voddan в значительной степени объяснил доступные стратегии.
Относительно синтаксиса. Если вы интересуетесь только ненулевыми значениями, используйте let ()
override fun onMapReady(map: GoogleMap?) { map?.let { m -> // do your staff // 'm' now is definitely not null } }
Если вы хотите знать, когда оно равно null, используйте обычный блок if-else
override fun onMapReady(map: GoogleMap?) { if (map != null) { this.map = map } else { Log.d("Activity","MapIsNull") }
Sidenotes:
1] @Cedric есть хорошая статья о kotlin's let () и друзья
2] ознакомьтесь с комментарием @ yole . когда переопределение забавы в аргументах IDEA может быть помечено как «?», но на самом деле это не так.