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)
- از نوشتن متدهای طولانی و سنگین خودداری کنید. معمولاً متدهای طویل نشاندهنده رفتار و وظایف متعدد هستش که نیاز به تجزیه و refactoring داره.
- از قانون 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) { // ... } @Test 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
یا concat()
بجای + استفاده کنید. با اینکار فقط یک شی String
ساخته میشه و همه رشته ها به این شی اضافه میشه.
33- توسط نرم افزار Appium میتونید UI اپلیکیشن رو تست کنید.
34- Log4j2 یک کتابخانه استاندارد و مناسب جهت Log کردن فرایندها و گزارشات نرم افزار.
درصورتیکه پرفورمنس اولویت اول نرم افزار شما نیست میتونید از کتابخانه Logback هم استفاده کنید.
35- شباهت ها و تفاوت های کلاس Abstract با Interface
- هر دو در پیاده سازی الگوی polymorphism استفاده می شن.
- هر دو برای پیروی از یک شِمای و اسکلت ثابت هستند.
- هردو گزینه خوبی برای استاندارد سازی API داخلی هستن.
- هردو بهترین گزینه برای کار تیمی/گروهی هستن.
- هر دو میتونن تعیین کنن که چه چیز باید پیاده سازی بشه بی توجه به اینکه چطور پیاده سازی بشه.
- هر دو برای انجام dependency injection می تونن استفاده بشن.
اما:
- متدهای کلاس 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 رو پیاده سازی کنه.
36- نکته جزیی: آیا میدونید توسط reflection و deserialization قادرید مقادیر final
رو هم تغییر بدید؟
37- حتاالمکان فیلدها رو protected
تعریف نکنید. زیرا subclass ها قادرن مستقیماً به انها مقدار بدن و کپسوله سازی رو از بین ببرن. همچنین تمامی کلاس های موجود در پکیج جاری به این فیلد ها دسترسی دارن.
38- برای بدست اوردن کلاس جاری در متدهای static
میتونید از کد زیر استفاده کنید:
new Object(){}.getClass().getEnclosingClass();
39- همیشه inner class هارو static
طراحی کنید، مگر اینکه نیاز به دسترسی به شی outer class داشته باشید.
نکته: در inner class نوع static
میتونید متد و فیلد static
هم داشته باشید.
نکته 2: inner class های واقع در interface
همگی بصورت خودکار public static
هستند.
40- هرگز متد run()
در کلاس Thread
یا Runnable
رو بصورت مستقیم و دستی اجرا نکنید. در غیر اینصورت عملیات بصورت single-thread اجرا خواهد شد. (باید متد start()
صدا زده بشه)
مقالات مرتبط
نکات و اصول مهم در برنامه نویسی Java/Android
#2 - نکات و اصول مهم در برنامه نویسی Java/Android
#3 - نکات و اصول مهم در برنامه نویسی Java/Android
#4 - نکات و اصول مهم در برنامه نویسی Java/Android