/Java Programming: Let's Master 5

Java Programming: Let's Master 5

Introduction To Java Programming

Chapter 5

الشابتر اللي فات اتكلمنا عن الجمل التكرارية loops في الجافا والنهاردة معادنا في الكلام عن الـ Methods.

احنا قبل كده قابلتنا ميثودس زي( System.out.println و JOptionPane.showMessageDiolg )

ودلوقتي جه وقت اننا نعرف معني الميثود.
* الميثود : هي مجموعة من الجمل اللي مع بعض بينفذوا وظيفة ما.

* الميثود دي بمعني تاني عبارة عن كلمة الجافا عارفاها بتنفذ وظيفة معينة.

* في ميثودس جاهزة في مكتبة الجافا زي( System.out.println ) وممكن احنا نعمل ميثودس بنفسنا.

مثلا ميثود زي( System.out.println ) في الحقيقة هي علشان تطبع جملة علي الشاشة بتنفذ مجموعة من الجمل وفي الشابتر ده هنتعلم نعمل الميثودس الخاصة بينا ونستخدمها في برامجنا.

5.2. Creating a Method

الشكل العام لأي ميثود في الجافا هو ده :

 

وجايبلنا مثال عملي هنشرح عليه مكونات اي ميثود والمثال عبارة عن ميثود بتحسب الرقم الأكبر بين رقمين وبترجعه :

في البداية الheader  بيعرف فيه ال modifiers , return value type , method name & parameters :  modifier  بيكون استخدامه اختياري وهو بيعرف الcompiler  ازاي ينادي الميثود واحنا هنستخدم ال static modifier  طول الشابتر ده .
:return value type : وده بيبقي نوع القيمة اللي هترجع من الميثود وفي بعض الأحيان مش بنحتاج ان الميثود ترجع حاجة في الحالة دي هيبقي ال return value type بيكون void زي ميثود الmain .
Parameters: ودول بيبقوا المتغيرات اللي بعرفهم في ال header بتاع الميثود ولما باجي انادي الميثود ببعت قيمتهم. اسم الميثود مع الparameters بيكون ما يعرف بـ Method Signature وموضوع الparameters بيبقي اختياري يعني ممكن احطهم او لأ علي حسب الغرض من الميثود.
في المثال اللي فوق ده هنلاقي عندنا في جسم الميثود الجمل اللي المفروض الميثود هتنفذها وهي عبارة عن جملة مقارنة بين الرقمين انهي واحد فيهم اكبر من التاني وفي الأخر جملة ال return وفيها القيمة المطلوب انها ترجع من الميثود واللي لما الميثود بتتنفذ بتنتهي بجملة ال return دي.
ملحوظة :: في بعض لغات البرمجة الأخري تسمي الميثودس بال functions & procedures والميثود اللي بترجع قيمة اسمها function واللي مش بترجع قيمة (void) اسمها procedure . لكن في الجافا الاتنين اسمهم ميثودس.
ملحوظة :: لما بنيجي نعرف ال parameters لأي ميثود مش بندمج النوع لأكتر من parameter يعني مثلا مينفعش اقول int num1,num2 ولكن لازم تكون int num1,int num2.

5.3. Calling a Method

في السكشن اللي فات اتعلمنا ازاي نعمل ميثود طيب ازاي اناديها او انفذها؟
لو الميثود بتاعتنا بترجع قيمة لما بنيجي نناديها بنرجع القيمة اللي جاية منها في متغير من نفس نوع return value type زي كده :

 

الأمر ده بينادي الميثود max وبيرجع الناتج في المتغير larger وممكن طريقة تانية برده :

 

ودي بتطبع الناتج من الميثود.
في حالة ان الميثود بتكون من نوع void يعني مش بترجع حاجة مش هستخدم متغير علشان ارجع الناتج فيه ولكن هناديها علطول زي كده :

 

ملحوظة :: لو مش مهتمين قوي بالناتج اللي راجع من الميثود اللي مش من نوع void ممكن نناديها زي اللي من نوع  void بس الناتج سيتم إهماله .

لما البرنامج بيجيي يتنفذ وبيجي علي جملة نداء الميثود بيروح لجسم الميثود ويبدأ في تنفيذ الجمل اللي فيها وبتنتهي الميثود إما بجملة ال return او لما توصل لقوس النهاية بتاعها.
مثال كامل فيه الميثود اللي عملناها فوق :

 

في البداية عملنا ميثود ال main بتاعتنا وهي زيها زي اي ميثود ولكن بتتنفذ عن طريق ال java virtual machine .
لو حللنا ميثود ال main هنلاقيها عادية زي اي ميثود ال modifiers بيكونوا public , static وال return value type بيكون void واسمها بيكون main وال parameters هو واحد من نوع String[] والنوع ده بيسمي array وهيتشرح الشابتر الجاي بإذن الله.
وللعلم ان اي ميثود بيتم ندائها او استدعائها داخل ميثود الmain.
لما بيوصل للسطر السادس ويلاقي جملة استدعاء الميثود اللي اسمها max بيوقف ويروح علي مكان مانا عارفتها في الكود ويبدأ ينفذ اللي في الجسم بتاعها فبيقوم حاطط القيمة اللي في المتغير i في المتغير num1 والقيمة اللي في المتغير j في المتغير num2 وبينفذ الجمل اللي في جسم الميثود max ولما بيوصل لجملة الreturn بيوصل لنهاية الميثود ويرجع الناتج في المتغير k زي الشكل ده :

ملحوظة :: جملة الreturn  لابد من وجودها في الميثود اللي مش من نوع void زي المثال ده هنلاقي ان الكود سليم ولكن هيطلع error بسبب ان في الحالة الأولي ممكن الميثود مترجعش اي حاجة ولحل المشكلة دي ممكن نحذف الشرط الأخير لأنه بالعقل طالما ال n مش اكبر من الصفر ولا بتساويه تبقي اكيد اصغر وبكده تبقي الميثود اكيد هترجع قيمة.

ملحوظة :: من اهم اسباب عمل الميثودس هي اعادة الأستخدام (reuse) يعني بمعني اني عملتها في الكلاس اللي اسمه TestMax وممكن اناديها في اي كلاس تاني بطريقة اني بكتب اسم الكلاس . اسم الميثود زي كده TestMax.max()

5.3.1. Call Stacks

في كل مرة بتتنفذ اي ميثود كل المتغيرات وال parameters بتتخزن في مكان في الميموري بيسمي stack وبيخزن العناصر او المتغيرات بسياسة last in – first out ولما ميثود بتنادي ميثود تانية الstack  بيجهز ليها مساحة هي كمان.

last in – first out دي سياسة في علم الQueuing Theory أو نظرية الطوابير ان صحت الترجمة، ودي سياسة معالجة معناها ان (القيمة الأخيرة تدخل – فالقيمة الأولى تخرج).

5.4. void Method Example

في السكشن ده هنعرف ازاي نعمل ميثود من نوع void وازاي نناديها اولا هنشوف مثال هنعمل فيه ميثود printGrade  بتحسب التقدير علي حسب المجموع :

ولإن الميثود printGrade من نوع void لما جينا نناديها استخدمنا جملة عادية statement وبتنتهي طبعا ب (;).
ملحوظة :: جملة ال return مش بتتحط في الميثودس اللي من نوع void ولكن ممكن احطها لو انا بس عاوز اخلص الميثود واطلع منها يعني ممكن استخدامها كنهاية للميثود..

5.5. Passing Parameters by Values

من اكتر نقاط القوة في اي ميثود هي قدرتها علي التعامل مع ال parameters وبنلاحظ ان لما بنيجي ننادي الميثود لازم نراعي اننا بنبعت المتغيرات بنفس الترتيب اللي بنيت بيه الميثود وحددت فيها الparameters  وده بيسمي parameter order association  علي سبيل المثال ميثود بتطبع رسالة معينة عدد معين من المرات :

 

لما نيجي نناديها بنقول nPrintln(“hello”,3) علشان نطبع كلمة hello تلات مرات واللي بيحصل انه بيبعت hello للمتغير message والرقم 3 للمتغير n ومينفعش ابدل بينهم لأنه هيبقي error
ملحوظة :: لازم نراعي توافق الأنواع عند ارسال المتغيرات لأي ميثود ونلاحظ ان مينفعش هنا نعمل casting يعني نغير النوع لازم من وجود توافق بين اللي ببعته للميثود وبين اللي انا معرفه في الميثود.
لما باجي ابعت قيم ده مايسمي pass by value ولكن لو حبيت ابعت متغيرات للميثود في الواقع انا ببعت قيمهم وبس للميثود لكن القيمة نفسها مش بتتغير زي المثال ده واللي بنعمل فيه ميثود بتبدل بين قيم المتغيرين اللي فيها ولكن قيم المتغيرات الأصلية لم تتغير او تتأثر بالتبديل :

 

قبل ماننفذ الميثود swap كانت قيمة num1 is 1 & num2 is 2 وبعد ماخلصنا الميثود وطلعنا قيمهم برده فضلت زي ماهي ولم تتأثر ولكن قيمهم اتبعتت ل n1 , n2 ودول اللي الميثود اتعاملت معاهم.
بما معناه قيم المتغيرات اللي ببعتها للميثود لا تتأثر بالعمليات داخل الميثود نفسها .

5.6. Overloading Methods

ميثود ال max اللي عملناها قبل كده بتطلعلي الأكبر من رقمين من نوع int . طيب افرض انه انا عاوز اختبر الأكبر بين رقمين من نوع double ؟ في الحالة دي هعمل ميثود تانية بتاخد في ال parameters متغيرين من نوع double زي كده :

لو حبيت انفذ الميثود اللي اسمها max وبتاخد متغيرين من نوع int هبعتلها متغيرين او قيمتين من نوع int ولو حبيت انفذ الميثود اللي بتاخد متغيرين من نوع double هبعتلها متغيرين او قيمتين من نوع double وده اللي بيسمي Method Overloading بما معناه انه فيه اتنين ميثودس بنفس الأسم ولكن بياخدوا parameters من انواع مختلفة في نفس الكلاس وال compiler بيعرف انت قاصد انهي نوع من الطريقة اللي بتنادي بيها الميثود .
في المثال ده هنعمل تلات ميثودس الاولي بتحسب الأكبر بين رقمين int والتانية بتحسب الأكبر بين رقمين double والتالتة بتحسب الأكبر بين تلات ارقام double :

 

ممكن واحد يسأل طيب انا ممكن انفذ الميثود بالمنظر ده  max(2, 2.5) ؟ ولو فعلا اتنفذت انهي ميثود هي اللي هتتنفذ ؟
الإجابة علي السؤال الأول هي نعم فعلا هتتنفذ والإجابة علي السؤال التاني هو الميثود اللي هتتنفذ هتبقي الميثود اللي بتاخد متغيرات من نوع double وده لأن الcompiler بيعتبر ان ال 2 قيمة double .
طيب حد هيقول طب ليه لما بنفذ max(2,3) مش بينفذ برده الميثود اللي بتاخد المتغيرات double؟
هقول ان الcompiler لما بيجي ينفذ بيختار اقرب ميثود مطابقة للمدخلات اللي انا كاتبها وفي حالة الmax(2,3) هتكون اقرب ميثود هي اللي بتاخد المتغيرات int .
ملحوظة :: عمل ال method overloading بيسهل الكود جدا لأنه بيخلي الميثود اللي بتقوم بوظائف متشابهة كلهم بنفس الأسم وده منطقي.
ملحوظة :: لعمل method overloading لابد من تغيير نوع ال parameters فقط وليس الأسم او ال modifiers او return value type .
ملحوظة :: في بعض الأحيان بيكون فيه غموض حتي علي ال compiler انه يعرف انهي ميثود هيتم تنفيذها وفي الحالة دي بيطلع compilation error :

 

5.8. The Scope of Variables

الscope  بتاع المتغير هو الجزء اللي في الكود واللي فيه بتعامل مع المتغير يعني بعمل عليه عملية او بغير قيمته . المتغير اللي بعرفه بداخل اي ميثود بيبقي اسمه local variable والتعامل معاه بيبقي من اول السطر اللي بيتعرف فيه لحد نهاية جسم الميثود اللي اتعرف فيها ولازم اعرفه قبل مااتعامل معاه .وجدير بالذكر ان ال parameters بتوع اي ميثود يعتبروا local variables .
مثال المتغير اللي متعرف وواخد قيمة ابتدائية في تعريف اول لووب له وضع معين والمتغير اللي متعرف بداخل اللووب له وضع تاني في التعامل بيبدأ من سطر تعريفه لحد نهاية اللوب اللي هو متعرف فيها :

ممكن اني اكرر اسم الlocal variable  في اكتر من لووب او ميثود مثلا ولكن مينفعش اكرر اسم local variable بداخل نفس اللوب او الميثود :

ملحوظة :: مينفعش اعرف متغير بداخل ميثود او لووب واتعامل معاه بره اللوب او الميثود لأن ده هيديني error زي كده :

 

وده هيطلع error لأن المتغير i مش متعرف بره اللوب .

5.9. The Math Class

كلاس ال Math بيحتوي علي الميثودس المطلوبة لعمل العمليات الرياضية الأساسية. احنا استخدمنا منها مثلا Math.random() لحساب اعداد عشوائية و Math.pow() لحساب الأس بين رقمين فيه غيرهم ميثودس كتير . لو قسمناهم علي حسب عملهم هيبقوا:

5.9.1. Trigonometric Methods

او الدوال المثلثية ودي بتتعامل مع العمليات علي الزوايا زي كده:

كل ميثود بتاخد parameter واحد فقط وبترجع قيمة من نوع double والparameter بيمثل زاوية بالتقدير الدائري وللتحويل من التقدير الدائري للستيني بنضرب القيمة في PI/180 وفيه ميثود جاهزة بتحول من الدائري للستيني واسمها toRadians(double angdeg) والعكس toDegrees(double angrad) وبعض الأمثلة عليهم:

 

5.9.2. Exponent Methods

او الدوال الأسية ودي خاصة بعمليات الأس واللوغاريتمات بين عددين :

 

ملحوظة :: في ميثود sqrt نراعي ان X لازم تكون عدد موجب.
امثلة عليهم :

 

5.9.3. The Rounding Methods

او الدوال التقريبية وهما :

بيتم تقريب الرقم لأقرب رقم عشري ليه

public static double ceil(double x)

 بيتم تقريب الرقم لأقرب رقم عشري ولكن الأقل وليس الأعلي

public static double floor(double x)

 بيتم تقريب الرقم لأقرب رقم عشري ليه ولو كان قريب من رقمين بيكون الناتج الرقم الزوجي .

public static double rint(double x)
public static int round(float x) /** Return (int)Math.floor(x + 0.5). */
public static long round(double x)  /** Return (long)Math.floor(x + 0.5). */

ودول امثلة عليهم :

 

 

5.9.4. The min, max, and abs Methods

كمان فيه تلاتة ميثودس موجودين في كلاس Math واحدة بترجع الأكبر بين
رقمين وواحدة بترجع الأصغر وواحدة بترجع الabsolute value او القسمة المطلقة لرقم معين وامثلة عليهم :

 

5.9.5. The random Method

وميثود الrandom بترجع قيمة عشوائية بتكون اكبر من الصفر واقل من الواحد الصحيح وممكن استخدمها في توليد عدد معين من الأرقام العشوائية في مدي معين زي كده :

والصيغة العامة ليها :

ملحوظة :: مش لازم كل الكلاسات تبقي فيها main method كلاسات زي Math , JOptionPane مفيهومش ميثود main وده لأنهم معمولين علشان كلاسات تانية تستخدم الميثودس اللي فيهم .

5.11. Method Abstraction and Stepwise Refinement

اي ميثود بنستخدمها في اي برنامج احنا بنعمله مش محتاجين نعرف الجسم بتاعها فيه ايه ولكن بس بنستخدمها علطول وده مايسمي بال abstraction يعني بفصل بين الجسم بتاع الميثود وطريقة استخدامها وبتبقي طريقة بنائها مخفية عن المستخدم العادي وده مايسمي بال encapsulation

 

طبعا اول سؤال اكيد اي حد هيسأله لنفسه هعمل البرنامج ده ازاي؟؟؟
ممكن نبدأ بالكود علطول من اول خطوة لحد اصغر خطوة . بس اعتقد ده حل صعب قوي واحتمال الخطا فيه كبير جدا .
حل تاني اني اقسم الكود إلي خطوات واهتم بكل خطوة علي حدي لحد مااخلص المشكلة كلها وده اللي هنعمله هنا :
الحل مقسوم لجزئين : الأول ازاي اخد الدخل من المستخدم والتاني ازاي اطبع التقويم وطبعا الخطوة دي اكيد هتتقسم برده لخطوات اصغر ولو فكرنا نعمل رسم تحليلي للخطوات هيبقي كده :

طيب جميل جدا اول خطوة اللي هي ازاي اقري الدخل من المستخدم سهلة هنعملها بالطريقة المعروفة بإستخدام()JOptionPane.showInputDialog .

المشكلة التانية اللي هي طباعة التقويم نقسمها لخطوتين تانيين الأولي طباعة عنوان الشهر والتانية طباعة التقويم نفسه .
في صورة الناتج لو لاحظنا شكل الخرج هنلاقي انه عبارة عن اسم الشهر والسنة وبعدين خط فاصل ويعدين أيام الأسبوع في الشهر المطلوب يعني لازم نيجيب الأول اسم الشهر وده بنيجبه من الميثود()getMonthName .
علشان اقدر اطبع التقويم للشهر لازم اعرف اول يوم في الشهر ()getStartDay والشهر فيه كام يوم()getNumberOfDaysInMonth  مثلا شهر ديسمبر سنة 2005 فيه 31 يوم اول يوم فيه كان يوم الخميس .

طيب ازاي اعرف اول يوم في الشهر كان ايه؟
فيه اكتر من طريقة اسهلهم اني استخدم كلاسات Calendar & Gregorian Calendar . طريقة تانية افرض اننا نعرف ان اول يوم في شهر يناير سنة 1800 كان يوم الأربعاء (startDay1800() = 3) وممكن احسب عدد الأيام من اول يوم في شهر يناير سنة 1800 لحد الشهر المطلوب (totalNumberOf Days) واول يوم في الشهر المطلوب هيبقي (totalNumberOfDays + startDay1800) % 7 وقسمنا علي 7 لأن الأسبوع فيه سبع ايام. وبكده ()getStartDay هيطلع منها ()getTotalNumberOfDays .
لما بنيجي نحسب عدد الأيام المفروض اعرف السنة كبيسة ولا لأ ()isLeapYear ولازم اعرف كل شهر فيه كام يوم ()getNumberOfDaysInMonth

وبكده ابقي حليت المشكلة وده هيبقي الشكل الكامل للحل :

ملحوظة مهمة جدا:: انا شرحت البرنامج دا بالذات عشان بجد فيه فكرة راقية جدا في الجافا وتطبيق أكثر من رائع على تكنيك الencapsulation  واللي هيفهم البرنامج دا يبقى حط رجله على الطريق بشكل كبير وهيرتاح جدا في الأوبجكت أورينتد OOP  بعد كده، واللي مش هيفهم البرنامج دا، انا معاه في أي استفسارات لحد ما نفهمه سوا.. وأتنمى بجد أقدر افيده..الكود جاي في السكشن الجاي 5.11.2

5.11.2. Top-Down or Bottom-Up Implementation

دلوقتي احنا فكرنا ازاي نفكر في الكود نيجي بقي للكود نفسه وانا بكتب الكود بعتبر ان اي مشكلة فرعية تلقائيا بتتحول لميثود في الكود ممكن طبعا تكون اسهل من انها تتعمل في ميثود لوحدها إذن يبقي علي حسب الكود هنتعامل وطبعا المعيار الوحيد في الأختيار ان الكود يكون اسهل في فهمه .
ممكن نطبق في الكود طريقة من اتنين إما Top-Down وفي الطريقة دي بنكتب الكود من اول ميثود لأخر ميثود ولكن من فوق لتحت علي اساس الرسمة التوضيحية للبرنامج اللي فوق والطريقة التانية Bottom-Up ودي العكس بتبدأ من تحت لفوق .
شكل البرنامج في النهاية هيبقي كده :

بس البرنامج مش بيحدد الدخل اللي المستخدم دخله صح ولا غلط يعني مثلا لو دخل رقم الشهر 15 مش هيطلع error . وممكن طبعا اعدل في البرنامج انه يطبع السنة كلها .

5.12. (Optional) Packages

الكلاسات المتاشبهة او المرتبطة مع بعضها بتتحط في مايسمي ال package او الحزمة وفيه اربع اسباب لأستخدام الpackages :
1- علشان اعرف احدد مكان كلاس معين علي اساس اني مجمع كل الكلاسات المتشابهة في package واحدة .
2- علشان ميحصلش لغبطة في اسامي الكلاسات يعني ممكن يبقي فيه كلاسين بنفس الأسم فعلشان ميحصلش لغبطة بحط كل واحد في package .
3- لما بجمع الكلاسات المتشابهة في package واحدة بيبقي اسهل اني اوزعهم او اتعامل معاهم.
4- كمان الpackage بتوفر حماية للكلاسات اللي فيها من حيث مين يقدر يقراهم او يقراهم ويعدل فيهم وهكذا .

5.12.1. Package-Naming Conventions

اسم الpackage  بيبقي اسم فريد علشان مايتكررش وتحصل مشاكل وممكن اعمل package بداخل package وبنادي الكلاس اللي فيها زي كلاس Math بناديه كده java.lang.Math يعني كلاس Math موجود في الpackage اللي اسمها lang واللي موجودة في الpackage اللي اسمها java .

5.12.3. Putting Classes into Packages

ازاي احط اي كلاس في الpackage ؟
بنعرف في اول سطر في البرنامج اسم الpackage اللي الكلاس ده انا عاوز احطه فيها :

5.12.4. Using Classes from Packages

طيب ازاي استخدم اي كلاس موجود في package ؟
بنعمل جملة import في بداية الكود للpackage المطلوبة واللي بتحتوي علي الكلاس اللي انا عاوزه زي كده :

 

ممكن لو انا هستخدم اكتر من كلاس في الpackage اني استدعي كل الكلاسات اللي فيها بإستخدام الطريقة دي :

 

Thanks a lot CATReloaded

Thanks CATazine

Om4rezz