چطور از دست "!!" خلاص شیم

اگر نیاز به آشنایی اولیه با کاتلین و نحوه تعریف نوع‌ها در اون رو دارید توصیه میکنم اول این مقاله رو بخونید. لازم هست قبل از خواندن با چند اصطلاح آشنا بشیم:mutable : تغییر پذیرimmutable : تغییر ناپذیرا NullSafety یکی از بهترین ویژگی های کاتلین هست. این ویژگی باعـث میشه که شما در سطح زبان برنامه نویسی به تهی پذیری (nullability) فکر کنید در نتیجه میتونید از بسیاری NullPointerException های مخفی که در جاوا معموله، خلاص بشید. وقتی از ابزارهای اتوماتیک برای تبدیل کد جاوا به کاتلین استفاده میکنید کلی !!(بخوانید دو علامت تعجب) میبینید. تا حد ممکن باید تعداد اونها رو کم کرد دلیلش اینه که !! به این معنی هست که "در این نقطه پتانسیل وجود KotlinNullPointerException هندل نشده وجود داره".کاتلین مکانیزم های هوشمندانه ای برای رفع این مشکل داره، شاید با یکی یا چندتا از اونها آشنا باشید. ما اینجا 6 راه برای حل این مشکل معرفی میکنیم.1- استفاده از val به جای varکاتلین باعث میشه شما در سطح زبان به immutability فکر کنید و این خیلی عالیه. val فقط خواندنی و var (متغیر variable) قابل تغییر هست. توصیه میشه تا حد ممکن متغیرهاتون رو فقط خواندنی تعریف کنید. چون Thread safe هست و با برنامه نویسی تابعی هماهنگه. اگه متغیرهای val رو به صورت immutable به کار ببریم لازم نیست دیگه نگران تهی پذیری باشیم. در نظر داشته باشید val میتونه mutable هم باشه(اگر برای متغیرتون getter ننوشتید متغیرتون immutable هست و لازم نیست نگران چیزی باشید).2- استفاده از lateinitگاهی شما نمی‌تونید از متغیرهای immutable استفاده کنید. برای مثال در اندروید متغیری رو در نظر بگیرید که در onCreate مقداردهی میشه. برای این مورد kotlin کلمه کلیدی lateinit رو داره.شما میتونید این کد رو: https://gist.github.com/77c47875f9f758f872e13dd2987bfda7.git به این تغییر بدید https://gist.github.com/4b60a9be3917011db7d8f55ec7ca72d0.git در نظر داشته باشید اگه متغیر lateinit رو قبل از مقدار دهی استفاده کنید باعث خطا از نوع UninitializedPropertyAccessException میشه.متاسفانه نمی​‌​​​​​توان متغیر lateinit از انواع داده primitive(مثل Int) تعریف کرد. برای این نوع داده‌ها میتونید از Delegates استفاده کنید:private var mNumber: Int by Delegates.notNull<Int>()3. استفاده از lazyبا استفاده از by lazy می​​​‌تونید متغیرهای immutable و تهی ناپذیر تعریف کنید، که در زمان مناسب مقدار دهی بشوند.مثال: https://gist.github.com/78e00bd6dac15ea8d577e8b79bcf8b09.git ا messageView فقط در اولین استفاده، با اجرای بلاک کد lazy مقداردهی میشه و در استفاده‌های بعدی همون مقدار مورد استفاده قرار میگیره.این طوری ما می‌تونیم حتی متغیرهایی که در لحظه ایجاد شدن شی آماده مقداردهی نیست‌اند(مثل ویوها در اندروید) رو هم immutable تعریف کنیم.4. استفاده از letکد زیر نمونه معمولی از ارورهای زمان کامپایل تو کاتلین هست:اینجا Smart cast ممکن نیست.شاید همیشه براتون سوال شده باشه که چرا کامپایلر کاتلین اینجا نمیتونه Smart cast رو انجام بده. دلیلش اینه که ممکنه thread دیگه ای غیر از threadی که null بودن رو داره چک میکنه این متغیر رو null کنه.این مشکل آزار دهنده است. من این رو مطمئن ام که این متغیر نمیتونه بعد از چک برای null نبودن تغییر کرده باشه. خیلی از برنامه نویس‌ها این مشکل رو با !! سریع حل میکنن: https://gist.github.com/dd5ad562bf28c9ebaee5de088b4dc3f6.git اما راه حل بهتر برای این مشکل استفاده از متد let هست: https://gist.github.com/f7f4bf39089f0cfdfff470c9c580d718.git اگه mPhotoUrl نال باشه کد داخل let اجرا نمیشه.5. استفاده از Elvis operatorاگر ممکنه متغیر null باشه و ی مقدار پیش فرض جایگزین برای موقع null بودن در نظر گرفته اید Elvis operator خیلی به درد می‌خوره. ما میتونید این کد رو: https://gist.github.com/bc57427e3a931bcb376619143742628e.git به این تغییر بدیم: https://gist.github.com/731df413c7a04decc44c25ec92ff925f.git نتیجه اش اینه میشه که علاوه بر حل مشکل !! کد کمتر و تمیزتری داریم.(کد کمتر اکثرا با کد بهتر مترادفه :) )6. زیر پا گذاشتن مقرراتباز هم مواردی وجود داره که شما مطمئنید که متغیر با اینکه تهی پذیر هست نمی‌تونه null باشه و اگر null باشه ی باگی تو کدتون وجود داره که باید اصلاح بشه. با این حال !! به شما چیزی جز ی Exception بدون پیام که دیباگ کردنش مشکله نمیده. پس بهتره از متدهایی مثل requireNotNull یا checkNotNull به همراه پیغام خطای مناسب استفاده کنید که دیباگ کردن رو هم راحتتر میکنه.تغییر این کد: https://gist.github.com/b768016f18024427b3c788988f7e1dbb.git به این کد: اhttps://gist.github.com/35ba25bc013e7c5738f9f14d58e30993.git نتیجه گیریاگر از 6 تکنیک بالا استفاده کنید می‌توانید همه !!ها رو از کدتون حذف کنید. وقتی با این کار کد شما مطمئن‌تر، تمیزتر و دیباگ آن راحتتر خواهد بود. اگر راههای دیگه ای برای حذف !! میشناسید یا مشکلی در این مطلب هست تو کامنت ها بهم اطلاع بدید.