یوشا آل ایوب

دست نوشته ها و تجربیات شخصی

یوشا آل ایوب

دست نوشته ها و تجربیات شخصی

دکتر مصطفی چمران: می گویند تقوا از تخصص لازمتر است، آنرا می پذیرم، اما می گویم: آنکس که تخصص ندارد و کاری را می پذیرد، بی تقواست!

تبلیغات
Blog.ir بلاگ، رسانه متخصصین و اهل قلم، استفاده آسان از امکانات وبلاگ نویسی حرفه‌ای، در محیطی نوین، امن و پایدار bayanbox.ir صندوق بیان - تجربه‌ای متفاوت در نشر و نگهداری فایل‌ها، ۳ گیگا بایت فضای پیشرفته رایگان Bayan.ir - بیان، پیشرو در فناوری‌های فضای مجازی ایران

در ادامه مقاله قبلیم که شماره شش "نکات و اصول مهم در برنامه نویسی Java/Android" بود، در این مقاله شماره هفت همین موضوع رو ارائه میدم...

 

1- تفاوت HashMap و HashTable:
کلاس HashMap از نوع synchronize نیست پس thread-safe نیست. اما کلاس HashTable از نوع synchronize هستش.
کلاس HashMap بخاطر synchronize نبودن کمی سریعتر از HashTable عمل میکنه.
کلاس HashMap اجازه داشتن یک کلید null و چندین مقدار null رو داره، اما کلاس HashTable همچین اجازه ای رو نداره.
کلاس HashMap زیرکلاس AbstractMap هستش، اما کلاس HashTable زیرکلاس Dictionary هستش.
کلاس HashTable تقریباً منسوخ شده و باید از جایگزینش ConcurrentHashMap استفاده بشه.
و...

در بیشتر موارد کلاس HashMap استفاده میشه، درصورتی که synchronization در اولویت نباشه.

2- برای حل مشکل ValueError: unsupported pickle protocol در لینوکس کافیه فایل .repopickle_.gitconfig در Android SDK رو پیدا و حذف کنید.

 

3- اصول طراحی کلاس:

- همیشه داده ها و فیلدها رو private نگهدارید و از اصول encapsulation پیروی کنید.

- همیشه فیلدها رو initialize کنید.

- هرکلاس رو به یک نوع/دسته از داده اختصاص بدید.

- کلاسهای چند منظوره با چند مسئولیت طراحی نکنید، بلکه آنها را تجزیه و جداسازی کنید.

- بی دلیل برای همه فیلدها و داده ها accessor و mutator طراحی نکنید. (set/get)

- همیشه بهترین و مناسبترین نام رو برای کلاس و متد تعیین کنید تا هدف رو بخوبی انعکاس بدهند.

- حتاالمکان کلاسها رو immutable (غیرقابل تغییر) طراحی کنید.

- بجای استفاده مکرر تودرتو if/else switch foreach از interface یا کلاس abstract استفاده کنید.

- حتاالمکان کلاس رو static طراحی نکنید. (بخاطر global state و مشکلات unit testing)

- از نوشتن متدهای طولانی و سنگین خودداری کنید. معمولاً متدهای طویل نشاندهنده رفتار و وظایف متعدد هستش که نیاز به تجزیه و refactory شدن داره.

- از قانون DRY (مخفف Don’t Repeat Yourself) پیروی کنید... متدهای تکراری رو با ساخت superclass abstract یکی کنید.

 

4- نکته جزیی: package ها در جاوا superclass نیستن، بلکه نوعی namespace هستن.

 

5- برای حل مشکل Gradle sync failed: CreateProcess error=216, This version of %1 is not compatible with the version of Windows you're running راه های زیر رو دنبال کنید:

- مطمعن بشید که معماری JDK, Windows و Android Studio همگی یکی باشن. مثلاً همگی x64 یا x86 باشن

- وارد منوی File -> Project Structure در Android Studio بشید و Use embedded JDK غیرفعال کنید، بعد آدرس JDK نصب شده خودتون رو بهش بدید.

- فایل gradle.properties رو باز کنید و مقدار memory مصرفی رو کاهش بدید.

- مطمعن بشید که مسیر پوشه bin پکیج JDK در PATH سیستم موجود باشه.

 

6- برای رفع خطای Error:Could not determine java version from '9.0.1' یکی از راه های زیر رو دنبال کنید:

- اگر JDK 9 رو نصب دارید حذفش کنید و JDK 8 (یا همون 1.8) رو نصب کنید.

- اگر از Gradle استفاده می کنید، به نسخه 4.3 یا جدیدتر upgrade کنید. و مقدار موجود در فایل gradle.properties رو هم تغییر بدید.

- در اندروید استودیو به منوی File -> Other settings -> Default project structure برید و گزینه use embedded JDK رو فعال کنید.

 

7- همیشه اطلاعات حساس رو قبل از serialize کردن، ابتدا رمزنگاری کنید!

 

8- برای حل مشکل Error: Execution failed for task ':app:preDebugAndroidTestBuild'.> Conflict with dependency 'com.android.support:support-annotations' in project ':app'. Resolved versions for app (25.0.1) and test app (26.4.0) differ. در اندروید استودیو کافیه دستور زیر رو در فایل build.gradle ماژول مورد نظر قرار بدید:

configurations.all
{
   resolutionStrategy.force 'com.android.support:support-annotations:24.2.1'
}

 

9- اولویت override شدن resource های پروژه اندروید بصورت: build types > flavors > main هستش.

 

10- هرگز thread های worker رو در حالت high priority قرار ندید، اینها باید درحالت background (اولویت پایین) عملیات رو انجام بدن.

نکته: AsyncTask بصورت پیشفرض عملیات رو درحالت background انجام میده اما کلاس java.lang.Thread خیر.

 

11- از انجایی که نوع داده boolean برای SQLite در اندروید بدرستی پیاده سازی نشده، بهتره از نوع داده int استفاده کنید. (هم برای فیلد دیتابیس و هم در کدهای جاوا)

 

12- همیشه توسط برنامه apksigner خود Android SDK فایلهای apk رو امضا کنید و نه برنامه jarsigner.

 

13- نکته جزیی: آیا میدونید Interface ها و Enum ها در جاوا بصورت پیشفرض final static هستن؟

 

14- فراموش نکنید که در Java 7 و جدیدتر میتونید از String هم در دستور switch استفاده کنید!

 

15- با استفاده از کلمه کلیدی volatile در متغیرها می تونید thread های برنامه رو وادار کنید تا اطلاعات متغیر رو مستقیماً از حافظه بخونن و نه کش CPU. (این عمل درواقع نوعی thread-safety محسوب میشه)

 

16- شما میتونید متدهای static رو overload کنید، اما نمیتونید override کنید. چون عملیات overloading مربوط به run-time هستش، اما عملیات overrding مربوط به compile-time هستش، زمانی که متدهای static پردازش میشن.

 

17- درصورت بروز خطای manifest merger failed در Gradle یکی از راه های زیر رو دنبال کنید:

- کد tools:replace="android:icon" رو داخل تگ <application> در فایل manifest اضافه و بعد پروژه رو Clean کنید.

- یا کد xmlns:tools="http://schemas.android.com/tools" رو به خود تگ <manifest> اضافه کنید.

- یا جای dependency هارو داخل فایل build.gradle عوض کنید. مثلاً از پایین به بالا یا از بالا به پایین حرکتشون بدید. (re-ordeding)

- یا دستور useOldManifestMerger true رو در قسمت android فایل build.gradle اضافه کنید:

android
{
   useOldManifestMerger true
}

- اگر درست نشد مطمعن بشید که مقدار Minsdk کتابخانه ها از Minsdk پروژه کوچیکتر "نباشه".

 

 

18- توجه داشته باشید که رشته های Unicode escape قبل از parse شدن کدها پردازش میشن. بنابراین بخشی از ساختار دستوری بحساب میان. مثال:

public void myMethod(String\u005B\u005B names)
برابره با
public void myMethod(String[] names)

 

19- هنگام صدا زدن متد های static بهتره از کلاس اصلی استفاده بشه تا نمونه های کلاس یا اشیا فرزند:

public class Vehicle
{
   public static int getId()
   {
      return 123;
   }
}

// غلط
Vehicle bmw = new Vehicle;
int id = bmw.getId();

// صحیح
int id = Vehicle.getId();

 

20- مفهوم refactory به زبان ساده: تغییر کد، بدون تغییر رفتار کد. یا تغییر کد، بدون شکستن API کد.

 

21- هرگز بصورت دستی مسیرهای jre/lib و jre/lib/ext رو داخل متغیر CLASSPATH اضافه نکنید، این مسیرها توسط ماشین جاوا بصورت خودکار پیمایش خواهند شد.

 

22- همیشه هنگام نوشتن کد داخل کامنت های doc بجای <code> </code> از تگ {@code } استفاده کنید تا کاراکترهای escaping داخل کد با مشکل مواجه نشن.

 

23- عمل auto boxing و auto unboxing توسط کامپایلر(compile-time) انجام میشه و نه ماشین مجازی(run-time).

Integer myInt = new Integer(22);

if (myInt < 11) // Auto unboxing internally
{
   // ...
}

myArrayList.add(22); // == myArrayList.add(Integer.valueOf(22));

نکته: عمل Unboxing درواقع تبدیل نوع داده شی(wrapper) به نوع داده اولیه(primitive) هست و عمل Autoboxing تبدیل خودکار نوع داده اولیه(primitive) به نوع داده شی(هستش) مربوطه هست.

 

24- بهتره همیشه برنامه ها رو توسط پارامتر -Xlint:fallthrough کامپایل کنید تا متوجه break های فراموش شده احتمالی در دستور switch بشید.

نکته: درصورتی که نیاز به این قابلیت(عدم استفاده از break) دارید میتونید توسط دستور @SuppressWarnings("fallthrough") این هشدار رو برای متد مورد نظر خاموش کنید.

 

25- نکته جزیی: در جاوا چیزی بنام آرایه چند بعدی وجود ندارد! چیزی که هست آرایه ای از آرایه هستش. درواقع Fake ای از آرایه ها هست.

 

26- در encapsulation(یا detail hiding) کلاس، دسترسی تمامی فیلدها باید private باشند.

 

27- برای انجام Unit Test هر کلاس بصورت مستقل میتونید تابع main رو به کلاس مورد نظر اضافه کنید و کلاس رو بصورت مجزا کامپایل و Unit Test کنید:

class MyLib
{
   public MyLib(String message)
   {
      // ...
   }

   public static void main(String[] args) // Unit test.
   {
      MyLib ml = new MyLib("Hello World");
      // ...
   }

   //...
}

 

28- آیا میدونید در جاوای قبل از نسخه 6 میتونید بجای تابع main از بلوک static استفاده و برنامه رو کامپایل کنید؟

public class Test
{
   static
   {
      System.out.println("Hello World");
   }
}

نکته: از جاوا نسخه 7 و جدیدتر، کامپایلر ابتدا بدنبال متد public static main میگرده و بعد کامپایل میکنه.

 

29- درصورت بروز خطای Instant run equires that the platform corresponding to your target device راه های زیر رو دنبال کنید:

1- گوشی/امولاتور رو از سیستم قطع و مجدداً وصلش کنید.
2- برنامه رو از روی گوشی/امولاتور بصورت دستی uninstall و دوباره امتحان کنید.
3- هنگام run به دستگاه مراجعه کنید اگر پنجره confirmation یا security باز شده، تاییدش کنید.
4- اگر گوشی هستش، حالت اتصال رو MTP قرار بدید.
5- اگر در لینوکس هستید، استودیو رو از طریق sudo باز کنید. اگر هم داخل ویندوزید، از طریق run as administrator بازش کنید.
6- اگر امولاتور هستش، حذفش کنید و دوباره بسازیدش.

 

30- هرگز شی Throwable رو catch نکنید!

این شی superclass همه کلاسهای Exception ها و Error ها هستش پس با catch کردنش نه تنها Exception ها بلکه Error رو هم catch می کنید. درصورتیکه Error ها برخاسته از JVM و نشان دهنده مشکلات جدی در برنامه (مثل OutOfMemoryError و StackOverflowError) و غیرقابل هندل و کنترل هستن.

try
{

}
catch (Throwable throwable) // Bad!
{

}

 

31- حتاالمکان Exception رخداده رو مجدداً throw نکنید. با اینکار فقط پیام تکراری و اضافه برای همون Exception ایجاد می کنید.

مگر اینکه اطلاعات بیشتر و پیامی متفاوت تر به اون Exception اضافه کنید.

try
{
   // ...
}
catch (NumberFormatException exception)
{
   throw exception;
}

خروجی:

ERROR MyTestJava:7 - java.lang.NumberFormatException: For input string: "test"

Exception in thread "main" java.lang.NumberFormatException: For input string: "test"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:7)
    at java.lang.Long.parseLong(Long.java:589)
    at java.lang.Long.(Long.java:965)
    at com.stackify.example.MyTestJava.logAndThrowException(MyTestJava.java:63)
    at com.stackify.example.MyTestJava.main(MyTestJava.java:58)

 

32- برای چسباندن و الحاق رشته ها حتاالمکان از StringBuilder بجای + استفاده کنید. با اینکار فقط یک شی String ساخته میشه و همه رشته ها به این شی اضافه میشه.

 

33- درصورتیکه از جاوا نسخه 8 یا قدیمیتر استفاده می کنید و بسیار دستور replace رو در کدهاتون بکار بردید، بهتر بجاش از دستور StringUtils.replace موجود در کتابخانه Apache Commons استفاده کنید.

با اینکار پروفورمنس عملیات رو تا 1.5 برابر افزایش میدید.

 

34- Log4j2 یک کتابخانه استاندارد و مناسب جهت Log کردن فرایندها و گزارشات نرم افزار.

درصورتیکه پرفورمنس اولویت اول نرم افزار شما نیست میتونید از کتابخانه Logback هم استفاده کنید.

 

 

30- شباهت ها و تفاوت های کلاس Abstract با Interface

-  هر دو در پیاده سازی الگوی polymorphism استفاده می شن.

- هر دو برای پیروی از یک شِمای و اسکلت ثابت هستند.

- هردو گزینه خوبی برای استاندارد سازی API داخلی هستن.

- هردو بهترین گزینه برای کار تیمی/گروهی هستن.

- هر دو قوانین استفاده از کلاس رو برای توسعه دهنده اجبار می کنن.

- هر دو میتونن تعیین کنن که چه چیز باید پیاده سازی بشه بی توجه به اینکه چطور پیاده سازی بشه.

اما:
- متدهای کلاس Abstract میتونن حاوی کد/محتوا باشن تا یک عملیات رو برای همه کلاس های مصرف کننده فراهم کنن. ولی Interface ها نمی تونن.

- کلاس Abstract میتونه متد private و protected داشته باشه، اما Interface نمی تونه.

- کلاس Abstract در واقع ترکیبی از Interface و کلاس هستش ولی Interface یک کلاس مجازی.

- کلاس Abstract قابلیت instantiation یا همون new شدن رو نداره. فقط میشه inheritance/extend بشه. و درطرف دیگر Interface رو فقط میشه  implement کرد.

- یک کلاس فقط از یک کلاس Abstract می تونه extend بشه. ولی یک کلاس میتونه از 65535 عدد interface مختلف implement بگیره.

- یک Interface می تونه از چندین Interface مختلف extend بشه. اما  کلاس Abstract نمی تونه.

- اینترفیس معمولاً در طراحی Listener ها، Callback ها و سازگارسازی کلاس های غیرمرتبط استفاده داره، اما abstract در همه جا.

- کلاس Abstract میتونه فیلد، نوع final static و متد داشته باشه. اما Interface فقط می تونه متد(خالی) و فیلد final static داشته باشه.

- یک کلاس معمولی(concrete) باید همه متدهای interface رو implement کنه، اما در کلاس Abstract اجباری نیست.

- سطوح دسترسی متدها و فیلدها در Abstract میتونه public, private, protected باشه. اما در Interface فقط public میتونه باشه.

زمانی از abstract class استفاده کنید که بدنه متد هم لازمه از قبل کدنویسی بشه، و زمانی از interface استفاده کنید که لازم نیست بدنه متد از قبل کدنویسی بشه یا کلاس نیاز داره که چندین interface رو پیاده سازی کنه.

 

32- نکته جزیی: آیا میدونید توسط reflection و deserialization قادرید مقادیر final رو هم تغییر بدید؟

 

33- حتاالمکان فیلدها رو protected تعریف نکنید. زیرا subclass ها قادرن مستقیماً به انها مقدار بدن و کپسوله سازی رو از بین ببرن. همچنین تمامی کلاس های موجود در پکیج جاری به این فیلد ها دسترسی دارن.

 

34- برای بدست اوردن کلاس جاری در متدهای static میتونید از کد زیر استفاده کنید:

new Object(){}.getClass().getEnclosingClass();

 

35- همیشه inner class هارو static طراحی کنید، مگر اینکه نیاز به دسترسی به شی outer class داشته باشید.

نکته: در inner class نوع static میتونید متد و فیلد static هم داشته باشید.

نکته 2: inner class های واقع در interface همگی بصورت خودکار public static هستند.

 

36- هرگز متد run() در کلاس Thread یا Runnable رو بصورت مستقیم و دستی اجرا نکنید. در غیر اینصورت عملیات بصورت single-thread اجرا خواهد شد. (باید متد start() صدا زده بشه)

 

37- یادتون باشه که فلسفه استفاده از ابزارهای اتوماسیون build(مثل gradle, maven, phing, ant) تنها کاهش خطاهای انسانی و صرفه جویی در زمان می باشد.

 

38- از Java 6 به بعد(JDBC 4.0) دیگر نیازی به لود کردن درایور دیتابیس توسط دستور Class.forname یا registerDriver نیست، اینکار توسط JVM بصورت خودکار انجام میشه. (درصورت وجود فایل Driver)

 

39- همیشه اطلاعات ورودی/کاربر رو قبل از ثبت کردن در log، ابتدا فیلترسازی کنید!

 

40- کاربردها و اهداف بلوک های static:

- برای initialize کردن کدهای استاتیک(static) که هنگام Load شدن کلاس(توسط classloader) اعمال بشن

public static Map<String, String> myField = new HashMap<String, String>();

static
{
   myField.put("Test name", "Test value");
   // ...
}

- برای initialize کردن کلاسهای master

public class MasterClass
{
   static
   {
      SlaveClass.initialize();
      // ...
   }
}

- بارگذاری کتابخانه های Native

static
{
   System.loadLibrary("TestLibrary");
}

توجه: باید فیلدهای static در بلوک static قرار بگیرند و initialize بشن و نه در constructor! اینها بخشی از class definition هستن و نه object.

 

نظرات (۲)

۰۲ تیر ۹۸ ، ۱۹:۰۰ هادی بهربگی
عالی بود! تجدید خاطرات شد...
سال 86 تو اپتک اینارو (البته بعضیاش هنوز نبودن، جاوا با ناک کد ببر (Tiger) یعنی جاوا 1.5 آخرین ویرایشش بودف برا همین مثلا استفاده String ها تو switch ممکن نبود و من اینو هی به دانشجوام میگفتم فقط نوع های داده ای enumerable میتونن تو switch باشن که اوراکل دستش درد نکنه این مفهوم رو داغون کرد!) درس میگفتم! یادش بخیر
۲۰ بهمن ۹۷ ، ۱۸:۳۴ فرهاد حسن پور
بسیار طولانی اما مفید بودن.

کاربران بیان میتوانند بدون نیاز به تأیید، نظرات خود را ارسال کنند.
اگر قبلا در بیان ثبت نام کرده اید لطفا ابتدا وارد شوید، در غیر این صورت می توانید ثبت نام کنید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">