دانستنی‌ها

چرا کاتلین؟ ۸ دلیل که می‌تواند برنامه‌نویسان جاوا را برای تغییر قانع کند. (قسمت دوم)

جاوا به چه شکلی در می‌آمد اگر کسی آن‌ را امروز از نو طراحی می‌کرد؟ احتمالا چیزی شبیه کاتلین

در قسمت اول این مطلب، در مورد سینتکس و تایپ‌سیستم زبان کاتلین خواندیم. در صورتی که هنوز قسمت اول را نخوانده‌اید پیشنهاد می‌شود ابتدا آن را مطالعه کنید.

۳- امنیت دربرابر null

یکی از اهداف طراحی کاتلین، از بین بردن یا کاهش مشکلات ناشی از رفرنس‌های نال است. کاتلین بیشتر از هر زبان دیگری که من استفاده کرده‌ام، از مشکل بزرگ NullPointerException جلوگیری می‌کند.

در واقع تایپ‌سیستم کاتلین بین رفرنس‌هایی که می‌توانند مقدار نال نگه دارند (رفرنس nullable) و آن‌ها که نمی‌توانند تفاوت قائل می‌شود و کامپایلر سازگاری بین رفرنس‌ها موقع انتساب را بررسی می‌کند. برای مثال تایپ String در کاتلین نمی‌تواند هرگز نال باشد اما متغیری از جنس ?String می‌تواند نال باشد (تفاوت در ? است). در مثال زیر این ایده را می‌توان دقیق تر مشاهده کرد.

فراخوانی‌های امن

اگر رفرنس s از نوع نالبل باشد و کامپایلر نتواند مطمئن شود که الزاما s زمانی که دی‌رفرنس می‌شود نال نیست، در نتیجه s.length باعث کامپایل ارور می‌شود. اگرچه می‌توان از s?.length استفاده کرد. در صورت استفاده از این عملگر، اگر s نال نباشد، s.length برمی‌گردد و اگر نال باشد، کلا نال برمی‌گردد. در نتیجه تایپ نتیجه‌ی s?.length برابر ?Int خواهد بود و کامپایلر مطمئن می‌شود که از آن به درستی استفاده شده باشد.

از آن‌جا که تابع println می‌تواند مقدار null را هندل کند، صدا کردن تابع println(s?.length) امن است و در صورت وجود، طول و در غیر این صورت null را چاپ می‌کند.

عملگر Elvis

بسیار پیش می‌آید که در برنامه‌نویسی بخواهیم از یک ویژگی یک متغیر nullable استفاده کنیم، پس ابتدا چک می‌کنیم که آیا نال است یا نه. اگر نال نبود که از مقدارش استفاده می‌کنیم اما اگر نال بود، یک مقدار پیش‌فرض را به کار می‌گیریم.

مثال بدون استفاده از Elvis

در کاتلین عملگر «نال‌ یکپارچه» (Nul coalescing با علامت :?) وجود دارد که البته بیشتر به نام عملگر Elvis شناخته می‌شود. سمت چپ عملگر، عبارتیست که می‌تواند نال باشد. اگر عبارت سمت چپ نال باشد، به جای خودش، مقدار سمت راست به عنوان مقدار محاسبه شده از مجموعه‌ی عملگر و عملوندها برمی‌گردد. با عملگر Elvis، مثال بالا می‌تواند به شکل زیر نوشته شود:

(یادداشت مترجم: می‌توانید از این لینک بیشتر درباره عملگر «نال یکپارچه» بخوانید. همچنین اگر ترجمه بهتری برای Null coalescing سراغ دارید در کامنت‌ها برایمان بنویسید.)

عملگر «!!»

در کاتلین می‌‌توانید از عملگر !! استفاده کنید تا کامپایلر چک‌های مربوط به نال را انجام ندهد. کد زیر را در نظر بگیرید:

در اینجا به کامپایلر می‌گوییم که «ببین من مطمئن هستم که اینجا s نال نیست و مسئولیتش را می‌پذیرم.» در نتیجه این کار باعث خطای کامپایل نمی شود ولی در عوض، اگر s نال باشد باعث پرتاب استثنای NullPointerException می‌شود.

۴- توابع و برنامه‌نویسی تابعی

توابع در کاتلین، آبجکت‌های مرتبه بالا هستند، به این معنی که نیازی نیست حتما داخل یک کلاس قرار داشته باشند.

همچنین کاتلین امکانات بیشتری در زمینه توابع به برنامه‌نویسان می‌دهد که باعث کدهای تمیزتر و گویاتر بدون افت خوانایی می‌شود. برای مثال می‌ توانید تایپ خروجی، آکولاد باز و بسته و عبارت return از یک تابع را حذف کنید و توابع تک خطی داشته باشید. (مشابه عبارت های لامبدا در جاوا)

برای مثال کد زیر

می‌توانید به شکل زیر نیز نوشته شود:

همچنین کاتلین (مانند سی‌پلاس‌پلاس) مقدار پیش‌فرض برای آرگومان‌های تابع را پشتیبانی می‌کند. در جاوا مرسوم است که یک سازنده، سازنده‌های دیگری از همان کلاس را صدا کند، مثلا اگر کلاس ArrayList را خودمان بنویسیم، ممکن است چند سازنده به شکل زیر داشته باشیم:

اما در کاتلین به کمک مقدار پیش‌فرض برای آرگومان‌های تابع، به یک سازنده تقلیل می‌یابد.

توابع مرتبه بالاتر

کاتلین همچنین از توابع مرتبه بالاتر زیر پشتیبانی می‌کند، به این معنی که می‌توانید توابع را به عنوان آرگومان به توابع دیگر پاس دهید و به عنوان مقدار برگشتی از تابع برگردانید یا هردو. همچنین مثل جاوا، کاتلین از عبارات لامبدا و کلوژرها پشتیبانی می‌کند، به این ترتیب نیازی نیست تعریف کامل تابع را بنویسیم. حتی بیشتر از آن، اگر لامبدا فقط یک پارامتر ورودی داشته باشد، نیازی به مشخص کردن آن نیست و به شکل ضمنی نام «it» می‌گیرد.

از قابلیت‌های دیگر کاتلین برای پشتیبانی از برنامه‌نویسی تابعی می‌توان به بهینه‌سازی فراخوانی دم ( tail recursion) و بسیاری از توابع زبان‌های برنامه‌نویسی تابعی برای کار با لیست اشاره کرد.

مثال زیر از این مطلب که توسط مارکین مُسکالا نوشته‌شده استخراج شده‌است.

در حالات مشخصی، کامپایلر کاتلین  از توابع درون‌خطی (inline) هم پشتیبانی می‌کند یعنی کامپایلر به جای فراخوانی تابع، بدنه‌اش را قرار می‌دهد. درون‌خطی کردن یک تابع می‌تواند باعث بهبود کارایی برنامه با از بین بردن سربار فراخوانی و برگشت از تابع بشود اما از طرفی می‌تواند اندازه کد تولیدشده را افزایش دهد برای همین باید از این تکنیک آگاهانه استفاده شود.

مناسب‌ترین جا برای اجرای این تکنیک، برای عبارات لامبدا است، در این صورت کامپایلر برای هر عبارت لامبدا لازم نیست یک تابع جدید تولید کند.

۵- کلاس‌های داده

کلاسی که از ابتدا به منظور نگهداری داده طراحی می‌شوند، به نام کلاس موجودیت یا کلاس بیزینس یا کلاس داده نامیده می‌شوند و معمولا در پایگاه‌داده نگهداری می‌شوند. در جاوا معمولا این کلاس‌ها متدهای کمی دارند. مثلا متدهای دسترسی فیلد‌ها (getter و setterها)  و متدهای استاندارد toString و hashCode و equals و احتمالا clone.

اگرچه محیط های توسعه‌ی مدرن، می‌توانند با تولید کد استاندارد برای این متدها در زمان شما صرفه‌جویی کنند، اما کاتلین نوع خاصی از کلاس با نام «کلاس داده» فراهم می‌کند که دیگر اصلا نیازی به پیاده‌سازی این‌ متدها در آن نیست.

برای فهم این بهبود، دو کد زیر را مقایسه کنید. کد اول به زبان جاوا معادل کد دوم به زبان کاتلین است. کد جاوا با متد‌هایی که Eclipse برای ما تولید کرده حدود ۱۸۰ خط (!)‌ بدون کامنت می‌شود در حالی که پیاده‌سازی آن با کاتلین کمتر از ۱۰ خط می‌‌شود!

کد جاوا:

کد کاتلین:

 

رکورد‌ها در جاوا

طراحان زبان جاوا مشغول اضافه کردن قابلیت Record به جاوا هستند که می‌تواند امکانات مشابه کلاس‌های داده را به برنامه‌نویسان بدهد.

توضیح مترجم: این قابلیت از نسخه‌ی ۱۴ جاوا به شکل نمایشی اضافه شده‌است.

سینتکس آن در جاوا به این شکل خواهد بود.

 

۶- توابع و فیلد‌های افزودنی

امکانات افزودنی (Extension) به ما این امکان را می‌دهد که بدون کمک وراثت و بدون تغییر مستقیم تعریف یک کلاس، به آن قابلیت‌هایی اضافه کنیم.

یک تابع افزودنی به این شکل تعریف می‌شود که قبل از نام تابع، نام کلاس می‌اید. مثلا  فرض کنید که می‌خواهیم به کلاس String یک تابع اضافه کنیم. کد زیر یک مثال ساده را نشان می‌دهد که تابع isLong را که یک boolean برمی‌گرداند را پیاده‌سازی می‌کنیم.

 

همچنین به شکل مشابه می‌توانیم یک فیلد به کلاس فعلی اضافه کنیم. مثلا کلاس داده‌ای Student را که در بالا نوشتیم به همان شکل در نظر بگیرید. می‌خواهیم بدون تغییر دادن کد اولیه، فیلد‌های fullName و age را به Student اضافه کنیم (مانند کد زیر).

دقت کنید که در پیاده‌سازی fullName ابتدا چک کردیم فیلدِ نالبل middleInitial برابر نال نباشد.

 

اگرچه این دو فیلد جدید به شکل فیلد extension اضافه شدند،  اما همچنین می‌توان به شکل فیلد محاسبه‌ای (computed properties)  در تعریف کلاس Student نیز آن‌ها را تعریف کرد (به شرط اینکه به کد منبع Student دسترسی داشته باشیم).

فیلد محاسبه‌ای، معادل یک متد get() در جاواست که پشت آن فیلدی وجود ندارد و محاسبه می‌شود.

توجه داشته باشید که صدا کردن یک تابع extension و استفاده از فیلد‌های extension، در زمان کامپایل توسط کامپایلر پیدا می‌شود، به این معنی که تابع افزودنی که قرار است صدا شود در زمان کامپایل از روی تایپ متغیر (و نه تایپ واقعی آن شی در زمان اجرا) شناسایی می‌شود و در آن‌ها چندریختی معنایی ندارد.

 

(این مطلب ادامه دارد)

 

منبع: https://www.infoworld.com/article/3396141/why-kotlin-eight-features-that-could-convince-java-developers-to-switch.html

با اندکی تغییر و تلخیص

.

.

.

.

با ما همراه باشید


آدرس کانال تلگرام: JavaCupIR@

آدرس اکانت توییتر: JavaCupIR@

آدرس صفحه اینستاگرام: javacup.ir

صفحه ویرگول: javcup

آدرس گروه لینکدین: Iranian Java Developers

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا