با وجود اینکه اخیرا بحثهای خیلی زیادی در مورد زبان برنامهنویسی کاتلین (Kotlin) صورت گرفته است اما شما ممکن است از خودتان بپرسید که چرا شما باید از آن استفاده کنید؟ کاتلین چه کاری انجام میدهد که جاوا انجام نمیدهد؟ خوب است که آدم همیشه یک احساس شکاکیت سالم نسبت به هر تکنولوژی جدیدی داشته باشد.
اما اینجا یک راز در مورد کاتلین وجود دارد: این زبان در کل کار خاصی انجام نمیدهد که جاوا نتواند انجام دهد. خیلی از چیزهایی که کاتلین میتواند انجام دهد جاوا با دستکاری کافی میتواند انجام دهد. این درست است که شما میتوانید همه کد را از پایه بدون کمک گرفتن از همهی ابزارها و افزونههایی که کاتلین به محیط توسعه اضافه میکند بنویسید. خیلی از اَپها از کاتلین استفاده نمیکنند و به خوبی هم کار میکنند. اما آنچه که کاتلین میتواند بهتر از جاوا انجام دهد این است که با ساده سازی کد و راحتی خوانش آن سرعت برنامهنویسی را افزایش میدهد. کاتلین این کار را با حذف بعضی از کدهای پر استفاده و پر حجم انجام میدهد.
در این پست ما بر دو موضوع ویژه تمرکز میکنیم: خصوصیات[کلاسها] و قابلیت نال شدن (nullability) در کاتلین.
خصوصیات[کلاسها]
اجازه دهید که با یک مدل یوزر شروع کنیم که وقتی که شما یک اَپ جدید را میسازید یک مدل رایج است . این مدل یوزر دو تا فیلد دارد: یک آدرس ایمیل (یک String) و سن یوزر (یک Integer). در جاوا ممکن است شما خودتان کد آن را بنویسد یا IDE شما کد آن را به صورت خودکار تولید کند. در مثال زیر این مدل با زبان جاوا نشان داده شده است:
public final class User { @NotNull private final String email; private final int age; public User(@NotNull String email, int age) { if (email == null) { throw new RuntimeException("Email can't be null"); } super(); this.email = email; this.age = age; } @NotNull public final String getEmail() { return this.email; } public final int getAge() { return this.age; } public String toString() { return "User(email=" + this.email + ", age=" + this.age + ")"; } public int hashCode() { return (this.email != null ? this.email.hashCode() : 0) * 31 + this.age; } @NotNull public final User copy(@NotNull String email, int age) { Intrinsics.checkParameterIsNotNull(email, "email"); return new User(email, age); } public boolean equals(Object otherObject) { if(this != otherObject) { if(otherObject instanceof User) { User otherUser = (User)otherObject; if(this.email.equals(otherUser.email) && this.age == otherUser.age) { return true; } } return false; } else { return true; } } }
این حدود ۵۰ خط کد برای نوشتن getterها ، setterها و تابع برابری برای مدل یوزر است. حالا اجازه دهید این کار را با کاتلین انجام دهیم:
data class User(val email: String, val age: Int)
در کل کاتلین با سادگی و فقط یک خط کد برنده میشود. این یک اشتباه نیست، این یک خط کد دقیقا همان کارایی کد جاوا را دارد. در واقع از لحاظ تکنیکی جمله قبلی صد در صد درست نیست، زیرا کد کاتلین علاوه بر کاری که جاوا انجام میدهد از برنامهنویس در زمان کامپایل از اینکه به طور تصادفی مقدار ایمیل را null ارسال کند محافظت میکند.
قابلیت نال شدن (nullability)
اجازه دهید به قابلیت نال شدن بپردازیم. در این مورد کاتلین null را به صورت داخلی در سیستم نوع دادهاش دارد. این دقیقا به چه معناست؟ در کاتلین وقتی که شما یک آبجکت تعریف میکنید شما باید تعیین کنید که آیا به آن اجازه نال شدن میدهید یاخیر؟ زیرا در کاتلین آبجکتها به صورت پیشفرض قابلیت نال شدن ندارند.
به عنوان مثال اجازه دهید در جاوا یک کلاس رویدادنگار ساده بنویسم که به ایمیل کاربر برای ثبت یک رویداد نیاز دارد:
public class LoggingClass { private final User myUser; public LoggingClass(User myUser) { this.myUser = myUser; } public void logEvent(String eventName) { String userEmail = myUser.getEmail(); AnalyticsClient.logEvent(eventName, userEmail); } }
مشکلی که با این کد جاوا وجود دارد این است که اگر myUser نال باشد صدا زدن متد logEvent ممکن است باعث یک NullPointerException شود که این باعث کرش کردن برنامه میشود. بنابرین سعی میکنیم این مشکل را حل کنیم:
public class LoggingClass { private final User myUser; public LoggingClass(User myUser) { this.myUser = myUser; } public void logEvent(String eventName) { if (myUser != null) { String userEmail = myUser.getEmail(); AnalyticsClient.logEvent(eventName, userEmail); } } }
اجازه دهید همین کلاس را با کاتلین بنویسیم:
class LoggingClass(private val myUser: User) { fun logEvent(eventName: String) { val userEmail = myUser.email AnalyticsClient.logEvent(eventName, userEmail) } }
در این مثال اگر مدل یوزری که به آن پاس داده میشود احتمال نال شدن داشته باشد برنامه اصلا کامپایل نمیشود. یک امکان خوب که به کاتلین اضافه شده است این است که کامپایلر در همچین جایی یک خطا تولید میکند و از اینکه شما یک NullPointerException تولید کنید جلوگیری میکند:
همچنان که در شکل بالا مشخص است کامپایلر به شما اجازه نمیدهد یوزری که امکان نال شدن دارد را به logger پاس دهید. این بدان معناست که نیاز نیست شما نگران احتمال نال شدن آبجکت یوزر باشید و با حفاظتی که در مقابل مقادیر نال قرار دارد شما میتوانید بدون اینکه نگران حالت مدل یوزر باشید کلاس logger خودتان را بنویسید.
پس کاتلین اینجا چه کاری انجام میدهد تا مقداری که نمیتواند نال باشد را تحمیل کند؟ اجازه بدهید کد کاتلین را دکامپایل کنیم تا به جواب برسیم:
public LoggingClass(@NotNull User myUser) { Intrinsics.checkParameterIsNotNull(myUser, “myUser”); super(); this.myUser = myUser; }
علاوه بر چک کردن در زمان کامپایل، کاتلین همچنین یک چک زمان رانتایم هم به کد اضافه میکند.
در زبان جاوا هم شما به راحتی میتوانستید یک کلاس کمکی برای انجام این کار در زمان رانتایم اضافه کنید، و با کمی دستکاری یک linter هم برای کمک در زمان کامپایل بنویسید.
یا میتوانید از کاتلین استفاده کنید که این کارها را به راحتی و رایگان برای شما انجام میدهد.
نتیجهگیری
کاتلین به برنامهنویسان کمک میکند که کد کمتری بنویسند که این باعث ایجاد باگ کمتر، ذخیره زمان بیشتر و استرس کمتر میشود. با کاتلین برنامهنویسها میتوانند زمان کمتری را صرف نوشتن کدهای تکراری و پر حجم کنند یا زمان کمتری به حل کردن NullPointerExceptionها اختصاص دهند و زمان بیشتری را صرف نوآوری در تولید و ایجاد تجربیات بهتر برای کاربران کنند.
منبع: medium.com
پ.ن: اگر در خواندن سورس کدها مشکل دارید میتوانید این مطلب را در این لینک در وبسایت شخصی من هم بخوانید.