<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/page/4/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; &#x62C;&#x627;&#x641;&#x627;</description><language>ar</language><item><title>&#x645;&#x641;&#x647;&#x648;&#x645; &#x627;&#x644;&#x62A;&#x635;&#x631;&#x64A;&#x62D;&#x627;&#x62A; (declarations) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D8%AD%D8%A7%D8%AA-declarations-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1093/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_12/30.png.6c8caeff9595aad73058d9e66a78e340.png" /></p>

<p>
	كما ذَكَرَنا سابقًا، الأسماء هي أحد أركان البرمجة الأساسية. تَتَضمَّن مسألة التَّصْريح (declaring) عن الأسماء واِستخدَامها الكثير من التفاصيل التي تَجنَّبنا غالبيتها إلى الآن، ولكن حان وقت الكشف عن كثير من تلك التفاصيل. حاول التركيز عمومًا على محتوى القسمين الفرعيين "التهيئة أثناء التصريح" و "الثوابت المسماة (named constants)"؛ لأننا سنُعيد الإشارة إليهما باستمرار.
</p>

<h2>
	التهيئة (initialization) أثناء التصريح (declaration)
</h2>

<p>
	عندما نُصرِّح عن مُتَغيِّر ما (variable declaration)، يُخصِّص الحاسوب مساحة من الذاكرة لذلك المُتَغيِّر، والتي ينبغي تَهيئتها (initialize) مبدئيًا، بحيث يَتَضمَّن ذلك المُتَغيِّر قيمة معينة قَبْل أي مُحاولة لاِستخدَامه ضِمْن تعبير (expression). عادةً ما ترى تَعْليمَة التَّصْريح (declaration) عن مُتَغيِّر محليّ معين (local variable) مَتبوعة بتَعْليمَة إِسْناد (assignment statement) لغرض تهيئة ذلك المُتَغيِّر مبدئيًا (initialization). على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_7" style="">
<span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">    </span><span class="com">// ‫صرح عن المتغير count </span><span class="pln">
count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">    </span><span class="com">// ‫أسند القيمة 0 إلى المتغير count</span></pre>

<p>
	في الواقع، تستطيع تَضْمِين التهيئة المبدئية (initialization) للمُتَغيِّر بنفس تَعْليمَة التصريح (declaration statement)، أيّ يُمكِن اختصار التَعْليمَتين بالأعلى إلى التَعْليمَة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_9" style="">
<span class="typ">int</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫صرح عن المتغير count وأسند إليه القيمة 0</span></pre>

<p>
	سيُنفِّذ الحاسوب ذلك على خطوتين: سيُصرِّح أولًا عن مُتَغيِّر اسمه <code>count</code>، ثم سيُسنِد القيمة صفر إلى ذلك المُتَغيِّر المُنشَئ للتو. ليس ضروريًا أن تَكُون قيمة المُتَغيِّر المبدئية ثابتة (constant)، وإِنما قد تَتَكوَّن من أي تعبير (expression). يُمكِنك أيضًا تهيئة عدة مُتَغيِّرات بتَعْليمَة تَّصْريح واحدة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_11" style="">
<span class="kwd">char</span><span class="pln"> firstInitial </span><span class="pun">=</span><span class="pln"> </span><span class="str">'D'</span><span class="pun">,</span><span class="pln"> secondInitial </span><span class="pun">=</span><span class="pln"> </span><span class="str">'E'</span><span class="pun">;</span><span class="pln">

</span><span class="typ">int</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">   </span><span class="com">// ‫صالح ولكن أسندت القيمة 1 إلى المتغير y فقط</span><span class="pln">

</span><span class="typ">int</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> M </span><span class="pun">=</span><span class="pln"> N</span><span class="pun">+</span><span class="lit">2</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫صالح، هُيأت القيمة N قبل استخدامها</span></pre>

<p>
	لمّا كان المُتَغيِّر المُتحكِّم بحَلْقة معينة (loop control variable) غير مَعنِي بأي شيء يَقَع خارج تلك الحَلْقة عمومًا، كان من المنطقي التَّصْريح عنه ضِمْن ذلك الجزء من البرنامج الذي يَستخدِمُه فعليًا. ولهذا يَشيَع اِستخدَام التَعْليمَة المُختصرة بالأعلى ضِمْن حَلْقات التَكْرار <code>for</code>؛ حيث تُمكِّنك من التَّصْريح عن المُتَغيِّر المُتحكِّم بالحَلْقة، وتَهيئته مبدئيًا بمكان واحد ضِمْن الحَلْقة ذاتها. على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_13" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">  i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الشيفرة بالأعلى هي بالأساس اختصار لما يَلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_15" style="">
<span class="pun">{</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">  i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أَضفنا زوجًا إضافيًا من الأقواس حول الحَلْقة -بالأعلى- للتأكيد على أن المُتَغيِّر <code>i</code> قد أصبح مُتَغيِّرًا محليًا (local) لتَعْليمَة الحَلْقة <code>for</code>، أيّ أنه لَمْ يَعُدْ موجودًا بعد انتهاء الحَلْقة.
</p>

<p>
	يُمكِنك أيضًا إجراء التهيئة المبدئية (initialize) للمُتَغيِّرات الأعضاء (member variable) أثناء تَّصْريحك عنها (declare)، كما هو الحال مع المُتَغيِّرات المحليّة (local variable). فمثلًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_17" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Bank</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> interestRate </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.05</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> maxWithdrawal </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">.</span><span class="pln">
     </span><span class="pun">.</span><span class="pln">  </span><span class="com">// المزيد من المتغيرات والبرامج الفرعية</span><span class="pln">
     </span><span class="pun">.</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عندما يُحمِّل مُفسِّر الجافا (Java interpreter) صنفًا معينًا، فإنه يُنشِئ أي مُتَغيِّر عضو ساكن (static member variable) ضِمْن ذلك الصنف، ويُهيِئ قيمته المبدئية (initialization). لمّا كانت تَعْليمَات التَّصْريح (declaration statements) هي النوع الوحيد من التَعْليمَات التي يُمكِن كتابتها خارج أيّ برنامج فرعي (subroutine)، وعليه فإن تَعْليمَات الإِسْناد (assignment statements) غير ممكنة الكتابة خارجها، كان لزامًا تهيئة المُتَغيِّرات الأعضاء الساكنة أثناء التَّصْريح عنها -إذا أردنا القيام بالتهيئة-، فهو في تلك الحالة ليس مُجرَّد اختصار لتَعْليمَة تَّصْريح (declaration) مَتبوعة بتَعْليمَة إِسناد (assignment statement) مثلما هو الحال مع المُتَغيِّرات المحليّة. لاحِظ عدم إِمكانية القيام بالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_19" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Bank</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> interestRate</span><span class="pun">;</span><span class="pln">
   </span><span class="com">// غير صالح! لا يمكن استخدام تعليمة إسناد خارج برنامج فرعي</span><span class="pln">
   interestRate </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.05</span><span class="pun">;</span><span class="pln">  
   </span><span class="pun">.</span><span class="pln">                     
   </span><span class="pun">.</span><span class="pln">
   </span><span class="pun">.</span></pre>

<p>
	لذلك، غالبًا ما يَحتوِي التَّصْريح عن مُتَغيِّر عضو (member variables) على قيمته المبدئية. وكما ذَكَرَنا سلفًا بالقسم الفرعي ٤.٢.٤، فإنه في حالة عدم تَخْصِيص قيمة مبدئية لمُتَغيِّر عضو معين (member variable)، تُسنَد إليه قيمة مبدئية افتراضية. على سبيل المثال، اِستخدَام التَعْليمَة <code>static int count</code> للتَّصْريح عن المُتَغيِّر العضو <code>count</code> هو مُكافِئ تمامًا للتَعْليمَة <code>static int count = 0;‎</code>.
</p>

<p>
	نستطيع أيضًا تهيئة مُتَغيِّرات المصفوفة (array variables) مبدئيًا. ولمّا كانت المصفوفة عمومًا مُكوَّنة من عدة عناصر وليس مُجرَّد قيمة وحيدة، تُستخدَم قائمة من القيم، مَفصولة بفاصلة (comma)، ومُحاطة بزوج من الأقواس؛ لتهيئة (initialize) المُتَغيِّرات من ذلك النوع، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_21" style="">
<span class="typ">int</span><span class="pun">[]</span><span class="pln"> smallPrimes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">,</span><span class="pln"> </span><span class="lit">17</span><span class="pun">,</span><span class="pln"> </span><span class="lit">19</span><span class="pun">,</span><span class="pln"> </span><span class="lit">23</span><span class="pun">,</span><span class="pln"> </span><span class="lit">29</span><span class="pln"> </span><span class="pun">};</span></pre>

<p>
	تُنشِئ التَعْليمَة بالأعلى مصفوفة أعداد صحيحة (array of int)، وتَملؤها بالقيم ضِمْن القائمة. يُحدِّد عدد العناصر بالقائمة طول المصفوفة المُعرَّفة، أيّ أن طولها (length) -في المثال بالأعلى- يُساوِي ١٠.
</p>

<p>
	تَقْتصِر صيغة (syntax) تهيئة المصفوفات -يُقصَد بذلك قائمة العناصر- على تَعْليمَات التَّصْريح (declaration statement)، أي بينما نُصرِّح عن مُتَغيِّر مصفوفة (array variable)، ولا يُمكِن اِستخدَامها ضِمْن تَعْليمَات الإِسْناد (assignment statements).
</p>

<p>
	تستطيع أيضًا إنشاء مصفوفة باِستخدَام العَامِل <code>new</code>، ثم تَستخدِمها لتهيئة مُتَغيِّر مصفوفة (array variable). لاحِظ أن تلك الصيغة صالحة ضِمْن تَعْليمَات الإِسْناد أيضًا على العَكْس من الصيغة السابقة. على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_23" style="">
<span class="typ">String</span><span class="pun">[]</span><span class="pln"> nameList </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">String</span><span class="pun">[</span><span class="lit">100</span><span class="pun">];</span></pre>

<p>
	ستَحتوِي جميع عناصر المصفوفة على القيمة الافتراضية في المثال بالأعلى.
</p>

<h2>
	التصريح عن المتغيرات باستخدام <code>var</code>
</h2>

<p>
	منذ الإصدار العاشر، تُوفِّر الجافا صيغة (syntax) جديدة للتَّصْريح عن المُتَغيِّرات، باستخدَام كلمة <code>var</code>، بشَّرْط تَخْصيص قيمة مبدئية ضِمْن تَعْليمَة التَّصْريح. تمتلك المُتَغيِّرات المُصرَّح عنها بتلك الطريقة نوعًا محدَّدًا، كأي مُتَغيِّر عادي آخر، ولكن بدلًا من تَحْديد ذلك النوع تحديدًا صريحًا، يعتمد مُصرِّف الجافا (Java compiler) على نوع القيمة المبدئية المُخصَّصة لتَحْديد نوع ذلك المُتَغيِّر. تَقْتصِر تلك الصيغة، مع ذلك، على المُتَغيِّرات المحليّة (local variables)، أي تلك المُصرَّح عنها ضِمْن برنامج فرعي (انظر القسم الفرعي ٤.٢.٤). اُنظر تَعْليمَة التَّصْريح التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_25" style="">
<span class="pln">var interestRate </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.05</span><span class="pun">;</span></pre>

<p>
	تُستخدَم التَعْليمَة بالأعلى لتعريف (define) مُتَغيِّر محليّ اسمه <code>interestRate</code> بقيمة مبدئية تُساوِي ٠,٠٥، ولمّا كانت القيمة المبدئية المُخصَّصة من النوع <code>double</code>، يَكُون نوع ذلك المُتَغيِّر هو <code>double</code>. بالمثل، للتَّصْريح عن مُتَغيِّر محليّ اسمه <code>nameList</code> من النوع <code>String[]‎</code>، يُمكِنك كتابة التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_27" style="">
<span class="pln">var nameList </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">String</span><span class="pun">[</span><span class="lit">100</span><span class="pun">];</span></pre>

<p>
	تستطيع أيضًا اِستخدَام كلمة <code>var</code> أثناء التَّصْريح عن المُتَغيِّر المُتحكِّم بالحَلْقة (loop control variable) ضِمْن الحَلْقة <code>for</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_29" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> var i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">  i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قد لا يبدو ذلك مفيدًا في الوقت الحالي، ولكنك ستُدرِك أهميته عندما نَتَعرَّض لما يُعرَف باسم الأنواع المُعمَّمة أو الأنواع المُحدَّدة بمعاملات نوع (parameterized types)، والتي تُعدّ أكثر تعقيدًا. سنتناول تلك الأنواع بكُلًا من القسم ٧.٢، والفصل العاشر.
</p>

<h2>
	الثوابت المسماة (named constants)
</h2>

<p>
	في بعض الأحيان، لا يَكُون هناك حاجة لتَعْديل قيمة المُتَغيِّر بَعْد تهيئتها مبدئيًا (initialize). على سبيل المثال، هُيَئ المُتَغيِّر <code>interestRate</code> بالأعلى، بحيث تَكُون قيمته المبدئية مُساوِية للقيمة ٠,٠٥. دَعْنَا نفْترِض أنه لا حاجة لتَعْديل تلك القيمة طوال فترة تَّنْفيذ البرنامج. في مثل تلك الحالات، قد يبدو المُتَغيِّر عديم الفائدة، ولهذا قد تَتَساءل، لماذا قد يُعرِّف (defining) المبرمج ذلك المُتَغيِّر من الأساس؟ في الواقع، يَلجأ المُبرمجين عادةً إلى تعريف تلك المُتَغيِّرات؛ بهدف إعطاء قيمة عددية معينة (٠,٠٥ في هذا المثال) اسمًا له مَغزى، فبخلاف ذلك، ستَكُون القيمة ٠,٠٥ بلا أي مَعنَى؛ فمن الأسهل عمومًا فِهم تَعْليمَة مثل <code>principal += principal*interestRate;‎</code> بالمُوازنة مع <code>principal += principal*0.05</code>.
</p>

<p>
	يُمكِن اِستخدَام المُبدِّل (modifier)‏ <code>final</code> أثناء التَّصْريح عن مُتَغيِّر معين (variable declaration)؛ للتَأكُّد من اِستحالة تَعْديل القيمة المُخزَّنة بذلك المُتَغيِّر بمجرد تَهيئتها (initialize). إذا صَرَّحت، مثلًا، عن المُتَغيِّر العضو <code>interestRate</code> باستخدام التَعْليمَة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_31" style="">
<span class="kwd">public</span><span class="pln"> final </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> interestRate </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.05</span><span class="pun">;</span></pre>

<p>
	فسيَستحِيل تَعْديل قيمة ذلك المُتَغيِّر <code>interestRate</code> بأيّ مكان آخر داخل البرنامج، فإذا حَاوَلت، مثلًا، اِستخدَام تَعْليمَة إِسْناد لتَعْديل قيمته، فإن الحاسوب سيُبلِّغ عن وجود خطأ في بناء الجملة (syntax error) أثناء تَصْرِيف (compile) البرنامج. من المنطقي عمومًا اِستخدَام المُبدِّل <code>final</code> مع مُتَغيِّر عام (public) يُمثِل قيمة "مُعدل الفائدة"؛ فبينما يُريد بنك معين الإعلان عن قيمة "مُعدل الفائدة"، فإنه، وبكل تأكيد، لا يُريد أن يَسمَح لأشخاص عشوائية بتَعْديل قيمة "مُعدل الفائدة".
</p>

<p>
	تَبرز أهمية المُبدِّل <code>final</code> عند اِستخدَامه مع المُتَغيِّرات الأعضاء، ولكنه مع ذلك، قابل للاِستخدَام مع كلا من المُتَغيِّرات المحليّة (local variables)، والمُعامِلات الصُّوريّة (formal parameters). يُطلَق مصطلح الثوابت المُسمَاة (named constants) على المُتَغيِّرات الأعضاء الساكنة (static member variable) المُصرَّح عنها باِستخدَام المُبدِّل <code>final</code>؛ لأن قيمتها تَظلّ تابثة طوال فترة تَّنْفيذ البرنامج. اِستخدَامك للثوابت المُسمَاة (named constants) قادر على تَحسِّين شيفرة البرامج بشكل كبير، وجَعْلها مَقروءة؛ فأنت بالنهاية تُعطِي أسماء ذات مَغزى للمقادير المُهمة بالبرنامج، ويُوصَى عمومًا بأن تَكُون تلك الأسماء مُكوَّنة بالكامل من حروف كبيرة (upper case letters)، بحيث يَفصِل محرف الشرطة السُفلية (underscore) بين الكلمات إذا ما لَزِم الأمر. على سبيل المثال، يُمكِن تعريف "مُعدَل الفائدة" كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_33" style="">
<span class="kwd">public</span><span class="pln"> final </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> INTEREST_RATE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.05</span><span class="pun">;</span></pre>

<p>
	يَشيِع اِستخدَام نَمط التسمية بالأعلى عمومًا بأصناف الجافا القياسية (standard classes)، والتي تُعرِّف الكثير من الثوابت المُسمَاة. فمثلًا، تَعرَّضنا بالفعل للمُتَغيِّر <code>Math.PI</code> من النوع <code>double</code> المُعرَّف ضِمْن الصنف <code>Math</code> باِستخدَام المُبدِّلات <code>public final static</code>. بالمثل، يَحتوِي الصَنْف <code>Color</code> على مجموعة من الثوابت المُسمَاة (named constants) مثل: <code>Color.RED</code> و <code>Color.YELLOW</code>، والتي هي مُتَغيِّرات من النوع <code>Color</code>، مُعرَّفة باِستخدَام نفس مجموعة المُبدِّلات <code>public final static</code>.
</p>

<p>
	تُعدّ ثوابت أنواع التعداد (enumerated type constants)، والتي تَعرَّضنا لها خلال القسم الفرعي ٢.٣.٣، مثالًا آخرًا للثوابت المُسمَاة. يُمكِننا تعريف تعداد من النوع <code>Alignment</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_35" style="">
<span class="kwd">enum</span><span class="pln"> </span><span class="typ">Alignment</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> LEFT</span><span class="pun">,</span><span class="pln"> RIGHT</span><span class="pun">,</span><span class="pln"> CENTER </span><span class="pun">}</span></pre>

<p>
	يُعرِّف ذلك التعداد كُلًا من الثوابت <code>Alignment.LEFT</code> و <code>Alignment.RIGHT</code> و <code>Alignment.CENTER</code>. تقنيًا، يُعدّ <code>Alignment</code> صنفًا (class)، وتُعدّ تلك الثوابت (constants) الثلاثة أعضاء ساكنة عامة ونهائية (public final static) ضِمْن ذلك الصَنْف. في الواقع، يُشبِه تعريف نوع التعداد (enumerated type) بالأعلى تعريف ثلاثة ثوابت من النوع <code>int</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_37" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> final </span><span class="typ">int</span><span class="pln"> ALIGNMENT_LEFT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> final </span><span class="typ">int</span><span class="pln"> ALIGNMENT_RIGHT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> final </span><span class="typ">int</span><span class="pln"> ALIGNMENT_CENTER </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span></pre>

<p>
	وفي الحقيقة، كانت تلك الطريقة هي الأسلوب المُتبَع قبل ظهور أنواع التعداد (enumerated types)، وما تزال في الواقع مُستخدَمة بكثير من الحالات. فبِتَوفُّر ثوابت الأعداد الصحيحة (integer constants) بالأعلى، تستطيع الآن ببساطة تعريف مُتَغيِّر من النوع <code>int</code>، وإِسْناد واحدة من تلك القيم الثلاثة <code>ALIGNMENT_LEFT</code> و <code>ALIGNMENT_RIGHT</code> و <code>ALIGNMENT_CENTER</code> له؛ بهدف تمثيل أنواع مختلفة من التعداد <code>Alignment</code>. مع ذلك هناك مشكلة، وهي عدم إِطلاع الحاسوب على نيتك باِستخدَام ذلك المُتَغيِّر لتمثيل قيمة من النوع <code>Alignment</code>، لذا فإنه لن يَعترِض إذا حاولت إِسْناد قيمة هي ليست ضِمْن تلك القيم الثلاثة الصالحة.
</p>

<p>
	في المقابل، ومع ظهور أنواع التعداد (enumerated type)، فإنه إذا كان لديك مُتَغيِّر من نوع التعداد <code>Alignment</code>، فيُمكِنك فقط إِسْناد إحدى تلك القيم الثابتة المُدرجة بتعريف التعداد إليه، وأي محاولة لإِسْناد قيم آخرى غَيْر صالحة ستُعدّ بمثابة خطأ ببناء الجملة (syntax error) سيَكْتَشفها الحاسوب أثناء تَصْرِيف (compile) البرنامج. يُوفِّر ذلك نوعًا من الأمان الإضافي، وهو أحد أهم مميزات أنواع التعداد (enumerated types).
</p>

<p>
	يُسهِل استخدام الثوابت المُسمَاة (named constants) من تَعْديل قيمة الثابت المُسمَى. بالطبع، لا يُقصَد بذلك تَعْديلها أثناء تَّنْفيذ البرنامج، وإنما بين تَّنْفيذ معين والذي يليه، أيّ تَعْديل القيمة داخل الشيفرة المصدرية ذاتها ثم إعادة تَصرِيف (recompile) البرنامج. لنُعيد التفكير بمثال "معدل الفائدة"، غالبًا ما ستَكُون قيمة "مُعدَل الفائدة" مُستخدَمة أكثر من مرة عبر شيفرة البرنامج. لنفْترِض أن البنك قد عَدَّل قيمة "معدل الفائدة"، وعليه ينبغي تَعْديلها بالبرنامج. إذا كانت القيمة ٠,٠٥ مُستخدَمة بشكل مُجرَّد ضِمْن الشيفرة، فسيَضطرّ المبرمج لتَعقُّب جميع الأماكن المُستخدِمة لتلك القيمة بحيث يُعدِّلها إلى القيمة الجديدة. يَصعُب القيام بذلك خصوصًا مع احتمالية اِستخدَام القيمة ٠,٠٥ داخل البرنامج لأهداف مختلفة غير "مُعدَل الفائدة"، بالإضافة إلى احتمالية اِستخدَام القيمة ٠,٠٢٥ مثلًا لتمثيل نصف قيمة "مُعدَل الفائدة". في المقابل، إذا كنا قد صَرَّحنا عن الثابت المُسمَى <code>INTEREST_RATE</code> ضِمْن البرنامج، واستخدَمناه بصورة مُتَّسقِة عبر شيفرة البرنامج بالكامل، فسنحتاج إلى تعديل سطر وحيد فقط هو سَطْر التهيئة المبدئية لذلك الثابت.
</p>

<p>
	لنأخذ مثالًا آخر من القسم السابق، سنُعيد خلاله كتابة نسخة جديدة من البرنامج <code>RandomMosaicWalk</code>. ستَستخدِم تلك النسخة عدة ثوابت مُسمَاة (named constants) بهدف تمثيل كُلًا من عدد الصفوف، وعدد الأعمدة، وحجم كل مربع صغير بنافذة الصَنْف <code>mosaic</code>. سيُصرَّح عن تلك الثوابت (constants) الثلاثة كمُتَغيِّرات أعضاء ساكنة نهائية (final static member) كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_39" style="">
<span class="pln">final </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> ROWS </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln">        </span><span class="com">// عدد صفوف النافذة</span><span class="pln">
final </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> COLUMNS </span><span class="pun">=</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">     </span><span class="com">// عدد أعمدة النافذة</span><span class="pln">
final </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> SQUARE_SIZE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">15</span><span class="pun">;</span><span class="pln"> </span><span class="com">// حجم كل مربع بالنافذة</span></pre>

<p>
	عُدِّل أيضًا باقي البرنامج بحرِص بحيث يتلائم مع الثوابت المُسمَاة (named constants) المُعرَّفة، فمثلًا، لفَتْح نافذة <code>Mosaic</code> بالنسخة الجديدة من البرنامج، يُمكِن استخدام التَعْليمَة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_41" style="">
<span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="pln">ROWS</span><span class="pun">,</span><span class="pln"> COLUMNS</span><span class="pun">,</span><span class="pln"> SQUARE_SIZE</span><span class="pun">,</span><span class="pln"> SQUARE_SIZE</span><span class="pun">);</span></pre>

<p>
	ليس من السهل دومًا العُثور على جميع تلك الأماكن التي يُفْترَض بها اِستخدَام ثابت مُسمَى معين. لذا، انتبه! ففي حالة عدم اِستخدَامك لثابت مُسمَى معين بصورة مُتَّسقِة عبر شيفرة البرنامج بالكامل، فأنت تقريبًا قد أَفسدت الهدف الأساسي منه. لذلك يُنصَح عادة بتجربة البرنامج عدة مرات، بحيث تَستخدِم قيمة مختلفة للثابت المُسمَى (named constant) في كل مرة؛ لاِختبار كَوْنه يَعَمَل بصورة سليمة بجميع الحالات.
</p>

<p>
	اُنظر النسخة الجديدة من البرنامج كاملة <code>RandomMosaicWalk2</code> بالأسفل. لاحظ كيفية اِستخدَام الثابتين <code>ROWS</code> و <code>COLUMNS</code> داخل البرنامج <code>randomMove()‎</code> عند تحريكه للتشويش (disturbance) من إحدى حواف النافذة <code>mosaic</code> إلى الحافة المضادة. لم تُضاف التعليقات (comments) لغرض تَوْفِير المساحة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_43" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">RandomMosaicWalk2</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    final </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> ROWS </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln">        </span><span class="com">// عدد الصفوف بالنافذة</span><span class="pln">
    final </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> COLUMNS </span><span class="pun">=</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">     </span><span class="com">// عدد الأعمدة بالنافذة</span><span class="pln">
    final </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> SQUARE_SIZE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">15</span><span class="pun">;</span><span class="pln"> </span><span class="com">// حجم كل مربع بالنافذة</span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> currentRow</span><span class="pun">;</span><span class="pln">    </span><span class="com">// رقم الصف المعرض للتشويش</span><span class="pln">
    </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> currentColumn</span><span class="pun">;</span><span class="pln"> </span><span class="com">// رقم العمود المعرض للتشويش</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="pln"> ROWS</span><span class="pun">,</span><span class="pln"> COLUMNS</span><span class="pun">,</span><span class="pln"> SQUARE_SIZE</span><span class="pun">,</span><span class="pln"> SQUARE_SIZE </span><span class="pun">);</span><span class="pln">
        fillWithRandomColors</span><span class="pun">();</span><span class="pln">
        currentRow </span><span class="pun">=</span><span class="pln"> ROWS </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">   </span><span class="com">// ابدأ بمنتصف النافذة</span><span class="pln">
        currentColumn </span><span class="pun">=</span><span class="pln"> COLUMNS </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            changeToRandomColor</span><span class="pun">(</span><span class="pln">currentRow</span><span class="pun">,</span><span class="pln"> currentColumn</span><span class="pun">);</span><span class="pln">
            randomMove</span><span class="pun">();</span><span class="pln">
            </span><span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">delay</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">  </span><span class="com">// نهاية‫ main</span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> fillWithRandomColors</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
         </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> row</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> row </span><span class="pun">&lt;</span><span class="pln"> ROWS</span><span class="pun">;</span><span class="pln"> row</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> column </span><span class="pun">&lt;</span><span class="pln"> COLUMNS</span><span class="pun">;</span><span class="pln"> column</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                changeToRandomColor</span><span class="pun">(</span><span class="pln">row</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">);</span><span class="pln">  
            </span><span class="pun">}</span><span class="pln">
         </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">  </span><span class="com">// نهاية‫ fillWithRandomColors</span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> changeToRandomColor</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> rowNum</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> colNum</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// اختر قيم عشوائية تتراوح بين 0 و 255</span><span class="pln">
        </span><span class="com">// لقيم الألوان الثلاثة (الأحمر، و الأزرق، والأخضر‫)</span><span class="pln">
        </span><span class="com">// ‫بنظام الألوان RGB</span><span class="pln">
         </span><span class="typ">int</span><span class="pln"> red </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">    
         </span><span class="typ">int</span><span class="pln"> green </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">  
         </span><span class="typ">int</span><span class="pln"> blue </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">   
         </span><span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">setColor</span><span class="pun">(</span><span class="pln">rowNum</span><span class="pun">,</span><span class="pln">colNum</span><span class="pun">,</span><span class="pln">red</span><span class="pun">,</span><span class="pln">green</span><span class="pun">,</span><span class="pln">blue</span><span class="pun">);</span><span class="pln">  
     </span><span class="pun">}</span><span class="pln">  </span><span class="com">// نهاية‫ changeToRandomColor</span><span class="pln">

     </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> randomMove</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
         </span><span class="com">// ‫اضبط القيمة عشوائيًا بحيث تتراوح من 0 وحتى 3</span><span class="pln">
         </span><span class="typ">int</span><span class="pln"> directionNum</span><span class="pun">;</span><span class="pln"> 
         directionNum </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">4</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
         </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">directionNum</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">  </span><span class="com">// تحرك للأعلى </span><span class="pln">
               currentRow</span><span class="pun">--;</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentRow </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
                  currentRow </span><span class="pun">=</span><span class="pln"> ROWS </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
               </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">  </span><span class="com">// تحرك لليمين</span><span class="pln">
               currentColumn</span><span class="pun">++;</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentColumn </span><span class="pun">&gt;=</span><span class="pln"> COLUMNS</span><span class="pun">)</span><span class="pln">
                  currentColumn </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
               </span><span class="kwd">break</span><span class="pun">;</span><span class="pln"> 
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">  </span><span class="com">// تحرك للأسفل</span><span class="pln">
               currentRow</span><span class="pun">++;</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentRow </span><span class="pun">&gt;=</span><span class="pln"> ROWS</span><span class="pun">)</span><span class="pln">
                  currentRow </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
               </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">  </span><span class="com">// تحرك لليسار  </span><span class="pln">
               currentColumn</span><span class="pun">--;</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentColumn </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
                  currentColumn </span><span class="pun">=</span><span class="pln"> COLUMNS </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
               </span><span class="kwd">break</span><span class="pun">;</span><span class="pln"> 
         </span><span class="pun">}</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية randomMove</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// نهاية الصنف‫ RandomMosaicWalk2</span></pre>

<h2>
	التسمية وقواعد النطاق (scope rules)
</h2>

<p>
	عندما نُصرِّح عن مُتَغيِّر ما (variable declaration)، يُخصِّص الحاسوب مساحة من الذاكرة لذلك المُتَغيِّر. بحيث تستطيع اِستخدَام اسم ذلك المُتَغيِّر ضِمْن جزء معين على الأقل من شيفرة البرنامج؛ بهدف الإشارة إلى تلك المساحة من الذاكرة أو إلى تلك البيانات المُخزَّنة بها. يُطلَق على ذلك الجزء من الشيفرة، والذي يَكُون فيه اسم المُتَغيِّر صالحًا للاِستخدَام، اسم نطاق المُتَغيِّر (scope of variable). بالمثل، يُمكِن الإشارة إلى نطاق كُلًا من أسماء البرامج الفرعية (subroutine) وأسماء المُعامِلات الصُّوريّة (formal parameter).
</p>

<p>
	لنبدأ بالأعضاء الساكنة من البرامج الفرعية، والتي تُعدّ قواعد نطاقها (scope rule) بسيطة نوعًا ما. يَمتد نطاق (scope) أي برنامج فرعي ساكن إلى كامل الشيفرة المصدرية للصَنْف (class) المُعرَّف بداخله، أيّ يُمكِن استدعاء ذلك البرنامج الفرعي من أيّ مكان داخل الصنف، بما في ذلك تلك الأماكن الواقعة قَبْل تعريف (definition) البرنامج الفرعي. بل أنه حتى من المُمكن لبرنامج فرعي معين استدعاء ذاته، وهو ما يُعرَف باسم التَعاود أو الاستدعاء الذاتي (recursion)، وهو أحد المواضيع المتقدمة نسبيًا، وسنتناوله عمومًا بالقسم ٩.١. وأخيرًا، إذا لم يَكُن البرنامج الفرعي خاصًا (private)، فتستطيع حتى الوصول إليه من خارج الصَنْف المُعرَّف بداخله بشَّرْط اِستخدَام اسمه الكامل.
</p>

<p>
	لننتقل الآن إلى الأعضاء الساكنة من المُتَغيِّرات، والتي تَملُك قواعد نطاق (scope rule) مشابهة بالإضافة إلى تعقيد واحد إضافي هو كالآتي. تستطيع عمومًا تعريف مُتَغيِّر محليّ (local variable) أو مُعامِل صُّوريّ (formal parameter) يَحمِل نفس اسم إحدى المُتَغيِّرات الأعضاء (member variable) ضِمْن الصَنْف، وفي تلك الحالة، يُعدّ المُتَغيِّر العضو مخفيًا ضِمْن نطاق المُتَغيِّر المحليّ أو المُعامِل الذي يَحمِل نفس الاسم. فعلى سبيل المثال، إذا كان لدينا الصَنْف <code>Game</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_45" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Game</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">  </span><span class="com">// متغير عضو</span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> playGame</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">  </span><span class="com">// متغير محلي</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">   </span><span class="com">// ‫بعض التعليمات لتعريف playGame()</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">.</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">   </span><span class="com">// المزيد من المتغيرات والبرامج الفرعية</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">

</span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية الصنف Game</span></pre>

<p>
	يُشير الاسم <code>count</code> بالتَعْليمات المُؤلِّفة لمَتْن (body) البرنامج الفرعي <code>playGame()‎</code> إلى المُتَغيِّر المحليّ (local variable). أما ببقية الصنف <code>Game</code>، فإنه سيُشيِر إلى المُتَغيِّر العضو (member variable)، بالطبع إذا لم يُخفَى باستخدام مُتَغيِّر محليّ آخر أو مُعامِلات تَحمِل نفس الاسم <code>count</code>. مع ذلك، ما يزال بإمكانك الإشارة إلى المُتَغيِّر العضو <code>count</code> بواسطة اسمه الكامل <code>Game.count</code>، والذي يُستخدَم، في العادة، خارج الصَنْف الذي عُرِّف به العضو، ولكن ليس هناك قاعدة تَمنع اِستخدَامه داخل الصنف. لهذا يُمكِن اِستخدَام الاسم الكامل <code>Game.count</code> داخل البرنامج الفرعي <code>playGame()‎</code> للإشارة إلى المُتَغيِّر العضو بدلًا من المُتَغيِّر المحليّ. يُمكِننا الآن تلخيص قاعدة النطاق (scope rule) كالآتي: يَشمَل نطاق مُتَغيِّر عضو ساكن الصنف المُعرَّف بداخله بالكامل، وعندما يُصبِح الاسم البسيط (simple name) للمُتَغيِّر العضو مَخفيًا نتيجة تعريف مُتَغيِّر محليّ أو مُعامِل صُّوريّ يَحمِل نفس الاسم، يُصبِح من الضروري اِستخدَام الاسم الكامل على الصورة <strong><classname>.<variablename></variablename></classname></strong> للإشارة إلى المُتَغيِّر العضو. تُشبِه قواعد نطاق الأعضاء غير الساكنة (non-static) عمومًا تلك الخاصة بالأعضاء الساكنة، باستثناء أن الأولى لا يُمكِن اِستخدَامها بالبرامج الفرعية الساكنة (static subroutines)، كما سنرى لاحقًا.
</p>

<p>
	أخيرًا، يَتَكوَّن نطاق المُعامِل الصُّوريّ (formal parameter) لبرنامج فرعي معين من الكُتلَة (block) المُؤلِّفة لمَتْن البرنامج الفرعي (subroutine body). في المقابل، يَمتَد نطاق المُتَغيِّر المحليّ (local variable) بدايةً من تَعْليمَة التَّصْريح (declaration statement) المسئولة عن تعريف ذلك المُتَغيِّر وحتى نهاية الكُتلَة (block) التي حَدَثَ خلالها ذلك التَّصْريح. كما أشرنا بالأعلى، تستطيع التَّصْريح عن المُتَغيِّر المُتحكِّم بحَلْقة (loop control variable)‏ <code>for</code> ضمن التعليمة ذاتها على الصورة <code>for (int i=0; i &lt; 10; i++)‎</code>، ويُعدّ نطاق مثل هذا التَّصْريح (declaration) حالة خاصة: فهو صالح فقط ضِمْن تَعْليمَة <code>for</code>، ولا يَمتَد إلى بقية الكُتلَة المتضمنة للتَعْليمَة. لا يُسمَح عمومًا بإعادة تعريف (redefine) اسم المُعامِل الصُّوريّ أو المُتَغيِّر المحليّ ضِمْن نطاقه (scope)، حتى إذا كان ذلك داخل كُتلَة مُتداخِلة (nested block)، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_47" style="">
<span class="kwd">void</span><span class="pln">  badSub</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫خطأ، لأن x مُعرَّفة بالفعل</span><span class="pln">
         </span><span class="pun">.</span><span class="pln">
         </span><span class="pun">.</span><span class="pln">
         </span><span class="pun">.</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 </span><span class="pun">}</span></pre>

<p>
	في الواقع، تَسمَح بعض اللغات بذلك، بحيث يُخفِي التَّصْريح عن <code>x</code> ضِمْن حَلْقة <code>while</code> التَّصْريح الأصلى، ولكن لا تَسمَح الجافا بذلك، حيث يُصبِح اسم المُتَغيِّر متاحًا للاِستخدَام مرة آخرى فقط بعد انتهاء تَّنْفيذ الكُتلَة (block) المُصرَّح عن المُتَغيِّر ضِمْنها. اُنظر على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_49" style="">
<span class="kwd">void</span><span class="pln"> goodSub</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">int</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">
      </span><span class="com">// ينتهي نطاق‫ x هنا</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">int</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫صالح، فتَّصريح x السابق انتهت صلاحيته</span><span class="pln">
       </span><span class="pun">.</span><span class="pln">
       </span><span class="pun">.</span><span class="pln">
       </span><span class="pun">.</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هل تَتَسبَّب أسماء المُتَغيِّرات المحليّة (local variable) بإخفاء أسماء البرامج الفرعية (subroutine names)؟ لا يُمكِن حُدوث ذلك لسبب قد يبدو مفاجئًا. ببساطة، لمّا كانت أسماء البرامج الفرعية دومًا مَتبوعة بزوج من الأقواس (parenthesis)، والتي يُسْتحسَن التفكير بها على أساس أنها جزء من اسم البرنامج الفرعي، كأن تقول البرنامج الفرعي <code>main()‎</code> وليس البرنامج الفرعي <code>main</code>، فإن الحاسوب عمومًا يُمكِنه دائمًا مَعرِفة ما إذا كان اسم معين يُشير إلى مُتَغيِّر أم إلى برنامج فرعي، لذا ليس ضروريًا أن تكون أسماء المُتَغيِّرات والبرامج الفرعية مختلفة من الأساس، حيث يُمكِنك ببساطة تعريف مُتَغيِّر اسمه <code>count</code> وبرنامج فرعي بنفس الاسم <code>count</code> ضِمْن نفس الصَنْف. كذلك لمّا كان الحاسوب قادرًا على مَعرِفة ما إذا كان اسم معين يُشير إلى اسم صَنْف أم لا وِفقًا لقواعد الصيغة (syntax)، فإنه حتى يُمكِن إعادة اِستخدَام أسماء الأصناف (classes) بهدف تسمية كلا من المُتَغيِّرات والبرامج الفرعية. اسم الصنف هو بالنهاية نوع، لذا يُمكِن اِستخدَام ذلك الاسم للتََّصْريح عن المُتَغيِّرات والمُعامِلات الصُّوريّة (formal parameters)، بالإضافة إلى تَخْصيص نوع القيمة المُعادة (return type) من دالة (function) معينة. يَعنِي ذلك أنك تستطيع التََّصْريح عن الدالة التالية ضِمْن صَنْف اسمه <code>Insanity</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3272_51" style="">
<span class="kwd">static</span><span class="pln">  </span><span class="typ">Insanity</span><span class="pln">  </span><span class="typ">Insanity</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Insanity</span><span class="pln"> </span><span class="typ">Insanity</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	يَستخدِم التََّصْريح -بالأعلى- الاسم <code>Insanity</code> ٤ مرات، تُشير الأولى إلى النوع المُعاد (return type) من الدالة، بينما تُشير الثانية إلى اسم تلك الدالة، والثالثة إلى نوع مُعاملها الصُّوريّ (formal parameter)، والرابعة إلى اسم ذلك المُعامِل. لكن تَذَكَّر! لا يُعدّ كل ما هو مُتاح فكرة جيدة بالضرورة.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c4/s8.html" rel="external nofollow">Section 8: The Truth About Declarations</a> من فصل Chapter 4: Programming in the Large I: Subroutines من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1093</guid><pubDate>Mon, 14 Dec 2020 19:13:33 +0000</pubDate></item><item><title>&#x62A;&#x635;&#x645;&#x64A;&#x645; &#x627;&#x644;&#x628;&#x631;&#x627;&#x645;&#x62C; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1092/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_12/29.png.f0637a6e5c2ce9682f3c2df78228440d.png" /></p>

<p>
	قُدرتك على اِستيعاب طريقة عمل البرامج، وفهمها هو أمر جيد بلا شك، ولكنه يختلف تمامًا عن تَصميمها بحيث تُنفِّذ مُهِمّة معينة. لقد ناقشنا بالقسم ٣.٢ كيفية تَطْوير الخوارزميات بطريقة مَنهجية باستخدام أسلوب التصميم المُتدرج (stepwise refinement) والشيفرة الوهمية (pseudocode).
</p>

<p>
	التصميم المُتدرج هو عملية تَقَع ضِمْن استراتيجيات التصميم من أعلى لأسفل (top-down)، أيّ لابُدّ عمومًا من وجود نقطة معينة تَتَوقَّف عندها عن عملية التحسِّين التدريجي لخوارزمية الشيفرة الوهمية (pseudocode algorithm)، وتُحوِّل عندها تلك الخوارزمية مباشرة إلى شيفرة برنامج فعليّة. بدون البرامج الفرعية (subroutines)، ستُمثِل تلك النقطة مستوًى بدائيًا جدًا من العمليات، كتَعْليمَات الإِسْناد (assignment statements)، وعمليات الدَخْل والخَرْج، أما في حالة تَوفُّر البرامج الفرعية المسئولة عن إنجاز بعض المَهَامّ (tasks) المُحدَّدة، فسيَكُون بإمكانك التَوقُّف عن التحسِّين بمجرد تعبيرك عن الخوارزمية بنفس المصطلحات التي تَستخدِمها البرامج الفرعية.
</p>

<p>
	يَعنِي ذلك أننا قد أضفنا عنصر، هو بالأساس يَتَّبِع أسلوب التصميم من أسفل لأعلى (bottom-up)، إلى استراتيجيات التصميم من أعلى لأسفل (top-down approach) الخاصة بالتصميم المُتدرج. بفَرْض وجود مشكلة معينة، تستطيع الآن البدء بكتابة بعض البرامج الفرعية (subroutines) المسئولة عن إنجاز بعض المَهَامّ المُتَعلِّقة بموضوع البرنامج، بحيث تُصبِح تلك البرامج بمثابة صندوق من الأدوات الجاهزة (toolbox) يُمكِنك دَمْجها إلى الخوارزمية أثناء تَطْويرها، أو حتى قد تستطيع شراء صندوق أدوات برمجي جاهز (software toolbox)، كُتب بواسطة شخص آخر، بحيث يَتَضمَّن ذلك الصندوق مجموعة من البرامج الفرعية، التي ستَكُون بمثابة صندوقًا أسودًا (black boxes)، يُمكِنك تَوظِّيفه ضِمْن المشروع الخاص بك.
</p>

<p>
	بإمكانك حتى استخدام البرامج الفرعية مباشرة ضِمْن أساليب التصميم من أعلى لأسفل (top-down approach) الأكثر صرامة، بمعنى أنه وبينما تُحسِّن الخوارزمية بالطريقة المُعتادة، يُمكِنك أن تُعبر عن مُهِمّة فرعية (sub-task) معينة ضِمْن الخوارزمية بصورة استدعاء لبرنامج فرعي. يُصبِح تَطْوير ذلك البرنامج الفرعي عندها مشكلة مُستقلة تستطيع العمل عليها بشكل منفصل. لا يَتَعدَى اتباع تلك الطريقة أكثر من مُجرَّد تَقسِّيم للمشكلة الرئيسية إلى مشكلات صغيرة مُنفصلة، أيّ أنها ما تزال تَقَع ضِمْن استراتيجيات التصميم من أعلى لأسفل؛ لأن تحليلك للمشكلة هو الذي وَجَّهك لكتابة البرامج الفرعية. في المقابل، تَبدأ استراتيجيات التصميم من أسفل لأعلى (bottom-up approach) بكتابة البرامج الفرعية المُتَعلِّقة بموضوع البرنامج، أو الحصول عليها بطريقة ما، بحيث تَعَمَل تلك البرامج الفرعية بمثابة أساس أو قاعدة تُستخدَم لبناء حل للمشكلة الأساسية.
</p>

<h2>
	الشروط المسبقة (precondition) والشروط اللاحقة (postcondition)
</h2>

<p>
	تَعََمَل البرامج الفرعية (subroutines) عمومًا كلَبِنات أساسية (building blocks) ضِمْن البرنامج الأساسي، لذا لابُدّ أن تَكُون طريقة تَفْاعُلها مع ذلك البرنامج واضحة. تُحدِّد المواصفة الاصطلاحية (contract) لأيّ برنامج فرعي عمومًا طريقة التَفْاعُل تلك، وهو ما ناقشناه بالقسم ٤.١، ويُمكِن كتابتها باِستخدَام ما يُعرَف باسم الشروط المُسَبَّقة (precondition) واللاحقة (postcondition).
</p>

<p>
	لابُدّ أن تَكُون الشروط المُسَبَّقة (precondition) لأي برنامج فرعي (subroutine) مُتحقِّقة عند استدعائه. على سبيل المثال، إحدى الشروط المُسَبَّقة (precondition) للدالة <code>Math.sqrt(x)‎</code> المبنية مُسْبَّقًا (built-in function) يَتمثَل في ضرورة أن تَكُون القيمة المُمرَّرة للمُعامِل (parameter)‏ <code>x</code> أكبر من أو تُساوِي الصفر؛ لأنه لا يُمكِن بطبيعة الحال حِسَاب الجذر التربيعي لعدد سالب. عمومًا، يُمثِل الشَّرْط المُسَبَّق (precondition) بمواصفة اصطلاحية معينة إلزامًا على مُستدعِي (caller) البرنامج الفرعي، أيّ أنه في حالة استدعائك لبرنامج فرعي معين دون تَوْفِية شَّرْطه المُسَبَّق، فما من سبب يَدْفَعك لتَوقع إِنجازه للمُهِمّة بشكل ملائم، فلرُبما يَنهار البرنامج أو يَكتفِي بإعادة نتائج غير صحيحة؛ لأنك ببساطة لم تَلتزِم بجانبك من الاتفاق، ولهذا لا تَلوّمن إلا نفسك.
</p>

<p>
	في المقابل، الشروط اللاحقة (postcondition) هي بمثابة الجانب الآخر من المواصفة الاصطلاحية (contract)، حيث تُمثِل إلزامًا على البرنامج الفرعي ذاته، أي بفَرْض اِستيفاء الشروط المُسَبَّقة (preconditions) لبرنامج فرعي معين، وعدم احتوائه على أية أخطاء برمجية (bugs)، فلابُدّ من تَحقُّق شروطه اللاحقة بعد الاستدعاء. على سبيل المثال، الشَّرْط اللاحق للدالة <code>Math.sqrt(x)‎</code> يَتمثَل في ضرورة تَساوِي كُلًا من مربع القيمة المُعادة من تلك الدالة (function) وقيمة المُعامِل (parameter) المُمرَّرة عند استدعاء البرنامج الفرعي، وهو ما سيَكُون صحيحًا فقط في حالة استيفاء شَّرْطها المُسَبَّق بخصوص كَوْن قيمة المُعامِل أكبر من أو تُساوِي الصفر. مثال آخر هو البرنامج الفرعي <code>System.out.print(x)‎</code> المَبنِي مُسْبَّقًا، والذي يَتَمثَل شَّرْطه اللاحق (postcondition) بطباعة قيمة مُعامِله (parameter) المُمرَّرة على الشاشة.
</p>

<p>
	عادة ما تَضَع الشروط المُسَبَّقة (preconditions) لأي برنامج فرعي قيودًا على قيم مُعاملاته، مثل البرنامج الفرعي <code>Math.sqrt(x)‎</code>، لكن لا يَقْتصِر دورها في الواقع على ذلك. قد تُشيِر تلك الشروط أيضًا إلى المُتَغيِّرات العامة (global variables) المُستخدَمة بالبرنامج الفرعي، أو قد تُحدِّد الحالة (state) التي ينبغي أن يَكُون عليها البرنامج عند استدعاء البرنامج الفرعي، وهو ما يَكُون مفيدًا إذا كانت عملية استدعاء ذلك البرنامج صالحة فقط بأوقات معينة.
</p>

<p>
	من الناحية الآخرى، يُحدِّد الشَّرْط اللاحق (postcondition) لأي برنامج فرعي مُهِمّته المُوكَلة إليه. فمثلًا، ينبغي أن يَتضمَّن الشَّرْط اللاحق لأي دالة (function) القيمة المُعادة منها.
</p>

<p>
	تُوصَف البرامج الفرعية أحيانًا باِستخدَام تعليقات (comments)، والتي ينبغي أن تُحدِّد شروط ذلك البرنامج المُسَبَّقة (preconditions) واللاحقة (postconditions). عندما تَستخدِم برنامجًا فرعيًا (subroutine) مكتوب مُسْبَّقًا، ستُخبرك تلك الشروط بكيفية اِستخدَام البرنامج بالإضافة إلى تِبيان الغرض منه. في المقابل، عندما تَكْتُب برنامجًا فرعيًا، ستَمنَحك تلك الشروط توصيفًا دقيقًا عما هو مُتوقَّع من ذلك البرنامج. سنَتَعرَّض خلال القسمين الفرعيين التاليين لمثال بسيط، سنَستخدِم فيه التعليقات لهذا الغرض، وستَكُون مَكْتوبة بصياغة تعليقات <code>Javadoc</code> مع عَنونة كُلًا من الشروط المُسَبَّقة واللاحقة. يرى كثير من علماء الحاسوب ضرورة إضافة وُسوم تَوْثيق جديدة <code>‎@precondition</code> و <code>‎@postcondition</code> إلى نظام <code>Javadoc</code> لعَنونة الشروط المُسَبَّقة واللاحقة بشكل صريح، ولكن لَمْ يَحدُث ذلك حتى الآن.
</p>

<h2>
	مثال عن عملية التصميم
</h2>

<p>
	سنُصمِّم الآن برنامجًا بالاعتماد على البرامج الفرعية بصورة أساسية، بمعنى أننا سنَستخدِم بعض البرامج الفرعية (subroutines) التي سُبق كتابتها كلَبِنة أساسية (building block)، كما أننا سنُصمِّم بعض البرامج الفرعية الجديدة التي قد نحتاجها لإكمال المشروع. فيما يَتعلَّق بالبرامج المَكْتوبة مُسْبَّقًا، سنَستخدِم واجهة برمجة تطبيقات (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) تَحتوِي على صنفين (classes) -كان الكاتب قد كَتَبَهما-، الصَنْف الأول هو <code>Mosaic.java</code> والذي بدوره يَعتمِد على الصنف الثاني <code>MosaicCanvas.java</code>. لاحظ ضرورة تَوفِّير كُلًا من الصنفين <code>Mosaic</code> و <code>MosaicCanvas</code> أثناء تَصْرِيف (compile) البرنامج وتَشْغِيله، مما يَعنِي وجود الملفين <code>Mosaic.java</code> و <code>MosaicCanvas.java</code> -أو ملفات الصَنْفين بَعْد التَصْرِيف- بنفس مجلد الصَنْف المُعرِّف للبرنامج.
</p>

<p>
	يَسمَح لك الصَنْف <code>Mosaic</code> بالتَعْامُل مع نافذة (window) مُكوَّنة من مجموعة من المستطيلات الصغيرة المُلوَّنة، والمُرَتَّبة بصورة صفوف وأعمدة، حيث يَتضمَّن أكثر من عضو برنامج فرعي ساكن (static member subroutines) يُمكِن اِستخدَامها لأغراض فَتْح النافذة، وغَلْقها، بالإضافة إلى التَلاعب بمُحتوياتها. يُوفِّر الصَنْف بطبيعة الحال صندوق أدوات (toolbox) أو واجهة برمجة تطبيقات (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) تَتضمَّن تلك المجموعة من البرامج (routines)، والتي نسْتَعْرِض بالأسفل بعضًا منها، مُوثَّقة باِستخدَام تعليقات <code>Javadoc</code>. تَذَكَّر أن تعليق <code>Javadoc</code> يَسبِق العنصر المَعنِي بذلك التعليق.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_7" style="">
<span class="com">/**
 * ‫افتح نافذة mosaic على الشاشة
 * ‫ينبغي أن يُستدعى هذا التابع قبل أي تابع آخر ضمن الصنف Mosaic
 * سينتهي البرنامج عندما يغلق المستخدم النافذة
 * 
 * ‫الشرط المسبق: المعاملات rows و cols و h و w هي أعداد صحيحة موجبة
 *
 * ‫‫الشرط اللاحق: تفتح نافذة على الشاشة والتي يمكنها عرض صفوف وأعمدة
 * ‫من المستطيلات الملونة بحيث يكون عرض المستطيل يساوي w وطوله يساوي h
 * ‫كما أن عدد الصفوف هو قيمة المعامل الأول الممررة بينما عدد الأعمدة
 * هو قيمة المعامل الثاني. مبدئيًا، تكون جميع المستطيلات سوداء
 *
 * ‫ملحوظة: الصفوف مرقمة من 0 وحتى rows - 1 بينما الأعمدة مرقمة 
 * ‫من 0 وحتى cols - 1 
 */</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> open</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> rows</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> cols</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> h</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> w</span><span class="pun">)</span><span class="pln">


    </span><span class="com">/**
     * ضبط لون أحد مربعات النافذة
     * 
     * ‫الشرط المسبق: لابد أن كون المعاملين row و col ضمن النطاق المسموح
     * ‫به لرقمي الصف والعمود، كما لابد أن تقع كلا من المعاملات r و g و b ‫بين العددين 0 و 255
     * الشرط اللاحق: سيضبط لون المربع المخصص عن طريق رقمي الصف والعمود
     * الممررين إلى اللون المحدد عبر المعاملات الثلاثة‫ r و g و b
     * بحيث تعطي هذه المعاملات قيم اللون الأحمر والأخضر والأخضر
     * بنظام‫ RGB للمربع، قمثلًا يعطي المعامل r قيمة اللون الأحمر بحيث
     * تشير القيمة 0 إلى انعدام اللون الأحمر بينما تشير القيمة 255 إلى أكبر قدر ممكن من اللون
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> setColor</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> row</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> col</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> r</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> g</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> b</span><span class="pun">)</span><span class="pln">


    </span><span class="com">/**
     * ‫جلب قيمة اللون الأحمر بنظام RGB لأحد المربعات
     * 
     * ‫الشرط المسبق: لابد أن يقع كُلا من المعاملين row و col ضمن النطاق المسموح به
     * ‫الشرط اللاحق: إعادة قيمة اللون الأحمر بنظام RGB للمربع المخصص
     * ‫كعدد صحيح يقع بين العددين 0 و 255
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> getRed</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> row</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> col</span><span class="pun">)</span><span class="pln">


    </span><span class="com">/**
     * ‫تعمل بنفس طريقة الدالة  getRed
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> getGreen</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> row</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> col</span><span class="pun">)</span><span class="pln">


    </span><span class="com">/**
     * ‫تعمل بنفس طريقة الدالة  getRed
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> getBlue</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> row</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> col</span><span class="pun">)</span><span class="pln">


    </span><span class="com">/**
     * لإبطاء تنفيذ البرنامج عبر الانتظار قليلًا 
     * 
     * الشرط المسبق: لابد أن يكون المعامل‫ milliseconds عددا موجبا
     * ‫الشرط اللاحق: سيتوقف البرنامج مؤقتًا لمدة تساوي الزمن الممرر
     * بوحدة المللي ثانية
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> delay</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> milliseconds</span><span class="pun">)</span></pre>

<p>
	تَذَكَّر أن البرامج الفرعية -بالأعلى- هي أعضاء (members) ضِمْن الصَنْف <code>Mosaic</code>، ولهذا ينبغي أن تَتضمَّن أسماء تلك البرامج (routine) اسم الصَنْف ذاته عند اِستدعائها بمكان يَقَع خارج الصنف <code>Mosaic</code>. على سبيل المثال، اِستخدِم الاسم <code>Mosaic.isOpen()‎</code> بدلًا من الاسم <code>isOpen</code>.
</p>

<p>
	لا تُحدِّد تعليقات البرامج الفرعية -بالأعلى- ما سيَحدُث في حالة عدم استيفاء شروطها المُسَبَّقة (preconditions). على الرغم من أن البرامج الفرعية (subroutine)، في العموم، غير مُلزَمة فعليًا بما هو مَكْتوب ضِمْن مواصفاتها الاصطلاحية (contract)، فسيَكُون من الجيد مَعرِفة ما سيَحدُث في مثل تلك الحالات. على سبيل المثال، يُبلِّغ البرنامجين الفرعيين <code>setColor()‎</code> أو <code>getRed()‎</code> عن حُدوث اعتراض من النوع <code>IllegalArgumentException</code> في حالة عدم استيفاء شَّرْطهما المُسَبَّق: "ضرورة وقوع كلًا من <code>row</code> و <code>col</code> ضِمْن النِطاق المَسموح به لرَقمي الصف والعمود على الترتيب." تَسمَح مَعرِفتك لمثل تلك الحقيقة بكتابة برامج يُمكِنها التقاط (catch) ذلك الاعتراض (exception)، ومُعالجته، ولهذا سيَكُون من المفيد تَوْثيق (document) تلك المعلومة من خلال إضافة الوَسْم التوثيقي (doc tag)‏ <code>‎@throws‎</code> إلى تعليق <code>Javadoc</code>. تَتَبقَّى أسئلة آخرى عديدة تَتَعلَّق بكيفية تَصرُّف البرنامج الفرعي ضِمْن حالات معينة. على سبيل المثال، ماذا سيَحدُث إذا استدعينا البرنامج الفرعي <code>Mosaic.open()‎</code> بينما هنالك نافذة مفتوحة بالفعل على الشاشة؟ في تلك الحالة، سيتجاهل البرنامج الفرعي عملية الاستدعاء الثانية. في الواقع، يَصعُب عادة إعداد تَوْثيق كامل على تلك الشاكلة، وأحيانًا ستحتاج إلى مُجرَّد تجربة حالة معينة لترى بنفسك كيفية تَصرُّفها، أو قد تَضطرّ أحيانًا للإطلاع على كامل الشيفرة المصدرية (source code) في حالة تَوفُّرها.
</p>

<p>
	تَتلخَّص فكرة البرنامج الذي سنقوم بتَطويره بكتابة تحريكة (animation) تَعتمِد على الصنف <code>Mosaic</code>. ببساطة، سنَملْئ نافذة بمربعات مُلوَّنة عشوائيًا، وبعدها، سنُغيِّر تلك الألوان عشوائيًا ضِمْن حَلْقة تَكْرار (loop) تستمر طالما كانت النافذة مفتوحة. قد تَعنِي عبارة "تَغْيِير الألوان عشوائيًا" الكثير من الأشياء المختلفة. المقصود هنا هو إِحداث ما يُشبِه "تشويش (disturbance)" يتحرك عبر النافذة، بحيث يُغيِّر ذلك التشويش من لون أيّ مربع يُواجهه. تُوضِح الصورة التالية ما قد تبدو عليه النافذة بلحظة معينة:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="54337" data-unique="7dj22r2oa" src="https://academy.hsoub.com/uploads/monthly_2020_12/001Mosaic_Window.png.27bbb47dffcb8459b6c1b1c531004229.png" alt="001Mosaic_Window.png"></p>

<p>
	مع اعتمادنا على البرامج الفرعية (routines) ضِمْن الصنف <code>Mosaic</code>، نستطيع كتابة التَصوُّر المَبدئي للبرنامج كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_9" style="">
<span class="com">// ‫افتح نافذة Mosaic</span><span class="pln">
</span><span class="typ">Open</span><span class="pln"> a </span><span class="typ">Mosaic</span><span class="pln"> window
</span><span class="com">// اِملئ النافذة بألوان عشوائية</span><span class="pln">
</span><span class="typ">Fill</span><span class="pln"> window with random colors
</span><span class="com">// تجول وغير لون المربعات عشوائيًا</span><span class="pln">
</span><span class="typ">Move</span><span class="pln"> around</span><span class="pun">,</span><span class="pln"> changing squares at random</span></pre>

<p>
	تبدو الخطوة "اِملئ النافذة بألوان عشوائية" كمُهِمّة (task) مُترابطة يُمكِن فصلها بصورة مستقلة، ولهذا سنَكتُب برنامجًا فرعيًا (subroutine) يَتولَى مسئولية تَّنْفيذ تلك المُهِمّة. في المقابل، يُمكِن إضافة مزيد من التفاصيل للخطوة الثالثة بحيث تُكتَب على عدة خطوات: اِبدأ من منتصف النافذة، ثُمَّ اِستمر بالتحرك إلى مربعات جديدة، وغَيّر لون تلك المربعات. ينبغي الاستمرار بتَّنْفيذ تلك الخطوات طالما كانت النافذة مفتوحة. يُمكِننا إعادة كتابة الخوارزمية (algorithm) لتُصبِح كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_11" style="">
<span class="com">// ‫افتح نافذة Mosaic</span><span class="pln">
</span><span class="typ">Open</span><span class="pln"> a </span><span class="typ">Mosaic</span><span class="pln"> window
</span><span class="com">// اِملئ النافذة بألوان عشوائية</span><span class="pln">
</span><span class="typ">Fill</span><span class="pln"> window with random colors
</span><span class="com">// اضبط المَوضع الحالي إلى المربع بمنتصف النافذة</span><span class="pln">
</span><span class="typ">Set</span><span class="pln"> the current position to the middle square in the window
</span><span class="com">// طالما كانت النافذة مفتوحة</span><span class="pln">
</span><span class="typ">As</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> as the mosaic window is open</span><span class="pun">:</span><span class="pln">
   </span><span class="com">// غير لون المربع بالمَوضع الحالي عشوائيًا</span><span class="pln">
   </span><span class="typ">Randomly</span><span class="pln"> change color of the square at the current position
   </span><span class="com">// حرك الموضع الحالي لأعلى أو لأسفل أو لليسار أو لليمين عشوائيًا</span><span class="pln">
   </span><span class="typ">Move</span><span class="pln"> current position up</span><span class="pun">,</span><span class="pln"> down</span><span class="pun">,</span><span class="pln"> left</span><span class="pun">,</span><span class="pln"> or right</span><span class="pun">,</span><span class="pln"> at random</span></pre>

<p>
	سنَستخدِم مُتَغيِّرين من النوع الصحيح <code>int</code> هما <code>currentRow</code> و <code>currentColumn</code>؛ لتَمثيِل "المَوْضِع الحالي (current position)"، سيَحمِلان رقمي الصف (row number) والعمود (column number) للمربع الحالي الذي يُطبَق عليه التشويش (disturbance). لما كانت نافذة <code>mosaic</code> مُكوَّنة من ١٦ صف و ٢٠ عمود من المربعات، يُمكِننا تهيئة قيمة "المَوضِع الحالي" المَبدئية إلى منتصف النافذة عن طريق ضَبْط المُتَغيِّرين <code>currentRow</code> و <code>currentColumn</code> إلى القيمتين ٨ و ١٠ على الترتيب. سنَلجأ لاستخدام البرنامج الفرعي <code>Mosaic.open()‎</code> لفَتْح النافذة، كما سنَكتُب برنامجين فرعيين (subroutines) إضافيين لإِنجاز مُهِمّتين ضِمْن حَلْقة التَكْرار <code>while</code> بحيث يَظلّ البرنامج <code>main()‎</code> بسيطًا. نستطيع الآن تَحْوِيل الخوارزمية (algorithm) إلى الشيفرة التالية بلغة الجافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_13" style="">
<span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="lit">16</span><span class="pun">,</span><span class="lit">20</span><span class="pun">,</span><span class="lit">25</span><span class="pun">,</span><span class="lit">25</span><span class="pun">)</span><span class="pln">
fillWithRandomColors</span><span class="pun">();</span><span class="pln">
currentRow </span><span class="pun">=</span><span class="pln"> </span><span class="lit">8</span><span class="pun">;</span><span class="pln">       </span><span class="com">// الصف الواقع بمنتصف النافذة</span><span class="pln">
currentColumn </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">   </span><span class="com">// العمود الواقع بمنتصف النافذة</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ينتهي البرنامج عند غلق النافذة</span><span class="pln">
    changeToRandomColor</span><span class="pun">(</span><span class="pln">currentRow</span><span class="pun">,</span><span class="pln"> currentColumn</span><span class="pun">);</span><span class="pln">
    randomMove</span><span class="pun">();</span><span class="pln">      
</span><span class="pun">}</span></pre>

<p>
	سنُجرِي أيضًا تَعْديلًا إضافيًا، وهو إِبطاء التحريكة (animation) قليلًا، ولذلك سنُضِيف السطر <code>Mosaic.delay(10);‎</code> إلى حَلْقة التَكْرار <code>while</code>.
</p>

<p>
	انتهينا الآن من إِعداد البرنامج <code>main()‎</code>، لكننا نَحتاج لكتابة البرامج الفرعية <code>fillWithRandomColors()‎</code> و <code>changeToRandomColor(int,int)‎</code> و <code>randomMove()‎</code> لنُكمِل البرنامج. تُعدّ عملية كتابة كل برنامج منها بمَثابة مُهِمّة صغيرة مُنفصلة. سنبدأ بالبرنامج الفرعي <code>fillWithRandomColors()‎</code> والمَسئول عن ضمان تَحقُّق الشَّرْط اللاحق (postcondition) التالي: "سيَتغيَّر لون كل مربع بالنافذة عشوائيًا." يُمكِننا كتابة خوارزمية (algorithm) لإِنجاز تلك المُهِمّة بأسلوب الشيفرة الوهمية (pseudocode) كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_15" style="">
<span class="com">// لكل صف</span><span class="pln">
</span><span class="typ">For</span><span class="pln"> each row</span><span class="pun">:</span><span class="pln">
   </span><span class="com">// لكل عمود</span><span class="pln">
   </span><span class="typ">For</span><span class="pln"> each column</span><span class="pun">:</span><span class="pln">
         </span><span class="com">// غير لون المربع بذلك الصف والعمود إلى لون عشوائي</span><span class="pln">
      </span><span class="typ">set</span><span class="pln"> the square in that row and column to a random color</span></pre>

<p>
	يُمكِن تَّنْفيذ (implement) السَطْرين "لكل صف"، و"لكل عمود" -بالأعلى- باِستخدَام حَلْقة التَكْرار <code>for</code>. أما بخصُوص السطر الأخير، فلقد قَررنا بالفعل كتابة البرنامج الفرعي <code>changeToRandomColor(int,int)‎</code> المَسئول عن ضَبْط اللون. لاحِظ أن إِمكانية إعادة اِستخدَام برنامج فرعي معين بعدة مَواضِع يُعدّ أحد أهم مَكاسِب اِستخدَام البرامج الفرعية. يُمكِننا الآن كتابة البرنامج الفرعي <code>fillWithRandomColors()‎</code> بلغة الجافا كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_17" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> fillWithRandomColors</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> row</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> row </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> row </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">16</span><span class="pun">;</span><span class="pln"> row</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> column </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> column </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln"> column</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
            changeToRandomColor</span><span class="pun">(</span><span class="pln">row</span><span class="pun">,</span><span class="pln">column</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سننتقل الآن إلى البرنامج الفرعي التالي <code>changeToRandomColor(int,int)‎</code>. يُوفِّر الصَنْف <code>Mosaic</code> بالفعل التابع (method)‏ <code>Mosaic.setColor()‎</code>، والمُستخدَم لتَغْيِير لون المربع.لمّا كنا نُريد لونًا عشوائيًا، فسنحتاج إلى اختيار قيم عشوائية لكل من <code>r</code> و <code>g</code> و <code>b</code>، والتي ينبغي أن تَكُون أعدادًا صحيحة (integers) مُتراوحة بين العددين ٠ و ٢٥٥، وفقًا للشَّرْط المُسَبَّق (precondition) للبرنامج الفرعي <code>Mosaic.setColor()‎</code>، ولهذا سنَستخدِم المُعادلة <code>(int)(256*Math.random()‎)</code> لاختيار مثل تلك الأعداد. بالتالي، يُمكِننا كتابة البرنامج الفرعي المُستخدَم لتَغْيِير اللون عشوائيًا كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_19" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> changeToRandomColor</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> rowNum</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> colNum</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> red </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> green </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">  
    </span><span class="typ">int</span><span class="pln"> blue </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
    </span><span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">setColor</span><span class="pun">(</span><span class="pln">rowNum</span><span class="pun">,</span><span class="pln">colNum</span><span class="pun">,</span><span class="pln">red</span><span class="pun">,</span><span class="pln">green</span><span class="pun">,</span><span class="pln">blue</span><span class="pun">);</span><span class="pln">  
</span><span class="pun">}</span></pre>

<p>
	وأخيرًا، يُمكِننا الانتقال إلى البرنامج الفرعي <code>randomMove()‎</code>، والمَسئول عن تحريك التشويش (disturbance) عشوائيًا، لأعلى، أو لأسفل، أو يسارًا، أو يمينًا. سنَستخدِم عددًا عشوائيًا يَتراوح بين القيمتين ٠ و ٣؛ لإجراء الاختيار ما بين الاتجاهات الأربعة، فمثلًا، عندما تَكُون قيمة العدد مُساوِية للصفر، سيَتحرَك التشويش باتجاه معين، أما إذا كانت قيمته مُساوِية للواحد، فسيَتحرَك باتجاه آخر، وهكذا. لمّا كنا نَستخدِم المُتَغيِّرين <code>currentRow</code> و <code>currentColumn</code> لتحديد المَوضِع الحالي للتشويش، فإن تحريك ذلك المَوضِع لأعلى يَعنِي بالضرورة إِنقاص قيمة المُتَغيِّر <code>currentRow</code> بمقدار الواحد. يَترك ذلك استفهامًا عما يُفْترَض حُدوثه عندما يَصِل المُتَغيِّر <code>currentRow</code> إلى القيمة -١؛ خُصوصًا وأن ذلك سيَتَسبَّب بإخفاء التشويش خارج النافذة، وهو ما سينتهك الشَّرْط المُسَبَّق (precondition) لكثير من البرامج الفرعية ضِمْن الصنف <code>Mosaic</code>، ولهذا سنُحرِك التشويش إلى الحافة المُضادة من النافذة من خلال ضَبْط قيمة المُتَغيِّر <code>currentRow</code> إلى ١٥ (تَذَكَّر أن النافذة مُكوَّنة من ١٦ صف مُرقَّمَين من ٠ وحتى ١٥). بدلًا من القفز إلى الحافة الآخرى، نستطيع أيضًا تَجاهُل تلك الحالة. يُمكِننا معالجة تحريك التشويش (disturbance) للاتجاهات الثلاثة الأخرى بنفس الطريقة، بحيث نستعين بتَعْليمَة <code>switch</code> لتَحْديد الاتجاه ذاته. اُنظر شيفرة البرنامج الفرعي <code>randomMove()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_21" style="">
<span class="typ">int</span><span class="pln"> directionNum</span><span class="pun">;</span><span class="pln">
directionNum </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">4</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
</span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">directionNum</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">  </span><span class="com">// تحرك لأعلى</span><span class="pln">
        currentRow</span><span class="pun">--;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentRow </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">   </span><span class="com">// إذا أصبح الموضع الحالي خارج النافذة</span><span class="pln">
            currentRow </span><span class="pun">=</span><span class="pln"> </span><span class="lit">15</span><span class="pun">;</span><span class="pln">   </span><span class="com">// قم بتحريكه للحافة المضادة</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">  </span><span class="com">// تحرك لليمين</span><span class="pln">
        currentColumn</span><span class="pun">++;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentColumn </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln">
            currentColumn </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln"> 
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">  </span><span class="com">// تحرك لأسفل</span><span class="pln">
        currentRow</span><span class="pun">++;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentRow </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">16</span><span class="pun">)</span><span class="pln">
            currentRow </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">  </span><span class="com">// تحرك لليسار</span><span class="pln">
        currentColumn</span><span class="pun">--;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentColumn </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
            currentColumn </span><span class="pun">=</span><span class="pln"> </span><span class="lit">19</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln"> 
</span><span class="pun">}</span></pre>

<h2>
	البرنامج
</h2>

<p>
	انتهينا الآن من كتابة جميع البرامج الفرعية، وتَبقَّى لنا تَجْميعها معًا بحيث نَحصُل على البرنامج كاملًا، بالإضافة إلى كتابة تعليقات <code>Javadoc</code> للصنف ذاته ولبرامجه الفرعية. لاحظ أننا قد عَرَّفنا المُتَغيِّرين <code>currentRow</code> و <code>currentColumn</code> كأعضاء ساكنة (static members) ضِمْن الصنف، وليس كمُتَغيِّرات محليّة (local)؛ وذلك لكَوْنهما مُستخدَمين ضِمْن أكثر من مُجرَّد برنامج فرعي (subroutines) واحد. تَتَوفَّر نسخة من الشيفرة المصدرية للبرنامج بالملف <code>RandomMosaicWalk.java</code>، وانتبه لكَوْنه يَعتمِد على كُلًا من الملفين <code>Mosaic.java</code> و <code>MosaicCanvas.java</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1512_23" style="">
<span class="com">/**
 * يفتح هذا البرنامج نافذة مليئة بالمربعات الملونة عشوائيًا
 * بحيث يتحرك نوع من "التشويش" عشوائيًا عبر الشاشة ويغير من 
 * لون أي مربع يواجهه بشكل عشوائي. يستمر البرنامج في العمل 
 * طالما كانت النافذة مفتوحة
 */</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">RandomMosaicWalk</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> currentRow</span><span class="pun">;</span><span class="pln">    </span><span class="com">// رقم الصف المعرض للتشويش</span><span class="pln">
    </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> currentColumn</span><span class="pun">;</span><span class="pln"> </span><span class="com">// رقم العمود المعرض للتشويش</span><span class="pln">

    </span><span class="com">/**
     * ‫يُنشيء برنامج main النافذة ويملؤها بألوان عشوائية
     * ثم يحرك التشويش بصورة عشوائية عبر النافذة طالما كانت مفتوحة
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="lit">16</span><span class="pun">,</span><span class="lit">20</span><span class="pun">,</span><span class="lit">25</span><span class="pun">,</span><span class="lit">25</span><span class="pun">);</span><span class="pln">
        fillWithRandomColors</span><span class="pun">();</span><span class="pln">
        currentRow </span><span class="pun">=</span><span class="pln"> </span><span class="lit">8</span><span class="pun">;</span><span class="pln">   </span><span class="com">// ابدأ بمنتصف النافذة</span><span class="pln">
        currentColumn </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            changeToRandomColor</span><span class="pun">(</span><span class="pln">currentRow</span><span class="pun">,</span><span class="pln"> currentColumn</span><span class="pun">);</span><span class="pln">
            randomMove</span><span class="pun">();</span><span class="pln">
            </span><span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">delay</span><span class="pun">(</span><span class="lit">10</span><span class="pun">);</span><span class="pln">  </span><span class="com">// احذف هذا السطر لزيادة سرعة التحريكة</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">  </span><span class="com">// نهاية main</span><span class="pln">

    </span><span class="com">/**
     * يملأ النافذة بمربعات ملونة عشوائيا
     *
     * الشرط المسبق: لابد أن تكون النافذة مفتوحة
     * الشرط اللاحق: سيصبح كل مربع النافذة ملون بصورة عشوائية
     */</span><span class="pln">
    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> fillWithRandomColors</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> row</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> row</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> row </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">16</span><span class="pun">;</span><span class="pln"> row</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> column </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln"> column</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                changeToRandomColor</span><span class="pun">(</span><span class="pln">row</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">);</span><span class="pln">  
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">  </span><span class="com">// نهاية fillWithRandomColors</span><span class="pln">

    </span><span class="com">/**
     * يغير من لون مربع معين بالنافذة عشوائيًا
     *
     * الشرط المسبق: لابد أن يقع رقمي الصف والعمود الممررين ضمن
     * النطاق المسموح به لأرقام الصف والعمود
     * الشرط اللاحق: سيتغير لون المربع المخصص بواسطة رقمي الصف والعمود
     *  
     * @param rowNum رقم الصف للمربع بحيث يبدأ عد الصفوف من الأعلى
     * @param colNum رقم الصف للمربع بحيث يبدأ عد الأعمدة من اليسار
     */</span><span class="pln">
    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> changeToRandomColor</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> rowNum</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> colNum</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// اختر قيم عشوائية تتراوح بين 0 و 255</span><span class="pln">
        </span><span class="com">// لقيم الألوان الثلاثة (الأحمر، والأزرق، والأخضر‫) ‫بنظام الألوان RGB</span><span class="pln">

        </span><span class="typ">int</span><span class="pln"> red </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">    
        </span><span class="typ">int</span><span class="pln"> green </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">  
        </span><span class="typ">int</span><span class="pln"> blue </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">256</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">   
        </span><span class="typ">Mosaic</span><span class="pun">.</span><span class="pln">setColor</span><span class="pun">(</span><span class="pln">rowNum</span><span class="pun">,</span><span class="pln">colNum</span><span class="pun">,</span><span class="pln">red</span><span class="pun">,</span><span class="pln">green</span><span class="pun">,</span><span class="pln">blue</span><span class="pun">);</span><span class="pln">  
    </span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية changeToRandomColor</span><span class="pln">

    </span><span class="com">/**
     * يحرك التشويش عبر النافذة
     * 
     * الشرط المسبق: لابد أن تكون المتغيرات العامة‫ currentRow و 
     * ‫currentColumn ضمن النطاق المسموح به لرقمي الصف والعمود
     * الشرط اللاحق: يتغير رقمي الصف والعمود إلى أحد المواضع المجاورة 
     * سواء للأعلى أو للأسفل أو لليسار أو لليمين
     */</span><span class="pln">
    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> randomMove</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> directionNum</span><span class="pun">;</span><span class="pln"> 

        directionNum </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">4</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
        </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">directionNum</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">  </span><span class="com">// move up </span><span class="pln">
                currentRow</span><span class="pun">--;</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentRow </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
                    currentRow </span><span class="pun">=</span><span class="pln"> </span><span class="lit">15</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">  </span><span class="com">// move right</span><span class="pln">
                currentColumn</span><span class="pun">++;</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentColumn </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln">
                    currentColumn </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln"> 
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">  </span><span class="com">// move down</span><span class="pln">
                currentRow </span><span class="pun">++;</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentRow </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">16</span><span class="pun">)</span><span class="pln">
                    currentRow </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">  </span><span class="com">// move left  </span><span class="pln">
                currentColumn</span><span class="pun">--;</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentColumn </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
                    currentColumn </span><span class="pun">=</span><span class="pln"> </span><span class="lit">19</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln"> 
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية randomMove</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف RandomMosaicWalk</span></pre>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c4/s7.html" rel="external nofollow">Section 7: More on Program Design</a> من فصل Chapter 4: Programming in the Large I: Subroutines من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1092</guid><pubDate>Mon, 14 Dec 2020 19:05:08 +0000</pubDate></item><item><title>&#x648;&#x627;&#x62C;&#x647;&#x629; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x627;&#x644;&#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x62D;&#x632;&#x645; &#x648;&#x627;&#x644;&#x648;&#x62D;&#x62F;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x62A;&#x648;&#x62B;&#x64A;&#x642; Javadoc &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%88%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D9%88%D8%AB%D9%8A%D9%82-javadoc-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1091/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_12/28.png.22d43c1cbfa431903ecdcd564ce9cc4c.png" /></p>

<p>
	كل تَطوُّر يَحدُث بواجهات المُستخدِم، يُقابله تَعقيد أكبر ينبغي على المبرمج التَعامُل معه، ففي حين تستطيع كتابة واجهة برنامج طرفية (console user interface) بواسطة عدد قليل من البرامج الفرعية (subroutines) البسيطة التي تقرأ ما يَكْتُبه المُستخدِم، وتَطبَع خَرْج البرنامج إلى الطرفية، فإن تطوير واجهات المُستخدِم الرسومية (graphical user interface) العصرية هو أمر أكثر تعقيدًا بمراحل عدة، خاصة مع كل هذا الكم الهائل من النوافذ، والأزرار، وشرائط التمرير، والقوائم، وصناديق الإِدْخَال النصية، وغيره، والتي أينعم تَمنَح المُستخدِم تجربة سهلة ومريحة، ولكنها في ذات الوقت تُجبر المبرمج على التَعامُل مع كمية هائلة من الاحتمالات والتعقيدات المتزايدة، والتي تَكُون بهيئة عدد ضخم من البرامج الفرعية المُخصَّصة فقط لأغراض إدارة واجهة المُستخدِم (user interface) ناهيك عن البرامج الفرعية الآخرى المُخصَّصة لغَيْر ذاك الغرض.
</p>

<h2>
	صناديق الأدوات (toolboxes)
</h2>

<p>
	اعتاد مبرمجي حاسوب ماكنتوش الأصلي (Macintosh) على التعامل مع "صندوق أدوات ماكنتوش (Macintosh Toolbox)"، والذي يَتكوَّن من أكثر من ألف برنامج فرعي (subroutines) مختلف؛ حيث تَتَوفَّر برامج لتَّنْفيذ جميع العمليات التي يُتوقَّع من الحاسوب القيام بها، فمثلًا، تَتَوفَّر تلك البرامج المُتعلقة بواجهة المُستخدِم (user interface) مثل فَتْح النوافذ (windows) وإِغلاقها، ورَسْم كُلًا من الأشكال الهندسية (geometric) والنصوص على تلك النوافذ، وإضافة الأزرار إليها، والاستجابة إلى ضغطات الفأرة على تلك النوافذ، وإضافة القوائم (menus)، والاستجابة لما يَختاره المُستخدِم منها. إلى جانب برامج واجهة المُستخدِم، تَتَوفَّر أيضًا برامج لفَتْح الملفات، وقراءة البيانات منها، وكذلك للاتصال الشبكي، ولإرسال الخَرْج إلى الطابعة، ولمُعالجة الاتصال بين البرامج. في المُقابل، يُوفِّر مايكروسوفت ويندوز (Microsoft Windows) مجموعة آخرى من البرامج الفرعية (subroutines) للمبرمجين، والتي تَختلِف نوعًا ما عن تلك المُستخدَمة بماكنتوش (Macintosh). علاوة على ذلك، يُوفِّر لينكس (Linux) للمبرمجين أكثر من صندوق أدوات لبرمجة واجهات المُستخدِم الرسومية (GUI toolboxes) يُمكِنهم الاختيار بينها.
</p>

<p>
	أيّ مشروع برمجي هو بالنهاية خليط من كُلًا من الابتكار وإعادة الاِستخدَام. يبدأ المبرمج بمجموعة الأدوات البسيطة المَبْنِيَّة باللغة نفسها، كالمتغيرات، وتَعْليمَات الإِسْناد (assignment statements)، وتَعْليمَات التَفْرِيع <code>if</code>، وحَلْقات التَكْرار (loops). إلى جانب ذلك، فإنه قد يَستعِين بصناديق أدوات (toolboxes)، مَكْتوبة من قِبَل مُطوِّرين آخرين، والتي تَتضمَّن مجموعة من البرامج (routines) لتَّنْفيذ مَهَامّ معينة يَحتاجها المبرمج. إذا كانت تلك الأدوات مُصمَّمة تَصْمِيمًا جيدًا، فإنها تَكُون أَشْبه بصندوق أسود (black boxes)، لا يحتاج المبرمج أكثر من مُجرَّد استدعائها، دون مَعرِفة أية تفاصيل أو خطوات تُنفِّذها تلك الأداة لإنجاز المُهِمّة المُسنَدة إليها. كُل ما سبق يصُنَّف ضِمْن ذلك الجزء الخاص بإعادة الاِستخدَام، أما الجزء الآخر المُتَعلِّق بالابتكار، فيَتكوَّن من توظيف كل تلك الأدوات السابق ذِكرَها ضِمْن مشروع معين بهدف حل مشكلة معينة كمُعالجة النصوص، أو الاحتفاظ بالحسابات البنكية، أو مُعالجة الصور المُلتقَطة بواسطة مسبار فضاء، أو ألعاب الكمبيوتر، أو تَصفُّح الإنترنت، ..إلخ. يُطلَق على ذلك برمجة التطبيقات (applications programming).
</p>

<p>
	صندوق الأدوات البرمجي (software toolbox) هو أَشْبه ما يَكُون بصندوق أسود، لابُدّ أن يَكُون مَصحُوبًا بواجهة (interface)، والتي تَتَكوَّن من توصيف لجميع البرامج (routines) المُعرَّفة بداخله، أيّ ذِكْر مُعامِلات (parameters) كل برنامج، والغرض منه. تُكوِّن تلك التوصيفات ما يُعرَف باسم واجهة برمجة التطبيقات (Application Programming Interface)، وتُختصَر إلى <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>، فمثلًا، تَحتوِي واجهة برمجة تطبيقات ماكنتوش (Macintosh <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) على تَوصِيف لجميع البرامج (routines) المُتاحة "بصندوق أدوات ماكنتوش (Macintosh Toolbox)". عادةً ما تُصدر الشركات المُصنعة للأجهزة العتادية (hardware device) -مثل بطاقات الشبكة (network cards) المسئولة عن توصيل الحاسوب بشبكة معينة- واجهة برمجة تطبيقات (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) خاصة بذلك الجهاز، تَحتوِي على قائمة بالبرامج (routines) التي يُمكِن للمبرمجين استدعائها؛ للاتصال مع الجهاز والتَحكُّم به. علاوة على ذلك، يُوفِّر العلماء المُساهمين بكتابة البرامج المسئولة عن حِسَاب بعض العمليات المُعقدة نوعًا ما -مثل حلّ المعادلات التفاضلية (differential equations)- واجهة برمجة تطبيقات (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>)، تَسمَح للآخرين باستدعاء تلك البرامج (routines) دون الحاجة إلى فهم تفاصيل تلك العمليات.
</p>

<p>
	لغة الجافا مُدعَّمة بواجهة برمجة التطبيقات القياسية (standard <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>)، والتي تَعرَّضنا لأجزاء منها بالفعل، مثل البرنامج الفرعي الرياضي <code>Math.sqrt()‎</code>، والصَنْف <code>String</code>، وما يَحتوِيه من برامج (routines)، بالإضافة إلى برامج طباعة الخَرْج <code>System.out.print()‎</code>. تَتضمَّن أيضًا تلك الواجهة برامج (routines) لبرمجة واجهات المُستخدِم الرسومية (graphical user interfaces)، وللاتصالات الشبكية (network communication)، ولقراءة الملفات وكتابتها، وغيرها. يَظُنّ البعض أن تلك البرامج (routines) هي جزء من لغة الجافا ذاتها، ولكنها في الواقع مُجرَّد برامج فرعية (subroutines) قد كُتبت وأُتيحت للاِستخدَام ببرامج (programs) الجافا.
</p>

<p>
	ينبغي لأيّ واجهة برمجة تطبيقات جافا (Java <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) العَمَل على جميع المنصات، وعندها يُعدّ برنامج (program) الجافا المَكْتوب وفقًا لتلك الواجهة مُستقلًا عن أيّ منصة (platform-independent)، أيّ أنه من المُمكِن تَشْغِيل نفس البرنامج (program) على منصات (platform) مُتعدِّدة، مثل ويندوز (Windows)، وماك (Mac OS)، ولينكس (Linux) وغيرها. ومع ذلك، لاحِظ أن الواجهة (interface) ذاتها هي التي تُعدّ مُستقلة عن المنصات (platform-independent)، أما تَّنْفيذ (implementation) تلك الواجهة فإنه قد يختلف من منصة لآخرى. فيما يتعلق بواجهة برمجة التطبيقات القياسية (standard <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>)، يَتضمَّن نظام الجافا (Java system) بأي حاسوب عمومًا تَّنْفيذًا (implementations) لجميع البرامج الموجودة بتلك الواجهة. عندما يَستدعِي برنامج جافا (Java program) واحدة من تلك البرامج القياسية (standard routines) ضِمْن الواجهة القياسية، فإن مُفسِّر الجافا (Java interpreter) -عند تَّنْفيذه للبرنامج (program)- يَسحَب تَّنْفيذ البرنامج المُستدعَى (routine implementation) المُتناسب مع المنصة (platform) الحالية، ثم يُنفِّذه. يَعنِي ذلك أنه بمُجرَّد تَعلُّمك لواجهة برمجة تطبيقات (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) واحدة، سيُصبِح بإمكانك استهداف مجموعة واسعة من المنصات، وهو ما يُعدّ ميزة قوية جدًا.
</p>

<h2>
	حزم الجافا القياسية (standard packages)
</h2>

<p>
	تُكتَب البرامج (routines) بواجهة برمجة التطبيقات القياسية (standard <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) داخل أصناف (classes) كما هو الحال مع أي برنامج فرعي (subroutine). بالإضافة إلى ذلك، فإنه من المُمكِن تَجْميع الأصناف ضِمْن حزم (packages)، والتي تَعرَّضنا لها باختصار بالقسم الفرعي ٢.٦.٧؛ بهدف تنظيمها على نطاق أوسع (large-scale). يُمكِن أيضًا تَضْمِين الحزم (packages) داخل حزم آخرى لتحقيق مُستوى أعلى من التَجْميع. في الواقع، واجهة برمجة تطبيقات جافا القياسية (standard Java <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) مُنفَّذة (implement) بالكامل ضِمْن عدة حزم، فمثلًا، تَحتوِي حزمة <code>java</code> على عدة حزم آخرى غَيْر مُتَعلِّقة بواجهة المُستخدِم الرسومية (non-GUI)، بالإضافة إلى احتوائها على أصناف <code>AWT</code> المُتَعَلِّقة بتلك الواجهات الرسومية. حزمة <code>javax</code> هي مثال آخر، وتَحتوِي على أصناف كثيرة، من ضِمْنها تلك الأصناف التي تَستخدِمها واجهة المُستخدِم الرسومية (GUI)‏ <code>Swing</code>. كذلك حزمة <code>javafx</code> والتي تَحتوِي على واجهة برمجة تطبيقات جافا إف إكس (JavaFX <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) التي يَستخدِمها الكتاب لبرمجة واجهات المُستخدِم الرسومية (GUI)‏.
</p>

<p>
	قد تَحتوِي أي حزمة (package) على أصناف أو حزم آخرى، وتُسمَى تلك الأخيرة باسم الحزم الفرعية (sub-package). تَتضمَّن كُلًا من الحزمتين <code>java</code> و <code>javafx</code> على حزم فرعية (sub-packages). فمثلًا، تَحتوِي الحزمة الفرعية <code>util</code> على تشكيلة من الأصناف، بما في ذلك الصَنْف <code>Scanner</code> الذي ناقشناه بالقسم الفرعي ٢.٤.٦، وهي في الواقع مُتضمَّنة داخل حزمة <code>java</code>، ولذا يَكُون اسمها الكامل هو <code>java.util</code>. مثال آخر هو الحزمة الفرعية <code>java.io</code>، والتي تُسهِل من عمليات الخَرْج والدَخْل (input/output). كذلك الحزمة الفرعية <code>java.net</code>، والتي تتعامل مع الاتصالات الشبكية. أخيرًا الحزمة الفرعية الأكثر بساطة <code>java.lang</code>، والتي تَحتوِي على الأصناف الأساسية مثل <code>String</code> و <code>Math</code> و <code>Integer</code> و <code>Double</code>.
</p>

<p>
	اُنظر الصورة التالية والتي تَتضمَّن تمثيلًا رسوميًا (graphical representation) لمُستويات التَدَاخُل (nesting levels) بحزمة <code>java</code>، بما في ذلك حزمها الفرعية (sub-packages)، والأصناف الموجودة ضِمْن تلك الحزم الفرعية، بالإضافة إلى البرامج الفرعية (subroutines) الموجودة ضِمْن تلك الأصناف. لاحِظ أن هذا التمثيل الرسومي غَيْر كامل، فهو يَعرِض فقط عددًا قليلًا جدًا من العناصر الكثيرة الموجودة بكل عنصر.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="54503" data-unique="4eye1cy1d" src="https://academy.hsoub.com/uploads/monthly_2020_12/001Package_Class_Subroutine.png.584c329a744102a90a7743be2377f6fd.png" alt="001Package_Class_Subroutine.png">]
</p>

<p>
	بالمثل، تَحتوِي حزمة <code>javafx</code> على الحزمة الفرعية <code>javafx.scene</code>، والتي تَحتوِي بدورها على كُلًا من الحزمتين الفرعيتين <code>javafx.scene.control</code> و <code>javafx.scene.paint</code>. تَحتوِي أولاهما على أصناف (classes) لتمثيل مُكوِّنات واجهة المُستخدِم الرسومية (GUI components)، كالأزرار (buttons)، وصناديق الإِدْخال (input boxes)، بينما تَحتوِي الآخرى على الصَنْف <code>Color</code>، وأصناف آخرى لأغراض مَلْئ الأشكال (filling) وتَحْدِيد حوافها (stroking).
</p>

<p>
	تَتضمَّن واجهة برمجة تطبيقات جافا القياسية (standard Java <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) آلافًا من الأصناف مُجمَّعة ضِمْن مئات من الحزم. الكثير من تلك الأصناف هو، في الواقع، مُتخصِّص للغاية أو غَيْر مَعْروف، لذا لا داعي للإلمام بكامل واجهة برمجة تطبيقات جافا (Java <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>)، ولا حتى غالبيتها، فحتى خبراء المبرمجين ليسوا على دِرَايَة بكامل الواجهة. ستُواجه عشرات الأصناف (classes) أثناء دراستك لهذا الكتاب، وستَجِدْ أنهم كافيين تمامًا لكتابة تشكيلة واسعة من البرامج (programs). مع ذلك، يُمكِنك تَصفُّح <a href="https://docs.oracle.com/javase/8/docs/api/" rel="external nofollow">توثيق واجهة برمجة التطبيقات (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) للإصدار ٨ من الجافا</a> بالإضافة إلى <a href="https://docs.oracle.com/javase/8/javafx/api/toc.htm" rel="external nofollow">توثيق واجهة برمجة تطبيقات جافا إف إكس (JavaFX)</a> للإطلاع على ما هو مُتاح عمومًا.
</p>

<p>
	يُناقِش القسم الفرعي "الوحدات (modules)" بالأسفل بعضًا من التَغْيِيرات التي طرأت بالإصدار ٩ من الجافا، كما ستَجِدْ روابط تَوْثيق (documentation) الإصدار ١١ من الجافا. لكن لاحِظ أن تَوْثيق الإصدار ٨ يُعدّ أكثر سهولة في الاِستخدَام فيما يَتعلَّق بدراسة هذا الكتاب.
</p>

<h2>
	استخدام الأصناف ضمن الحزم
</h2>

<p>
	تَتضمَّن الحزمة <code>javafx.scene.paint</code> الصَنْف <code>Color</code>، لذا فإن الاسم الكامل للصنف هو <code>javafx.scene.paint.Color</code>. ذلك الصَنْف، وكأي صنف، هو بالنهاية نوع، أيّ أنك تستطيع اِستخدَامه للتَّصْريح (declare) عن كلًا من المُتَغيِّرات، والمُعامِلات (parameters)، وكذلك لتَخْصيص نوع القيمة المعادة (return type) من دالة (function). إذا أردت اِستخدَام ذلك الصَنْف ضِمْن أحد البرامج (program) التي تقوم بكتابتها، فإن أحد الطرائق للقيام بذلك هو استخدام الاسم الكامل للصَنْف كاسم للنوع. مثلًا، إذا كنت تريد التَّصْريح عن مُتَغيِّر اسمه <code>rectColor</code> من النوع <code>Color</code>، تستطيع كتابة التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_8" style="">
<span class="pln">javafx</span><span class="pun">.</span><span class="pln">scene</span><span class="pun">.</span><span class="pln">paint</span><span class="pun">.</span><span class="typ">Color</span><span class="pln">  rectColor</span><span class="pun">;</span></pre>

<p>
	تُمثِل الشيفرة بالأعلى مُجرَّد تَّصْريح (declaration) عن مُتَغيِّر عادي على الصياغة <strong>‎<type-name><variable-name>;‎</variable-name></type-name></strong>. مع ذلك، فإن اِستخدَام الاسم الكامل للصَنْف هو حتمًا أمر مُتعب، وفي الواقع، نادرًا ما ستَجِدْ تلك الأسماء الكاملة مُستخدَمة بأيّ برنامج (program)؛ حيث تَسمَح الجافا بتَجَنُّب اِستخدَام الاسم الكامل للصَنْف، وفي المقابل، ستحتاج إلى اِستيراد (importing) ذلك الصَنْف أولًا. يُمكِنك استيراد الصَنْف بإضافة السَطْر التالي إلى بداية ملف الشيفرة المصدرية (source code):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_10" style="">
<span class="kwd">import</span><span class="pln"> javafx</span><span class="pun">.</span><span class="pln">scene</span><span class="pun">.</span><span class="pln">paint</span><span class="pun">.</span><span class="typ">Color</span><span class="pun">;</span></pre>

<p>
	بذلك، تستطيع ببقية ذلك الملف كتابة الاسم البسيط (simple name) للصَنْف، أيّ <code>Color</code>، بدلًا من الاسم الكامل <code>javafx.scene.paint.Color</code>. لابُدّ أن يُكتَب سَطْر الاستيراد <code>import</code> ببداية الملف (بعد تَعْليمَة <code>package</code> في حالة وجودها)، وبحيث لا يَقَع سَطْر الاستيراد <code>import</code> ضِمْن أيّ صَنْف (class) مُعرَّف داخل الملف. يُسمِى البعض سَطْر الاستيراد <code>import</code> -بالأعلى- أحيانًا باسم التَعْليمَة (statement)، ولكن من الأنسب تَسميته بالمُوجِّه (directive)‏ <code>import</code>؛ لأنه ليس تَعْليمَة بالمعنى المُعتاد. والآن، سَمَح لك المُوجِّه <code>import javafx.scene.paint.Color</code> بكتابة التالي للتَّصْريح عن مُتَغيِّر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_12" style="">
<span class="typ">Color</span><span class="pln">  rectColor</span><span class="pun">;</span></pre>

<p>
	يَقْتصِر دور المُوجِّه (directive)‏ <code>import</code> على السماح باِستخدَام الأسماء البسيطة للأصناف بدلًا من أسمائها الكاملة <strong><package>.<class></class></package></strong>، أي أنه لا يَستوِرد أي شيء فعليّ، فأنت ما زلت تستطيع الوصول إلى الصَنْف (class) بدون اِستخدَام ذلك المُوجِّه، فقط ستحتاج إلى تعيين اسم الصَنْف كاملًا. تَتَوفَّر طريقة مُختصرة لاستيراد (importing) جميع الأصناف الموجودة ضِمْن حزمة معينة. على سبيل المثال، اِستخدِم مُوجِّه <code>import</code> التالي بهدف استيراد جميع الأصناف (classes) الموجودة بحزمة <code>java.util</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_14" style="">
<span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.*;</span></pre>

<p>
	لاحِظ أنه في حين يَتطابَق محرف البدل (wildcard) <code>*</code> مع جميع الأصناف الموجودة ضِمْن حزمة معينة، فإنه لا يَتطابَق مع حزمها الفرعية (sub-packages)، أيّ أنك لا تستطيع استيراد جميع الحزم الفرعية (sub-packages) الموجودة ضِمْن حزمة <code>javafx</code> بمُجرَّد كتابة <code>import javafx.*‎</code>.
</p>

<p>
	لمّا كان اِستخدَام محرف البدل (wildcard) <code>*</code> بتَعْليمَة <code>import</code> يُتيح عددًا كبيرًا من أسماء الأصناف التي على الأرجح لن تُستخدَم، بل والتي ربما لا يَعَلم المبرمج عنها شيئًا، فإن بعض المبرمجين يُفضِّلون استيراد كل صَنْف سيَستخدِمونه فعليًا استيرادًا صريحًا وبصورة مُنفصلة. يَنصَح الكاتب باِستخدَام محرف البدل (wildcard) فقط مع الحزم (packages) الأكثر صلة بالتطبيق؛ بهدف استيراد جميع الأصناف (classes) الموجودة بها، أما في حالة اِستخدَام صَنْف واحد فقط أو اثنين من حزمة معينة، فلربما عندها من الأفضل اِستخدَام استيرادات (imports) فردية.
</p>

<p>
	على سبيل المثال، قد يَحتوِي برنامج يتعامل بصورة أساسية مع الشبكات على المُوجِّه <code>import java.net.*;‎</code>، بينما قد يَحتوِي برنامج آخر يقرأ الملفات ويكتبها على المُوجِّه <code>import java.io.*;‎</code>. لكن لاحِظ أنه في حالة بدأت باستيراد الكثير من الحزم بتلك الطريقة، فلابُدّ من الانتباه لأمر هام. قد تَحتوِي حزمتان مختلفتان على صَنْفين (classes) يَحمِل كلاهما نفس الاسم، فمثلًا تَحتوِي كُلًا من الحزمتين <code>java.awt</code> و <code>java.util</code> على صَنْف اسمه <code>List</code>. الآن، إذا استوردت كُلًا من <code>java.awt.*‎</code> و <code>java.util.*</code>‎، فسيُصبِح الاسم البسيط للصَنْف <code>List</code> مُبهمًا، وبالتالي، إذا حاولت التَّصْريح (declare) عن مُتَغيِّر من النوع <code>List</code>، ستَحصُل على رسالة خطأ من المُصرِّف (compiler) بشأن وجود اسم صَنْف مُبْهَم. مع ذلك، ما زلت تستطيع اِستخدَام كِلا الصنفين بالبرنامج (program)، إما باِستخدَام الاسم الكامل للصَنْف مثل <code>java.awt.List</code> و <code>java.util.List</code>، أو باِستخدَام المُوجِّه <code>import</code> لاستيراد الأصناف المُفردة التي تحتاجها بدلًا من استيراد الحزم (packages) بالكامل.
</p>

<p>
	تُعدّ الحزمة <code>java.lang</code> أحد أهم الحزم الأساسية؛ لاحتوائها على بعض الأصناف الرئيسية، ولذلك تُستورَد جميع الأصناف الموجودة بتلك الحزمة أتوماتيكيًا بأيّ برنامج (program)، أيّ كما لو كان كل برنامج يبدأ بالتَعْليمَة <code>import java.lang.*;</code>‎. وهو في الواقع ما قد مَكَّنا سابقًا من اِستخدَام اسم الصَنْف <code>String</code> بدلًا من <code>java.lang.String</code>، واِستخدَام <code>Math.sqrt()‎</code> بدلًا من <code>java.lang.Math.sqrt()</code>‎. ومع ذلك، يُمكِنك أيضًا اِستخدَام الصياغة الأطول من أسماء تلك الأصناف.
</p>

<p>
	تُستخدَم تَعْليمَة <code>package</code> لإنشاء حزم (packages) جديدة، والتي قد تَتضمَّن مجموعة من الأصناف (classes). كل ما عليك القيام به هو كتابة تلك التَعْليمَة ببداية ملفات الشيفرة المصدرية (source code) التي تَحتوِي على تعريف الأصناف المطلوب تَضْمِينها بتلك الحزمة. مثلًا، إذا أردت إنشاء حزمة اسمها <code>utilities</code>، اِستخدِم السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_16" style="">
<span class="pln">package utilities</span><span class="pun">;</span></pre>

<p>
	لابُدّ أن تُكْتَب تَعْليمَة <code>package</code> ببداية الملف، أيّ حتى قَبْل أيّ مُوجِّه <code>import</code> قد يَكُون موجودًا بذلك الملف. بالإضافة إلى ذلك، لابُدّ أن يوجد ذلك الملف بمجلد يَحمِل نفس اسم الحزمة، أي <code>utilities</code> بهذا المثال. وبالمثل، لابُدّ أن توجد ملفات الأصناف ضِمْن الحزم الفرعية (sub-package) بمجلدات فرعية. على سبيل المثال، ينبغي لملفات الأصناف الموجودة بحزمة اسمها <code>utilities.net</code> أن تكون موجودة بمجلد اسمه <code>net</code> الموجود بدوره بمجلد آخر اسمه <code>utilities</code>. يستطيع أي صَنْف داخل حزمة (package) معينة الوصول أتوماتيكيًا إلى جميع الأصناف (classes) الآخرى الموجودة بنفس الحزمة. بتعبير آخر، لا يحتاج صَنْف معين أن يَستورِد (import) الأصناف من نفس الحزمة (package) المُعرَّف بها.
</p>

<p>
	عادة ما يَلجأ المبرمجون لإنشاء حزم جديدة وذلك إِما بالمشروعات التي تُعرِّف عددًا كبيرًا من الأصناف؛ بهدف تنظيمها، أو عند إِنشائهم لصناديق أدوات (toolboxes)؛ لتوفير واجهة برمجة تطبيقات (APIs) لبعض الوظائف والميزات غير المُتوفِّرة بواجهة برمجة تطبيقات جافا القياسية (standard Java <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>). في الواقع، يَحظَى المبرمجون "من صَانِعي الأدوات" عادة بهَيْبة واحترام أكبر من مُبرمجي التطبيقات الذين يَستخدِمون تلك الأدوات.
</p>

<p>
	لاحظ أن غالبية الأصناف المَكْتوبة لهذا الكتاب غَيْر مُضمَّنة بأي حزمة، مع عدة استثناءات قليلة مثل الصَنْف <code>TextIO</code> بالحزمة <code>textio</code>. لأغراض هذا الكتاب، فإنك ستحتاج أن تدرك ماهية الحزم (packages)؛ حتى تَتَمكَّن من استيراد الصَنْف <code>TextIO</code>، وكذلك الأصناف الموجودة ضِمْن الحزم القياسية (standard packages). لاحِظ أن الحزم القياسية هي دائمًا مُتوفِّرة بجميع البرامج (programs) التي تَكتُبها، قد تَتَساءل، أين توجد تلك الأصناف القياسية (standard classes) بصورة فعليّة؟ يَعتمِد ذلك على إصدار الجافا المُستخدَم إلى حد كبير. مثلًا، بالإصدار ٨ من الجافا، فإنها تَكُون مُخزَّنة بملفات جافا أَرْشيفيّة (jar files/Java archive) تقع بالمجلد الفرعي <code>lib</code> الموجود بمجلد التثبيت الخاص ببيئة تَّنْفيذ الجافا (Java Runtime Environment). إن ملفات جافا الأَرْشيفيّة (jar file/Java archive) هي ببساطة ملفات بامتداد <code>‎.jar</code> قد تَحتوِي على عدة أصناف. توجد غالبية الأصناف المُستخدَمة بالإصدار ٨ من الجافا بملف جافا أرشيفي (jar file) اسمه <code>rt.jar</code>. طرأت بعض التَغْيِيرات بالإصدار ٩ من الجافا، وهو ما سنُناقشه بالقسم الفرعي التالي.
</p>

<p>
	لاحِظ أن أيّ صَنْف بالنهاية لابُدّ وأن يقع ضِمْن حزمة (package)، حتى في حالة عدم تَحْدِيد الحزمة التي يُفْترَض أن يقع بها الصنف صراحةً، وفي تلك الحالات، يُوضَع الصَنْف تلقائيًا فيما يُعرَف باسم الحزمة الافتراضية (default package)، والتي ليس لها اسم. تقع تقريبًا كل الأمثلة التي ستراها بهذا الكتاب بالحزمة الافتراضية.
</p>

<h2>
	الوحدات (modules)
</h2>

<p>
	تُدعِّم الجافا منذ الإصدار ٩ ما يُعرَف باسم الوحدات (modules)، وهو ما تَسَبَّب بحُدوث بعض التَغْيِيرات على بنيتها ذات النطاقات الواسعة (large-scale structure). تُوفِّر الوحدات (modules) عمومًا مستوًى آخرًا من التَجْميع؛ حيث تَتضمَّن الوحدات مجموعة من الحزم، التي تَحتوِي على أصناف، والتي بدورها تَحتوِي على مُتَغيِّرات وتوابع (methods). ليس ضروريًا أن تقع الحزمة ضِمْن وحدة (module) حتى تُصبِح قابلة للاِستخدَام، ومع ذلك، فإن جميع الأصناف القياسية (standard classes) بكُلًا من جافا (Java) وجافا إف إكس (JavaFX) قد ضُمّنت داخل وحدات (modules).
</p>

<p>
	وَفَّرت الجافا الوحدات (modules) لعدة أسباب: أولًا، لتَحسِّين التَحكُّم بالوصول (access control)، وهو في الواقع أحد أهم الأسباب الرئيسية. قَبْل الوحدات، كان بإِمكانك اِستخدَام الأصناف العامة، أيّ تلك المُصرَّح عنها باِستخدَام المُبدِّل <code>public</code>، بأيّ مكان وداخل أيّ صَنْف ضِمْن أيّ حزمة، وبالمثل مُتَغيِّراته وتوابعه المُصرَّح عنها باِستخدَام المُبدِّل <code>public</code>. في المقابل، يَعنِي اِستخدَام المُبدِّل العام <code>public</code> مع صَنْف، مُعرَّف ضِمْن وحدة (module)، كَوْن ذلك الصَنْف عامًا <code>public</code> ضِمْن الوحدة (module) المُعرَّف بداخلها فقط. ومع ذلك، ما يزال بإمكان الوحدات تصدير (export) أي حزمة بشكل صريح، وبناءً عليه، ستُصبِح الأصناف العامة، أيّ تلك المُعرَّفة باِستخدَام المُبدِّل <code>public</code>، ضمن تلك الحزمة قابلة للوصول (accessible) مرة آخرى من أي مكان، بما في ذلك الوحدات (modules) الآخرى، وكذلك الأصناف التي ليست جزءًا من أي وحدة. يمكن حتى تَخْصيص الوحدات (modules) المطلوب تصدير الحزمة إليها، وهو ما يُوفِّر تَحكُّمًا بالوصول (access control) أكثر دقة. يَعنِي كل ما سبق أنه يُمكِننا الآن إنشاء حزم هي خاصة (private) بالأساس، أيّ أنها غَيْر مَرئية (invisible) من خارج الوحدة، ولكنها في نفس الوقت تُوفِّر خدمات (services) للحزم الآخرى داخل نفس الوحدة. يُمكِننا بذلك عدّ الوحدة نوعًا آخرًا من الصندوق الأسود (black box)، تَكُون فيه الحزم غَيْر المُصدَّرة (non-exported) جزءًا من تَّنْفيذه (implementation) الخفي. تُعدّ التركيبية (modularity) على هذا المُستوى الواسع من النطاق مهمة بحقّ، وبالأخص للتطبيقات ذات النطاقات الواسعة (large-scale applications).
</p>

<p>
	الدافع الآخر لتَوْفِير الوحدات (modules) هو الحجم الكلي لبيئة تَّنْفيذ الجافا القياسية (Java Runtime Environment)، وتُختصر إلى JRE. تَتضمَّن تلك البيئة جميع الأصناف القياسية (standard classes) على الرغم من أن التطبيقات (application) تَستخدِم عادةً جزءًا صغيرًا منها. تَسمَح التركيبية (Modularization) بإنشاء بيئات تَّنْفيذ جافا مُخصَّصة (custom JREs) أصغر؛ بحيث تحتوي فقط على الوحدات التي يحتاجها التطبيق. تَتضمَّن عُدة تطوير الجافا (Java Development Kit)، وتُختصر إلى JDK، الأمر <code>jlink</code> المُستخدَم لإنشاء بيئات تَّنْفيذ مُخصَّصة (custom runtimes)، والتي عادةً ما تَتضمَّن وحدات (modules) التطبيق ذاته بالإضافة إلى الوحدات القياسية (standard modules) المطلوبة لتَشْغِيل ذلك التطبيق (application). بعد ذلك، تُوزَّع (distribute) بيئات التَّنْفيذ تلك كتطبيق قائم بذاته (standalone)، والذي يُمكِن تَشْغِيله حتى بتلك الحواسيب التي لم تُثبَّت عليها عُدة تطوير الجافا (JDK). ولكن لاحِظ أنك ستحتاج إلى إنشاء إصدارات مختلفة من بيئة التَّنْفيذ المُخصَّصة (custom runtime) للمنصات المختلفة مثل الويندوز (Windows) والماك (Mac OS) ولينكس (Linux)، كما هو الحال مع عُدة تطوير الجافا (JDK) ذاتها. بالإضافة إلى ذلك، لن تُطبَق تحديثات الأمان (security updates) الصادرة لعُدة تطوير الجافا (JDK) أتوماتيكيًا على بيئات التَّنْفيذ المُخصَّصة (custom runtime)، ولذلك تقع مسئولية تحديثها على مُطوِّر التطبيق. عمومًا يُعدّ ذلك ميزة مفيدة جدًا للتطبيقات الكبيرة.
</p>

<p>
	منذ الإصدار ٩ من الجافا، تُخزَّن ملفات أصناف الوحدات القياسية (standard modules) المُصرَّفة داخل الملف <code>modules</code>، والموجود بالمجلد الفرعي <code>lib</code> الموجود بدوره بالمجلد الرئيسي لعُدة تطوير الجافا (JDK). صيغة ذلك الملف هي <code>jimage</code>، يُمكِنك التعامل معها باِستخدَام أداة سطر الأوامر <code>jimage</code>. في الواقع، عندما تُستخدَم أداة <code>jlink</code> لإنشاء بيئة تَّنْفيذ مُخصَّصة (custom runtime)، فإن جزءًا مما تقوم به هو إِنشاء ملف <code>modules</code> مُخصَّص يَحتوِي فقط على الوحدات (modules) المطلوبة لبيئة التَّنْفيذ (runtime) تلك. بفَحْص مجلد الإصدار ١٢ من عُدة تطوير الجافا (JDK) بحاسوب لينكس (Linux) الخاص بالكاتب، تَبيَّن أن الملف <code>modules</code> يَتضمَّن حوالي ٣٠١٩٩ صَنْف، ضِمْن ١٠٠٠ حزمة، ضِمْن ٧٠ وحدة، كما وصل حجمه إلى حوالي ١٣٠ ميجا بايت. يَحتوِي المجلد الرئيسي لعُدة تطوير الجافا (JDK) أيضًا على المجلد الفرعي <code>jmods</code>، والذي يَتضمَّن تلك الوحدات (modules) ولكن بصيغة آخرى، وعمومًا هو ليس مطلوبًا لتَصْرِيف البرامج وتَشْغِيلها، وغالبًا يَقْتصِر اِستخدَامه على الأداة <code>jlink</code> على حَدْ عِلم الكاتب.
</p>

<p>
	تَتضمَّن عُدة تطوير الجافا (JDK) مجموعة من الوحدات، من بينها الوحدتين <code>java.base</code> و <code>java.desktop</code>. تَحتوِي أولاهما على الحزم الأساسية مثل <code>java.lang</code> و <code>java.util</code>، بينما تَتضمَّن الثانية حزم (packages) خاصة بـ"أدوات تَحكُّم واجهة المُستخدَم الرسومية <code>Swing</code> ‏(Swing GUI toolkit)". في المقابل، تَتضمَّن منصة جافا إف إكس (JavaFX) كُلًا من الوحدات <code>javafx.base</code> و <code>javafx.control</code> و <code>javafx.graphics</code> بالإضافة إلى وحدات آخرى غير شائعة الاِستخدَام عمومًا. يُقسَّم تَوْثيق واجهة برمجة التطبيقات (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>) للإصدارات التركيبية (modular) من الجافا إلى وحدات (modules)، مُقسَّمة بدورها إلى حزم (packages)، وأخيرًا إلى أصناف (classes)، وهو ما قد يَجعَل التَوْثيق (documentation) أصعب قليلًا في التَصفُّح بالموازنة مع الإصدارات الأقدم. مع ذلك تَتوفَّر مِيزَة بحث فعالة بالموقع الالكتروني للتَوْثيق. يُمكِنك تَصفُّح <a href="https://docs.oracle.com/en/java/javase/11/docs/api/index.html" rel="external nofollow">توثيق الإصدار ١١ من الجافا</a> بالإضافة إلى <a href="https://openjfx.io/javadoc/11" rel="external nofollow">توثيق الإصدار ١١ من جافا إف إكس (JavaFX)</a>.
</p>

<p>
	ليس ضروريًا أن يَقَع الصَنْف ضِمْن وحدة (module)، وفي تلك الحالة، فإنه ما يزال يستطيع اِستخدَام الحزم من الوحدات الاخرى، بشَّرْط أن تَكُون تلك الحزم قد صُدّرت (exported) بالوحدات المُعرَّفة داخلها. يستطيع المبرمج عمومًا اِستخدَام الأصناف الموجودة بعُدة تطوير الجافا (JDK) دون الحاجة للتفكير نهائيًا بالوحدات أو حتى مَعرِفة وجودها. يَنطبِق ذلك على برامج سطر الأوامر (command-line programs) بهذا الكتاب، أما برامج واجهة المُستخدِم الرسومية (GUI programs) التي تَستخدِم منصة جافا إف إكس (JavaFX)، فالأمور تختلف قليلًا منذ الإصدار ١١ من الجافا؛ وذلك لأن تلك المنصة قد حُذفَت من عُدة تطوير الجافا (JDK)، وأصبحت تُوزَّع بصورة مستقلة كمجموعة من الوحدات. لذلك، عند تَصْرِيف برنامج جافا إف إكس (JavaFX)، أو تَشْغِيله، ستحتاج، كما رأينا بالقسم ٢.٦، إلى تَخْصيص مسار الوحدة (module path)، والذي لابُدّ أن يَحتوِي على وحدات تلك المنصة، كما ستحتاج إلى تمرير قيمة للخيار ‎<code>--add-modules</code>. مُرِّرت <code>ALL-MODULE-PATH</code> كقيمة للخيار <code>‎--add-modules</code> بالقسم ٢.٦؛ للسماح للبرنامج بالوصول إلى أي وحدات (modules) موجودة بمسار الوحدة (module path) المُمرَّر. بدلًا من ذلك، قد تُمرِّر قائمة بأسماء الوحدات المُستخدَمة فعليًا بالبرنامج فقط.
</p>

<p>
	تنبيه: لا يُغطِى هذا الكتاب موضوع الوحدات (modules) بصورة أكبر من مُجرَّد اِستخدَامها مع منصة جافا إف إكس (JavaFX)، بالإضافة إلى المعلومات الأساسية بهذا القسم.
</p>

<h2>
	التوثيق بأداة <code>Javadoc</code>
</h2>

<p>
	ينبغي عمومًا كتابة تَوْثيق (documentation) جيد لأيّ واجهة برمجة تطبيقات (<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>)؛ وذلك حتى يَتَمكَّن المبرمجين من اِستخدَامها بصورة فعالة. يَشيِع اِستخدَام نظام <code>Javadoc</code> لتَوْثيق غالبية واجهات برمجة تطبيقات جافا (Java APIs)، فمثلًا، يُستخدَم هذا النظام لتجهيز تَوْثيق حزم الجافا القياسية (standard packages)، كما يَنشُر غالبية المبرمجين تقريبًا تَوْثيقًا باِستخدَام نفس ذلك النظام لأي صندوق أدوات (toolbox) يُطوروه بالجافا.
</p>

<p>
	يُجهَز تَوْثيق <code>Javadoc</code> بالاعتماد على مجموعة من التعليقات (comments) الخاصة، والتي تُكتَب بملفات الشيفرة المصدرية. كما تَعَلم، تُكتَب أحد أنواع تعليقات الجافا ضِمْن الترميزين <code>‎/*‎</code> و <code>‎*/‎</code>. بالمثل، تُكتَب تعليقات <code>Javadoc</code> بنفس الصياغة لكنها تبدأ بالترميز <code>‎/**‎‎</code> بدلًا من الترميز <code>‎/*‎</code>. لقد تَعرَّضت بالفعل لتعليقات مَكْتوبة بتلك الصياغة بكثير من الأمثلة بهذا الكتاب.
</p>

<p>
	ينبغي أن تُوْضَع تعليقات <code>Javadoc</code> قَبْل البرنامج الفرعي المَعنِي بالتعليق مباشرة. لاحظ ضرورة اتباع تلك القاعدة عمومًا وبَغْض النظر عن العنصر المَعنِي بالتَوْثيق. تُستخدَم تعليقات <code>Javadoc</code> عمومًا مع البرامج الفرعية (subroutines)، والمُتَغيِّرات الأعضاء (member variables)، والأصناف (classes)، وفي جميع تلك الحالات، لابُدّ دائمًا أن يَسبِق تعليق <code>Javadoc</code> العنصر المَعنِي بالتعليق مباشرة.
</p>

<p>
	عندما يُصرِّف (compile) الحاسوب ملفات الشيفرة المصدرية، فإنه يتجاهل تعليقات <code>Javadoc</code> مثلما يتجاهل أي تعليق عادي آخر. تَتوفَّر الأداة <code>javadoc</code>، والتي تَقْرأ ملفات الشيفرة المصدرية، لتَستخرِج منها تعليقات <code>Javadoc</code>، ثم تُنشِئ مجموعة من صفحات الانترنت التي تَتضمَّن تلك التعليقات بصياغة متناسقة ومترابطة. لاحظ أن تلك الأداة تَستخرِج افتراضيًا المعلومات المُتعلِّقة بكُلًا من الأصناف العامة والبرامج الفرعية العامة والمُتَغيِّرات الأعضاء العامة فقط، أي تلك المُصرَّح عنها باِستخدَام المُبدِّل <code>public</code>، ومع ذلك فهي تَسمَح بإنشاء تَوْثيق للعناصر غير العامة (non-public) من خلال خيار خاص. إذا لم تَعثُر الأداة <code>javadoc</code> على أية تعليقات <code>Javadoc</code> لعنصر معين، فإنها تُنشِئ واحدًا افتراضيًا يَتكوَّن من مُجرد معلومات بسيطة عن ذلك العنصر، مثل اسم المُتَغيِّر العضو ونوعه في حالة كان العنصر مُتَغيِّر عضو، أو كُلًا من اسم البرنامج الفرعي، ونوع القيمة المُعادة منه وقائمة مُعامِلاته في حالة كان العنصر برنامجًا فرعيًا. تعدّ تلك المعلومات مُجرد معلومات صياغية (syntactic)، أما لإضافة معلومات دلالية (semantics) واقعية، فلابُدّ من كتابة تعليق <code>Javadoc</code>.
</p>

<p>
	كمثال، يُمكِنك فَحْص "<a href="http://math.hws.edu/javanotes/TextIO_Javadoc/index.html" rel="external nofollow">توثيق <code>Javadoc</code> للصنف <code>TextIO</code></a>". اُنشأت صفحة التَوْثيق تلك باِستخدَام أداة <code>javadoc</code> مع <a href="http://math.hws.edu/javanotes/source/chapter4/textio/TextIO.java" rel="external nofollow">ملف الشيفرة المصدري <code>TextIO.java</code></a>. إذا حَمَّلت نسخة الكتاب المتاحة عبر الإنترنت، ستَجِدْ ذلك التوثيق بالمجلد <code>TextIO_Javadoc</code>.
</p>

<p>
	يُعدّ استخدام الترميز <code>*</code> ببداية كل سطر ضِمْن تعليقات <code>Javadoc</code> أمرًا اختياريًا؛ حيث تَحذفه أداة <code>javadoc</code> على أية حال. بالإضافة إلى النص العادي، قد تَحتوِي تعليقات <code>Javadoc</code> على ترميزات (codes) خاصة، مثل أوامر HTML الترميزية (HTML mark-up commands)‏. تُستخدَم لغة HTML عمومًا لإنشاء صفحات الانترنت، ولمّا كانت تعليقات <code>Javadoc</code> مَعنيَّة بالظهور على تلك الصفحات، فإن أداة <code>javadoc</code> تَنسَخ أي أوامر HTML بالتعليقات إلى صفحات الانترنت التي تُنشئها. لن يتناول الكتاب أيّ شرح تفصيلي عن HTML، لكن، كمُجرَّد مثال، تستطيع مثلًا إضافة <code>&lt;p&gt;</code> للإشارة إلى بداية فقرة جديدة. في حالة غياب أوامر HTML، تتجاهل الأداة الأسطر الفارغة والفراغات (spaces) الإضافية الموجودة بالتعليق. انتبه أيضًا للمحرفين <code>&amp;</code> و <code>‎&lt;‎</code>؛ لأن لهما معنًى خاصًا بلغة HTML، ولذا لا ينبغي اِستخدَامهما بتعليقات <code>Javadoc</code> لمعنى غير تلك المَعانِي، ولكن يُمكِن كتابتهما باِستخدَام <code>‎&amp;amp;‎</code> و ‎<code>&amp;lt‎;‎</code> على التوالي.
</p>

<p>
	يُوفِّر نظام التوثيق <code>Javadoc</code> ما يُعرَف باسم الوُسوم التوثيقية (doc tags). تُكتَب تلك الوسوم ضِمْن تعليقات <code>Javadoc</code>، بحيث تُعالجها أداة <code>javadoc</code> بعدّها نوعًا من الأوامر الخاصة. يبدأ أيّ وَسم تَوْثيقي (doc tag) بالمحرف <code>@</code> مَتبوعًا باسمه. سنتناول ٤ وسوم (tags) فقط، هي كالتالي: الوُسوم <code>‎@author</code> و ‎<code>@param</code> و <code>‎@return</code> و ‎<code>@throws</code>. يُستخدَم الوسم <code>‎@author</code> فقط مع الأصناف، وينبغي أن يُتبَع باسم المؤلف. تُستخدَم الوسوم الثلاثة الاخرى بتعليقات <code>Javadoc</code> التي تستهدف البرامج الفرعية بهدف تَوْفِير معلومات عن مُعاملاتها، وقيمها المُعادة، والاعتراضات (exceptions) التي قد تبلِّغ عنها. لابُدّ أن تُوْضَع تلك الأوسمة بنهاية التعليق، أي بَعْد وصف البرنامج الفرعي نفسه. تُكتَب بالصيغ (syntax) التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_18" style="">
<span class="lit">@param</span><span class="pln">  </span><span class="pun">&lt;</span><span class="pln">parameter</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;</span><span class="pln">   </span><span class="pun">&lt;</span><span class="pln">description</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="pln">parameter</span><span class="pun">&gt;</span><span class="pln">

</span><span class="lit">@return</span><span class="pln">  </span><span class="pun">&lt;</span><span class="pln">description</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="kwd">return</span><span class="pun">-</span><span class="pln">value</span><span class="pun">&gt;</span><span class="pln">

</span><span class="lit">@throws</span><span class="pln">  </span><span class="pun">&lt;</span><span class="pln">exception</span><span class="pun">-</span><span class="kwd">class</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;</span><span class="pln">   </span><span class="pun">&lt;</span><span class="pln">description</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="pln">exception</span><span class="pun">&gt;</span></pre>

<p>
	يُمكِن أن تمتد الأوصاف <strong><description-of-parameter></description-of-parameter></strong> و <strong><description-of-return-value></description-of-return-value></strong> و <strong><description-of-exception></description-of-exception></strong> إلى عدة أسطر؛ حيث ينتهي أي وصف إما ببداية الوَسْم التوثيقي (doc tag) التالي أو بنهاية تعليق <code>Javadoc</code> بالكامل. يُمكِنك اِستخدَام الوَسْم ‎<code>@param</code> لوصف كل مُعامِل (parameter) يَستقبِله البرنامج الفرعي، وكذلك الوَسْم ‎<code>@throws</code> بقدر ما تريد تَوْثيقه من أنواع الاعتراضات (exception) المختلفة. وأخيرًا الوَسْم <code>‎@return</code> والذي يُفْترَض كتابته للبرامج الفرعية التي تُعيد قيمة فعلية لا <code>void</code>. لا يُشترَط عمومًا كتابة تلك الوسوم (tags) بترتيب معين.
</p>

<p>
	اُنظر المثال التالي والذي يَستخدِم وُسوم التَوْثيق (doc tag) الثلاثة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1485_7" style="">
<span class="com">/**
 * يحسب هذا البرنامج الفرعي مساحة المستطيل بفرض استقباله
 * لكلا من طول وعرض المستطيل. 
 * ينبغي أن يكون كلا من طول وعرض المستطيل الممررين قيمة موجبة
 * @param width طول أحد جوانب المستطيل 
 * @param height طول الجانب الآخر من المستطيل
 * @return مساحة المستطيل
 * @throws IllegalArgumentException إذا كان عرض أو طول المستطيل قيمة سالبة
 */</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> areaOfRectangle</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> height</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> width </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> width </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln">  </span><span class="pun">||</span><span class="pln">  height </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">IllegalArgumentException</span><span class="pun">(</span><span class="str">"Sides must have positive length."</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">double</span><span class="pln"> area</span><span class="pun">;</span><span class="pln">
    area </span><span class="pun">=</span><span class="pln"> width </span><span class="pun">*</span><span class="pln"> height</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> area</span><span class="pun">;</span><span class="pln"> 
</span><span class="pun">}</span></pre>

<p>
	حَاوِل أن تَستخدِم تعليقات <code>Javadoc</code> بالشيفرة الخاصة بك، حتى لو لَمْ تَكُن تَنوِي إنشاء صفحة انترنت للتوثيق (documentation)؛ لأنها تُعدّ الصيغة القياسية لكتابة التوثيقات، لذا ستَكُون مألوفة لغالبية مُبرمجي الجافا.
</p>

<p>
	أما إذا أردت إنشاء صفحة انترنت للتَوْثيق، فستحتاج إلى اِستخدَام أداة <code>javadoc</code>، وهي متاحة كأمر بعُدة تطوير الجافا (JDK) التي ناقشناها بالقسم ٢.٦. تستطيع عمومًا اِستخدَام أداة <code>javadoc</code> بواجهة سطر الأوامر (command line interface) بنفس الطريقة التي تَستخدِم بها أوامر مثل <code>javac</code> و <code>java</code>. لاحِظ أنه يُمكِن تطبيق توثيق <code>Javadoc</code> أيضًا داخل بيئات التطوير المتكاملة (integrated development environments)، تُعرَف اختصارًا باسم IDE، التي تحدثنا عنها بالقسم ٢.٦. لن نَتَعرَّض لأيّ من تلك التفاصيل هنا، حيث يُمكِنك ببساطة مراجعة توثيق بيئة البرمجة (programming environment) الخاصة بك.
</p>

<h2>
	الاستيراد الساكن (static import)
</h2>

<p>
	كنقطة أخيرة بهذا القسم، سنتناول امتدادًا للمُوجِّه (directive)‏ <code>import</code>. رأيت بالفعل كيف مَكَّنَك المُوجِّه <code>import</code> من الإشارة إلى صَنْف مثل <code>java.util.Scanner</code> باِستخدَام الاسم البسيط للصَنْف <code>Scanner</code>. لكنك ما زلت مُضطرًا لاِستخدَام الأسماء المُركَّبة للإشارة إلى المُتَغيِّرات الأعضاء الساكنة (static member variables) مثل <code>System.out</code>، والتوابع الساكنة (static methods) مثل <code>Math.sqrt</code>.
</p>

<p>
	في الواقع، تَتَوفَّر صياغة آخرى من المُوجِّه <code>import</code>، تَستورِد الأعضاء الساكنة (static members) الموجودة بصَنْف معين بنفس الطريقة التي يَستورَد بها المُوجِّه <code>import</code> الأصناف (classes) من حزمة (package). تُسمَى تلك الصياغة من المُوجِّه باسم الاستيراد الساكن (static import). فمثلًا، لاستيراد اسم عضو ساكن (static member) واحد من صَنْف، نَكتُب الصيغة (syntax) التالية :
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_23" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">package</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;.&lt;</span><span class="kwd">class</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;.&lt;</span><span class="kwd">static</span><span class="pun">-</span><span class="pln">member</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;;</span></pre>

<p>
	بالمثل، قد تُكتَب الصيغة التالية لاستيراد جميع الأعضاء الساكنة العامة (public static members) ضِمْن صَنْف معين:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_25" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">package</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;.&lt;</span><span class="kwd">class</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;.*;</span></pre>

<p>
	على سبيل المثال، إذا كَتَبَت المُوجِّه <code>import</code> التالي قَبْل تعريف صَنْف (class definition) معين:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_27" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">lang</span><span class="pun">.</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">;</span></pre>

<p>
	فإنك تستطيع بَعْدها -ضِمْن ذلك الصَنْف- اِستخدَام الاسم البسيط <code>out</code> بدلًا من الاسم المُركَّب <code>System.out</code>، وكذلك كتابة <code>out.println</code> بدلًا من <code>System.out.println</code>.
</p>

<p>
	إذا كنت ستَستخدِم الصَنْف <code>Math</code> بكثرة ضِمْن صَنْف معين، فلربما قد تُفضِّل اِستِباق تعريف ذلك الصنف بالمُوجِّه <code>import</code> التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_29" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">lang</span><span class="pun">.</span><span class="typ">Math</span><span class="pun">.*;</span></pre>

<p>
	وهو ما سيَسمَح لك بكتابة <code>sqrt</code> بدلًا من <code>Math.sqrt</code>، وكتابة <code>log</code> بدلًا من <code>Math.log</code>، وأيضًا <code>PI</code> بدلًا من <code>Math.PI</code>، وغيره. يُمكِنك أيضًا استيراد الدالة <code>getlnInt</code> من الصنف <code>TextIO</code> باِستخدَام:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4592_31" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">;</span></pre>

<p>
	تنبيه: يتَطلَّب مُوجِّه الاستيراد الساكن (static import directive) تَخْصيص اسم الحزمة <strong><package-name></package-name></strong> حتى مع الأصناف المُعرَّفة بالحزمة القياسية <code>java.lang</code>، مما يَعنِي أنك لن تَكُون قادرًا على تَّنْفيذ أيّ استيراد ساكن (static import) من صَنْف مُعرَّف بالحزمة الافتراضية (default package)؛ لأن ليس لها اسم.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c4/s6.html" rel="external nofollow">Section 6: APIs, Packages, Modules, and Javadoc</a> من فصل Chapter 4: Programming in the Large I: Subroutines من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1091</guid><pubDate>Tue, 15 Dec 2020 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x628;&#x64A;&#x631;&#x627;&#x62A; &#x644;&#x627;&#x645;&#x62F;&#x627; (Lambda Expressions) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D8%A8%D9%8A%D8%B1%D8%A7%D8%AA-%D9%84%D8%A7%D9%85%D8%AF%D8%A7-lambda-expressions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1090/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_12/27.png.88233641fba6dad928e24a85c1509d18.png" /></p>

<p>
	يُخْزَّن البرنامج الفرعي (subroutine) بذاكرة الحاسوب على هيئة سِلسِلة نصية طويلة مُكوَّنة من الرقمين صفر وواحد، ولذلك فإنه لا يَختلف كثيرًا عن البيانات (data)، مثل الأعداد الصحيحة والسَلاسِل النصية والمصفوفات، والتي تُخْزَّن أيضًا بنفس الطريقة. ربما اِعتدت التفكير بكُلًا من البرامج الفرعية والبيانات على أساس أنهما شيئان مختلفان تمامًا، ولكن في الواقع يَتعامَل الحاسوب مع البرنامج الفرعي على أساس أنه مجرد نوع آخر من البيانات. تَسمَح حتى بعض اللغات البرمجية بالتَعامُل مع البرامج الفرعية بنفس الطريقة التي يَتعامَل معها الحاسوب، وهو ما أُضيف إلى الجافا على هيئة تعبيرات لامدا (lambda expressions) منذ الإصدار ٨.
</p>

<p>
	أصبحت تعبيرات لامدا أكثر شيوعًا ببرامج الجافا، وهي مفيدة في العموم، ولكن تَبرُز أهميتها بصورة أكبر ببرمجة واجهات المُستخدِم الرُسومية (GUI)، كالتَعامُل مع "أدوات تَحكُّم واجهة المُستخدَم الرسومية <code>JavaFX</code> ‏(JavaFX GUI toolkit)"، وهو ما سنتناوله بالفصل السادس، كما سنَتَعرَّض لها مجددًا بنهاية الفصل الخامس، لذا يُمكِنك تَخطِّي هذا القسم إذا أردت إلى ذلك الحين.
</p>

<h2>
	الدوال الكيانية (first-class functions)
</h2>

<p>
	يُمكِننا كتابة دالة لحِسَاب قيمة مربع العدد، بحيث تَستقبِل ذلك العدد كمُعامِل صُّوري أو وهمي (dummy parameter)، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_8" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> square</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> x </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كالعادة، لابُدّ من تَخْصيص اسم لتلك الدالة، وفي تلك الحالة كان <code>square</code>، وعليه تُصبِح تلك الدالة جزءًا دائمًا من البرنامج (program)، وهو ما قد لا يَكُون مُلائمًا؛ بالأخص إذا كنت تَنوِي اِستخدَام الدالة مرة واحدة فقط.
</p>

<p>
	لامدا (lambda) هو أحد حروف الأبجدية الإغريقية (Greek alphabet)، والذي اِستخدَمه عالم الرياضيات ألونزو تشرتش (Alonzo Church) أثناء دراسته للدوال القابلة للحِسَاب (computable functions). على سبيل المثال، إذا كنا نُريد حِسَاب قيمة مربع عدد، وليكن x، فقد تَظُنّ أن الترميز x<sup>2</sup> يُمثِل "دالة" تَحسِب مربع x، لكنه، في الواقع، ليس سوى تعبير (expression) يُمثِل "نتيجة" حِسَاب مربع x. قَدَّمَ ألونزو تشرتش (Alonzo Church) ترميز لامدا (lambda notation) والذي يُمكِن اِستخدَامه لتعريف دالة (function) بدون تَخْصيص اسم لها. بالتحديد اِستخدَم الترميز lambda(x).x<sup>2</sup> (في الواقع يُستخدَم الحرف الإغريقي لامدا ذاته وليس الكلمة نفسها) للإشارة إلى "دالة x معطاة بواسطة x<sup>2</sup>". يُعدّ هذا الترميز دالة مجرَّدة (function literal)، أيّ تُمثِل قيمة من النوع "دالة (function)" بنفس الطريقة التي تُعدّ بها القيمة 42 عددًا صحيحًا مُجرَّدًا (integer literal) يُمثِل قيمة من النوع <code>int</code>.
</p>

<p>
	ينبغي أن تَدْفَعك الدوال المُجرَّدة (function literals) إلى التَفكير بالدوال (function) على أنها مُجرَّد نوع آخر من القيم، وعندما تَصِل إلى تلك المرحلة، فإنك ستَكُون قادرًا على تَطْبِيق نفس تلك الأشياء التي اعتدت إجرائها على القيم الآخرى على الدوال أيضًا، كإِسْناد دالة إلى مُتَغيِّر، أو تمرير دالة كمُعامِل (parameter) إلى برنامج فرعي (subroutine)، أو إعادة دالة كقيمة من برنامج فرعي، أو حتى إنشاء مصفوفة دوال (array of functions). تَسمَح بعض لغات البرمجة بالقيام بكل تلك الأشياء، ويُقال عندها أنها تُدعِّم "الدوال الكيانيَّة (first-class functions)" أو أنها تُعامِل الدوال بعدّها كائنات كيانيَّة (first-class objects).
</p>

<p>
	تُوفِّر لغة الجافا كل تلك الأشياء من خلال تعبيرات لامدا (lambda expressions)، والتي تَختلِف صيغتها عن الترميز الذي اِستخدَمه ألونزو تشرتش (Alonzo Church)، فهي الواقع، لا تَستخدِم حتى كلمة لامدا (lambda) على الرغم من مُسماها. تُكتَب دالة حِسَاب مربع العدد بتعبير لامدا (lambda expression) بلغة الجافا، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_10" style="">
<span class="pln">x  </span><span class="pun">-&gt;</span><span class="pln">  x</span><span class="pun">*</span><span class="pln">x</span></pre>

<p>
	يُنشِئ العَامِل <code>‎-&gt;‎</code> تعبير لامدا، بحيث تَقَع المُعامِلات الوهمية أو الصُّوريّة (dummy parameter) على يسار العَامِل، بينما يَقَع التعبير (expression) المسئول عن حِسَاب قيمة الدالة على يمينه. قد ترى تعبير لامدا بالأعلى مُمرَّرًا كمُعامِل فعليّ (actual parameter) إلى برنامج فرعي، أو مُسنَد إلى مُتَغيِّر، أو مُعاد من دالة.
</p>

<p>
	إذًا، هل الدوال بلغة الجافا كيانيَّة (first-class)؟ لا تَتَوفَّر إجابة واضحة على هذا السؤال، لأن لغة الجافا لا تُدعِّم بعض الأشياء الآخرى المُتوفِّرة ضِمْن لغات برمجية آخرى. فمثلًا، في حين تستطيع إِسْناد تعبير لامدا المُعرَّف بالأعلى إلى مُتَغيِّر اسمه <code>sqr</code>، فإنك لن تستطيع بَعْدها اِستخدَام ذلك المُتَغيِّر كما لو كان دالة فعليّة، أيّ لا تستطيع كتابة <code>sqr(42)‎</code>. لغة الجافا عمومًا هي لغة صارمة في تَحْدِيد النوع (strongly typed)، ولذلك لكي تَتَمكَّن من إِنشاء المُتَغيِّر <code>sqr</code>، فعليك التَّصْريح عنه أولًا وهو ما يَتضمَّن تَخْصيص نوعه، فيا تُرى ما هو ذلك النوع الذي يَتناسب مع قيمة هي عبارة عن دالة؟ تُوفِّر الجافا ما يُعرَف باسم واجهة نوع الدالة (functional interface) لهذا الغرض، وسنناقشها بَعْد قليل.
</p>

<p>
	ملاحظة أخيرة: على الرغم من ارتباط مصطلح الدالة (function) بتعبيرات لامدا (lambda expressions) بدلًا من مصطلحات مثل برنامج فرعي (subroutine) أو تابع (method)، فإنها في الواقع لا تَقْتصِر على تمثيل الدوال (functions)، وإنما يُمكِنها تمثيل أي برنامج فرعي (subroutines)، وبصورة عشوائية.
</p>

<h2>
	واجهات نوع الدالة (functional interfaces)
</h2>

<p>
	كي تَتَمكَّن من اِستخدَام برنامج فرعي (subroutine) معين، فلابُدّ أن تَعرِف كُلًا من اسمه، وعدد المُعامِلات (parameters) التي يَستقبِلها، وأنواعها، بالإضافة إلى نوع القيمة المُعادة (return type) من ذلك البرنامج الفرعي. تُوفِّر لغة الجافا ما يُعرَف باسم واجهات نوع الدالة (functional interface)، وهي أَشْبَه بالأصناف (class)، حيث تُعرَّف بملف امتداده هو <code>‎.java</code> كأي صَنْف، وتَتضمَّن تلك المعلومات المذكورة بالأعلى عن برنامج فرعي وحيد. انظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_13" style="">
<span class="kwd">public</span><span class="pln"> interface </span><span class="typ">FunctionR2R</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">double</span><span class="pln"> valueAt</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> x </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُصرِّح الشيفرة بالأعلى عن واجهة نوع الدالة <code>FunctionR2R</code>، والموجودة بملف يَحمِل اسم <code>FunctionR2R.java</code>. تُصرِّح تلك الواجهة عن الدالة <code>valueAt</code>، والتي تَستقبِل مُعامِل وحيد من النوع <code>double</code>، وتُعيد قيمة من النوع <code>double</code>. تَفرِض قواعد الصيغة تَخْصيص اسم للمُعامِل -<code>x</code> بالأعلى- على الرغم من أنه في الواقع ليس ذا أهمية هنا، وهو ما قد يَكُون مزعجًا نوعًا ما. ها هو مثال آخر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_15" style="">
<span class="kwd">public</span><span class="pln"> interface </span><span class="typ">ArrayProcessor</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">void</span><span class="pln"> process</span><span class="pun">(</span><span class="pln"> </span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> array</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> count </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تَتضمَّن لغة الجافا الكثير من واجهات نوع الدالة القياسية (standard functional interfaces) بصورة افتراضية. تُعدّ واجهة نوع الدالة <code>Runnable</code> واحدة من أهم تلك الواجهات، وأبسطها، والمُعرَّفة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_17" style="">
<span class="kwd">public</span><span class="pln"> interface </span><span class="typ">Runnable</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> run</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنَستخدِم واجهات نوع الدالة (functional interfaces) الثلاثة بالأعلى للأمثلة التالية بهذا القسم.
</p>

<p>
	تُوفِّر لغة الجافا أيضًا ما يُعرَف باسم الواجهات (Interfaces)، والتي هي في الواقع أعم وأشمل، وربما أكثر تعقيدًا من واجهات نوع الدالة (functional interfaces). سنتعلَّّم المزيد عنها بالقسم ٥.٧. سنُقصِر حديثنا بهذا القسم على واجهات نوع الدالة (functional interfaces)؛ لارتباطها بموضوعنا الرئيسي: تعبيرات لامدا (lambda expressions).
</p>

<p>
	يُعدّ اسم واجهة نوع الدالة نوعًا (type)، تمامًا كالأنواع <code>String</code> و <code>double</code>، وكأيّ نوع، فإنه يُمكِن اِستخدَامه للتَّصْريح عن المُتَغيِّرات، والمُعامِلات، وكذلك لتَخْصيص نوع القيمة المُعادة (return type) من الدوال، ويُمكِن إِسْناد تعبيرات لامدا (lambda expression) كقيم للمُتَغيِّرات من ذلك النوع. في الواقع، تَتضمَّن واجهة نوع الدالة (functional interface) قالبًا (template) لبرنامج فرعي وحيد، وينبغي لتعبير لامدا (lambda expression) المُسنَد أن يَكُون مُتطابِقًا مع ذلك القالب.
</p>

<h2>
	تعبيرات لامدا (lambda Expressions)
</h2>

<p>
	يُعدّ أي تعبير لامدا (lambda expression) تمثيلًا لبرنامج فرعي مجهول الاسم (anonymous subroutine)، أيّ لا يَمتلك اسمًا، ولكنه في المقابل، وكأيّ برنامج فرعي، لديه قائمة من المُعامِلات الصُّوريّة (formal parameter list)، بالإضافة إلى التعريف (definition) نفسه، ويُكتَب عمومًا بالصيغة (syntax) التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_19" style="">
<span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">parameter</span><span class="pun">-</span><span class="typ">list</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">  </span><span class="pun">-&gt;</span><span class="pln">  </span><span class="pun">{</span><span class="pln"> </span><span class="str">&lt;statements&gt;</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	كما هو الحال مع البرامج الفرعية العادية، يُمكِن لقائمة المُعامِلات <strong><parameter-list></parameter-list></strong> -بالأعلى- أن تَكُون فارغة، أو قد تتكوَّن من تَّصْريح عن مُعامِل (parameter declaration) وحيد أو أكثر، بحيث يُفصَل بين كل تَّصْريح والذي يليه بفاصلة (comma)، وبحيث يَتكوَّن كل تَّصْريح من نوع المُعامِل متبوعًا باسمه. في الواقع، تُبسَّط عادة تلك الصيغة وفقًا لمجموعة من القواعد: أولًا: يُمكِن حَذْف أنواع المُعامِلات إذا كان استنباطها من السِّياق مُمكِنًا. على سبيل المثال، إذا كان هناك تعبير لامدا مُعرَّف على أنه من النوع <code>FunctionR2R</code>، فإن مُعامِل التعبير لابُدّ وأن يَكُون من النوع <code>double</code>، ولذلك فإنه، في تلك الحالة، ليس من الضروري تَخْصيص نوع المُعامِل ضِمْن تعبير اللامدا. ثانيًا، يُمكِن حَذْف الأقواس <code>()</code> حول قائمة المُعامِلات (parameter list) إذا كانت مُكوَّنة من مُعامِل وحيد غَيْر مُحدَّد النوع. ثالثًا، يُمكِن حَذْف الأقواس <code>{}</code> الموجودة على الجانب الأيمن من العَامِل <code>‎-&gt;‎</code> إذا كانت تَحتوِي على تَعْليمَة استدعاء برنامج فرعي (subroutine call) وحيدة. أخيرًا، إذا كان الجانب الأيمن من العَامِل <code>‎-&gt;‎</code> مكتوبًا بالصيغة <code>{ return &lt;expression&gt;;‎ }</code>، فيُمكِن تبسيطها إلى التعبير <strong><expression></expression></strong> وحَذْف أي شيء آخر.
</p>

<p>
	بفَرْض أننا نريد كتابة دالة لحِسَاب مربع القيم من النوع <code>double</code>، فإن نوع تلك الدالة هو من نفس نوع واجهة نوع الدالة <code>FunctionR2R</code> المُعرَّفة بالأعلى. الآن، إذا كان <code>sqr</code> مُتَغيِّرًا من النوع <code>FunctionR2R</code>، فإننا نستطيع أن نُسنِد تعبير لامدا (lambda expression) كقيمة لذلك المُتَغيِّر، ويُعدّ عندها ذلك التعبير تمثيلًا للدالة المطلوبة. يُمكِن القيام بذلك بأي من الصِيَغ التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_21" style="">
<span class="pln">sqr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">double</span><span class="pln"> x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x</span><span class="pun">;</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
sqr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x</span><span class="pun">;</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
sqr </span><span class="pun">=</span><span class="pln"> x </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x</span><span class="pun">;</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
sqr </span><span class="pun">=</span><span class="pln"> x </span><span class="pun">-&gt;</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
sqr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">double</span><span class="pln"> fred</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> fred</span><span class="pun">*</span><span class="pln">fred</span><span class="pun">;</span><span class="pln">
sqr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">z</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> z</span><span class="pun">*</span><span class="pln">z</span><span class="pun">;</span></pre>

<p>
	تُعرِّف تعبيرات لامدا (lambda expressions) الستة بالأعلى نفس الدالة بالضبط، وأُضيفت آخر تَعْليمَتين (statements) خصيصًا؛ للتأكيد على أن أسماء المُعامِلات غير مهمة، فهى بالنهاية مجرد مُعامِلات وهمية أو صُّوريّة (dummy parameters). لمّا كان المُصرِّف (compiler) على علم بكون المُتَغيِّر <code>sqr</code> من النوع <code>FunctionR2R</code>، ولأن النوع <code>FunctionR2R</code> يتطلَّب مُعامِلًا من النوع <code>double</code>، فقد تَمَكَّنا من حَذْف نوع المُعامِل <code>double</code>. يُمكِن اِستخدَام تعبيرات لامدا فقط ضِمْن السِّياقات التي يستطيع فيها المُصرِّف (compiler) استنباط نوعها، ولذلك لابُدّ من كتابة نوع المُعامِل إذا كان حَذْفه سيَتسبَّب بغموض نوع التعبير.
</p>

<p>
	لا يُعدّ المُتَغيِّر <code>sqr</code> -كما هو مُعرَّف بالأعلى- دالة (function) تمامًا، وإنما هو قيمة من النوع <code>FunctionR2R</code>، وبحسب ما هو مُخصَّص بتعريف الواجهة (interface definition)‏ <code>FunctionR2R</code>، فإن ذلك المُتَغيِّر لابُدّ وأن يَحتوِي على دالة تَحمِل اسم <code>valueAt</code>. يمكن استدعاء تلك الدالة من خلال اسمها الكامل <code>sqr.valueAt</code>، فمثلًا يُمكِن كتابة <code>sqr.valueAt(42)‎</code> أو <code>sqr.valueAt(x) + sqr.valueAt(y)‎</code>.
</p>

<p>
	إذا كانت قائمة مُعامِلات تعبير لامدا مُكوَّنة من أكثر من مُعامِل واحد، فإن الأقواس <code>()</code> المُحيطة بقائمة المُعامِلات (parameters list) لم تَعُدْ اختيارية. اُنظر المثال التالي، والذي يَستخدِم واجهة نوع الدالة <code>ArrayProcessor</code>، كما يُبيِّن طريقة كتابة تعبير لامدا عندما يكون تعريفها مُتعدِّد الأسطر (multiline definition):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_23" style="">
<span class="typ">ArrayProcessor</span><span class="pln"> concat</span><span class="pun">;</span><span class="pln">
concat </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// الأقواس هنا مطلوبة</span><span class="pln">
    </span><span class="typ">String</span><span class="pln"> str</span><span class="pun">;</span><span class="pln">
    str </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> n</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
        str </span><span class="pun">+=</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">str</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">  </span><span class="com">// الفاصلة المنقوطة هنا ليست جزءًا من تعبير لامدا</span><span class="pln">
    </span><span class="com">// وإنما تشير إلى انتهاء تعليمة الإسناد</span><span class="pln">

</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> nums</span><span class="pun">;</span><span class="pln">
nums </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">String</span><span class="pun">[</span><span class="lit">4</span><span class="pun">];</span><span class="pln">
nums</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"One"</span><span class="pun">;</span><span class="pln">
nums</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Two"</span><span class="pun">;</span><span class="pln">
nums</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Three"</span><span class="pun">;</span><span class="pln">
nums</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Four"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> nums</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   concat</span><span class="pun">.</span><span class="pln">process</span><span class="pun">(</span><span class="pln"> nums</span><span class="pun">,</span><span class="pln"> i </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	مما سينتج عنه الخَرْج التالي:
</p>

<pre class="ipsCode">
One
OneTwo
OneTwoThree
OneTwoThreeFour
</pre>

<p>
	تُصبِح الأمور أكثر تشويقًا عند تمرير تعبير لامدا كمُعامِل فعليّ (actual parameter)، وهو في الواقع الاِستخدَام الأكثر شيوعًا لتعبيرات لامدا. افترض أن لدينا الدالة التالية مثلًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_25" style="">
<span class="com">/** 
 * احسب قيمة التعبير‫ f(start) + f(start+1) + ... + f(end)
 * حيث‫ f عبارة عن دالة تُستقبل كمعامل
 * ‫قيمة المعامل end لابد أن تكون أكبر من أو تساوي start
 */</span><span class="pln">
</span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> sum</span><span class="pun">(</span><span class="pln"> </span><span class="typ">FunctionR2R</span><span class="pln"> f</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> start</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> end </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">double</span><span class="pln"> total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n </span><span class="pun">=</span><span class="pln"> start</span><span class="pun">;</span><span class="pln"> n </span><span class="pun">&lt;=</span><span class="pln"> end</span><span class="pun">;</span><span class="pln"> n</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        total </span><span class="pun">=</span><span class="pln"> total </span><span class="pun">+</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">valueAt</span><span class="pun">(</span><span class="pln"> n </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> total</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لمّا كانت <code>f</code> من النوع <code>FunctionR2R</code>، فإن قيمة <code>f</code> عند <code>n</code> تُكتَب على الصورة <code>f.valueAt(n)‎</code>. يُمكِن تمرير تعبير لامدا (lambda expression) كقيمة للمُعامِل الأول عند استدعاء الدالة <code>sum</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_27" style="">
<span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"The sum of n squared for n from 1 to 100 is "</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> sum</span><span class="pun">(</span><span class="pln"> x </span><span class="pun">-&gt;</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"The sum of 2 raised to the power n, for n from 1 to 10 is "</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> sum</span><span class="pun">(</span><span class="pln"> num </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">pow</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln">num</span><span class="pun">),</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	كمثال آخر، افترض أن لدينا برنامجًا فرعيًا (subroutine) ينبغي أن يُنفِّذ مُهِمّة (task) مُعطاة عدة مرات، يُمكِننا ببساطة تمرير تلك المُهِمّة كمُعامِل من النوع <code>Runnable</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_29" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> doSeveralTimes</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Runnable</span><span class="pln"> task</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> repCount </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> repCount</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        task</span><span class="pun">.</span><span class="pln">run</span><span class="pun">();</span><span class="pln">  </span><span class="com">// نفذ المهمة</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستطيع الآن طباعة السِلسِلة النصية "Hello World" عشر مرات باستدعاء التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_31" style="">
<span class="pln">doSeveralTimes</span><span class="pun">(</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Hello World"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	تَتَكوَّن قائمة مُعامِلات (parameter list) تعبيرات لامدا من النوع <code>Runnable</code> من زوج فارغ من الأقواس <code>()</code>؛ وذلك لتتماشى مع البرنامج الفرعي المُصرَّح عنه ضِمْن واجهة نوع الدالة <code>Runnable</code>.
</p>

<p>
	اُنظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_33" style="">
<span class="pln">doSeveralTimes</span><span class="pun">(</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="typ">int</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">21</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln"> 
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> count</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span></pre>

<p>
	على الرغم من أن الشيفرة بالأعلى قد تبدو معقدة نوعًا ما، إلا أنها، في الواقع، مُكوَّنة من تَعْليمَة وحيدة هي تَعْليمَة استدعاء البرنامج الفرعي <code>doSeveralTimes</code>. يَتَكوَّن مُعامِل البرنامج الفرعي الأول من تعبير لامدا (lambda expression) قد امتد تعريفه إلى عدة أسطر، أما مُعامِله الثاني فهو القيمة ١٠٠، وتُنهِي الفاصلة المنقوطة (semicolon) بنهاية آخر سطر تَعْليمَة استدعاء البرنامج الفرعي (subroutine call).
</p>

<p>
	اطلعنا على عدة أمثلة تُسنَد فيها تعبيرات لامدا (lambda expression) إلى مُتَغيِّرات، وآخرى تُمرَّر فيها تعبيرات لامدا كمُعامِلات فعليّة (actual parameter). تَبَقَّى الآن أن نراها مُستخدَمة كقيمة مُعادة (return value) من دالة. اُنظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_35" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="typ">FunctionR2R</span><span class="pln"> makePowerFunction</span><span class="pun">(</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> n </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> x </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">pow</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln">n</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وبالتالي، ستُعيد <code>makePowerFunction(2)</code>‎ قيمة من النوع <code>FunctionR2R</code> تَحسِب مربع قيمة المُعامِل المُمرَّر، بينما ستُعيد <code>makePowerFunction(10)</code>‎ قيمة من النوع <code>FunctionR2R</code> تَحسِب قيمة المُعامِل المُمرَّر مرفوعًا للأس ١٠. يُوضِح هذا المثال أيضًا أن تعبيرات لامدا (lambda expression) تستطيع اِستخدَام مُتَغيِّرات آخرى إلى جانب مُعامِلاتها، مثل <code>n</code> في المثال بالأعلى. (في الواقع هناك بعض القيود لتَحْدِيد متى يُمكِن القيام بذلك).
</p>

<h2>
	مراجع التوابع (Method References)
</h2>

<p>
	لنفْترِض أننا نريد كتابة تعبير لامدا (lambda expression) من النوع <code>FunctionR2R</code>، بحيث يُمثِل دالة تَحسِب الجذر التربيعي. نستطيع كتابته على الصورة <code>x -&gt; Math.sqrt(x)‎</code>، ولكننا إذا دققنا النظر، سنَجِدْ أن تعبير لامدا، في تلك الحالة تحديدًا، ليس سوى مجرد مُغلِّف (wrapper) بسيط للدالة <code>Math.sqrt</code> الموجودة بالفعل. ولهذا تُوفِّر الجافا ما يُعرَف باسم مَراجِع التوابع (method reference)؛ لاِستخدَامها في الحالات المشابهة (تَذَكَر أن "التابع [method]" هو مجرد كلمة آخرى للإشارة إلى "البرنامج الفرعي [subroutine]" بلغة الجافا). نستطيع مثلًا اِستخدَام المَرجِع التابعي <code>Math::sqrt</code>، والذي يُعدّ اختصارًا لتعبير اللامدا المذكور سلفًا، أينما أَمْكَن اِستخدَام تعبير اللامدا المناظر، كتمريره مثلًا كمُعامِل للدالة <code>sum</code> المُعرَّفة بالأعلى، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_37" style="">
<span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"The sum of the square root of n for n from 1 to 100 is "</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> sum</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">::</span><span class="pln">sqrt</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	فقط لو أَمْكَننا اِستخدَام الاسم <code>Math.sqrt</code> هنا بدلًا من الاستعانة بترميز (notation) جديد <code>::</code>! في الواقع، الترميز <code>Math.sqrt</code> مُعرَّف بالفعل ضِمْن الصَنْف <code>Math</code> لكن للإشارة إلى مُتَغيِّر اسمه <code>sqrt</code>. يُمكِن عمومًا اِستخدَام مَراجِع التوابع (method reference) بدلًا من تعبيرات لامدا (lambda expression) التي يَقْتصِر دورها على اِستدعاء أحد التوابع الساكنة (static method) الموجودة مُسْبَّقًا. تُكتَب مَراجِع التوابع على الصورة التالية:
</p>

<pre class="ipsCode">
&lt;classname&gt;::&lt;method-name&gt;
</pre>

<p>
	لا يَقْتصِر هذا الترميز (notation) على التوابع الساكنة، أي تلك المُنتمية للأصناف (classes)، وإنما يَمْتَدّ إلى تلكم المُنتمية للكائنات (objects) كذلك. على سبيل المثال، إذا كان <code>str</code> متغير من النوع <code>String</code>، فإن <code>str</code> بطبيعة الحال سيَحتوِي على التابع <code>str.length()‎</code>، وفي هذه الحالة، يُمكِن اِستخدَام المَرجِع التابعي <code>str::length</code> كتعبير لامدا من واجهة نوع الدالة <code>SupplyInt</code> المُعرَّفة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8810_39" style="">
<span class="kwd">public</span><span class="pln"> interface </span><span class="typ">SupplyInt</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> get</span><span class="pun">(</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c4/s5.html" rel="external nofollow">Section 5: Lambda Expressions</a> من فصل Chapter 4: Programming in the Large I: Subroutines من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1090</guid><pubDate>Sun, 13 Dec 2020 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x642;&#x64A;&#x645; &#x627;&#x644;&#x645;&#x639;&#x627;&#x62F;&#x629; &#x645;&#x646; &#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D9%82%D9%8A%D9%85-%D8%A7%D9%84%D9%85%D8%B9%D8%A7%D8%AF%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1089/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_12/26.png.eb5c02e49f6cfaeef7405b025c869e58.png" /></p>

<p>
	يُطلَق على البرامج الفرعية (subroutine) التي تُعيد قيمة اسم "الدوال (function)"، والتي يُمكِنها أن تُعيد قيمة من نوع واحد مُحدَّد ضِمْن التعريف ويُسمى النوع المُعاد (return type) من الدالة. بإِمكَانك استدعاء الدوال (function call) في العموم بأيّ مكان يَتوقَّع فيه الحاسوب قيمة (value)، مثل الجانب الأيمن من تَعْليمَات الإِسْناد (assignment statement)، أو كمُعامِل فعليّ (actual parameter) بتَعْليمَات استدعاء البرامج الفرعية، أو كجُزء من تعبير (expression) أكبر. يُمكِن حتى اِستخدَام الدوال من النوع <code>boolean</code>، أي التي تُعيد قيمة من ذلك النوع، مَحل الشَّرْط (condition) ضِمْن تَعْليمَات مثل <code>if</code> و <code>while</code> و <code>for</code> و <code>do..while</code>.
</p>

<p>
	يُمكِن أيضًا اِستخدَام تَعْليمَة استدعاء دالة (function call)، كما لو كانت برنامجًا فرعيًا، أيّ كما لو أنها لا تُعيد قيمة. في تلك الحالة، يَتجاهَل الحاسوب القيمة المُعادة من البرنامج الفرعي، وهو ما يَكُون منطقيًا في بعض الأحيان. على سبيل المثال، تَقرأ الدالة <code>TextIO.getln()‎</code> سَطْرًا مُدْخَلًا مِنْ قِبَل المُستخدِم وتُعيده كقيمة من النوع <code>String</code>. عادة، يُسنَد السَطْر المُعاد من تلك الدالة إلى مُتَغيِّر؛ لكي يُستخدَم لاحقًا، كما في التَعْليمَة <code>name = TextIO.getln();‎</code>. لكن، يُمكِن اِستخدَام تلك الدالة ضِمْن تَعْليمَة استدعاء برنامج فرعي على الصورة <code>TextIO.getln();‎</code>، والتي، كالعادة، ستَستمِر بقراءة مُدْخَلات المُستخدِم إلى أن تَصِل إلى محرف العودة إلى بداية السطر (carriage return). لمّا لم تُسنَد القيمة المُعادة من تلك الدالة إلى مُتَغيِّر، أو تُستخدَم ضِمْن تعبير (expression)، فإنها تُستبعَد ببساطة، لذا يَكُون تأثير استدعاء البرنامج الفرعي في تلك الحالة هو مجرد قراءة بعض المُدْخَلات واِستبعَادها، وهو الشيء الذي قد تَرغَب به في بعض الأحيان.
</p>

<h2>
	تعليمة <code>return</code>
</h2>

<p>
	بوصولك إلى هنا، فأنت قد تَعلَّمت طريقة استدعاء الدوال (functions) -التي تُعيد قيم فعليّة- مثل <code>Math.sqrt()‎</code> و <code>TextIO.getInt()‎</code>، لكنك لَمْ تَكتُب أيّ دالة خاصة بك بَعْد. في الواقع، ستبدو كتابة الدوال أمرًا مألوفًا بالنسبة لك؛ فهي بالنهاية مُشابهة تمامًا لصيغة كتابة أيّ برنامج فرعي (subroutine) عادي باستثناء ضرورة اِستخدَام التَعْليمَة <code>return</code>؛ لتَخْصِيص القيمة التي سيُعيدها البرنامج الفرعي (return value). تُكتَب تَعْليمَة <code>return</code> بالصيغة (syntax) التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_7" style="">
<span class="kwd">return</span><span class="pln"> </span><span class="str">&lt;expression&gt;</span><span class="pun">;</span></pre>

<p>
	يُمكِن اِستخدَام تَعْليمَة <code>return</code> بالأعلى داخل تعريف الدوال فقط (function definition)، ولابُدّ لنوع التعبير <strong><expression></expression></strong> المَكْتُوب بَعْد التَعْليمَة أن يَتماشى مع النوع المُعاد (return type) المُخصَّص ضِمْن تعريف الدالة، أيّ لابُدّ أن يؤول ذلك التعبير إلى قيمة هي من نوع يُمكِن إِسْناده -بواسطة تَعْليمَة إِسْناد (assignment)- إلى النوع المُعاد (return type) من الدالة والمُخصَّص بتعريفها (definition).
</p>

<p>
	عندما يُنفِّذ الحاسوب تَعْليمَة <code>return</code>، فإنه يَحسِب قيمة التعبير المُخصَّص، ثم يُنهِي تَّنْفيذ الدالة، وأخيرًا، يُعيد قيمة التعبير لتُصبِح القيمة المُعادة (return value) من الدالة. اُنظر تعريف الدالة التالي على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_9" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> pythagoras</span><span class="pun">(</span><span class="kwd">double</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln">  </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">sqrt</span><span class="pun">(</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> y</span><span class="pun">*</span><span class="pln">y </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بفَرْض تَّنْفيذ الحاسوب لتَعْليمَة إِسْناد تَتضمَّن تَعْليمَة استدعاء الدالة بالأعلى، مثل <code>totalLength = 17 + pythagoras(12,5);‎</code>، فإنه سيُحاوِل تَحْصِيل قيمة تَعْليمَة الاستدعاء <code>pythagoras(12,5)</code>‎، لذلك سيبدأ بإِسْناد قيم المُعامِلات الفعليّة (actual parameters) ‏المُمرَّرة، أيّ ١٢ و ٥، إلى المُعامِلات الصُّوريّة (formal parameters)‏ <code>x</code> و <code>y</code> بتعريف الدالة، ثم سينتقل إلى تَّنْفيذ مَتْن الدالة (function body)، وبالتالي سيضطرّ إلى تَحْصِيل قيمة التعبير <code>Math.sqrt(12.0*12.0 + 5.0*5.0)</code>‎ والتي تؤول إلى القيمة <code>13.0</code>، ثم سيُعيد هذه القيمة لتَكُون القيمة المُعادة (return value) من الدالة، وعليه تُستبدَل القيمة <code>13.0</code> بتَعْليمَة استدعاء الدالة، فتصبح تَعْليمَة الإِسْناد وكأنها مَكْتُوبة على الصورة <code>totalLength = 17+13.0</code>. أخيرًا، تُضاف القيمة المُعادة (return value) إلى العدد <code>17</code> ثم تُخْزَن النتيجة <code>30.0</code> بالمُتَغيِّر <code>totalLength</code>.
</p>

<p>
	لاحظ أنه وبينما تُنفَّذ الدالة، فإنك قد تَتَمكَّن من تَحْصِيل القيمة المُفْترَض إعادتها منها، وفي تلك الحالة، تستطيع اِستخدَام تَعْليمَة <code>return</code>؛ لإعادة تلك القيمة مباشرة، ومِنْ ثَمَّ تَخَطِّي أية تَعْليمَات آخرى بمَتْن الدالة، دون الحاجة إلى الانتظار إلى نهاية المَتْن، أيّ أنه ليس من الضروري أن تَكُون تَعْليمَة <code>return</code> هي آخر تَعْليمَة بمَتْن الدالة، بل يُمكِن اِستخدَامها بأي مكان ضِمْن المَتْن. ولكن، لابُدّ دائمًا من إعادة قيمة ما من الدالة وذلك بجميع مسارات التَّنْفيذ المُحتمَلة التي قد تَتَّخذها الدالة.
</p>

<p>
	كما ذَكَرَنا مُسْبَّقًا، لابُدّ دائمًا من كتابة تَعْليمَة <code>return</code> مَتبوعة بتعبير (expression) ضِمْن تعريف أي دالة (function)؛ لأن الدوال دائمًا ما تُعيد قيمة. في المقابل، لا يُعدّ ذلك ضروريًا مع البرامج الفرعية من غير الدوال (non-function)، أي تلك التي تَستخدِم <code>void</code> ضِمْن تعريفها للتَّصْريح عن نوعها المُعاد، فهي في النهاية لا تُعيد قيمة، ومع ذلك يَظِلّ اِستخدَام تَعْليمَة <code>return</code> ضِمْن هذا السِّياق مُمكنًا، بحيث يَقْتصِر دورها على إنهاء تَّنْفيذ البرنامج الفرعي بمكان ما وسط المَتْن وإعادة التَحكُّم (return control) مرة آخرى إلى سَطْر الشيفرة المسئول عن استدعاء البرنامج الفرعي. تُكتَب تَعْليمَة <code>return</code> في تلك الحالة على الصورة <code>return;</code>‎ بدون تعبير (expression).
</p>

<p>
	بالإضافة إلى ما سبق، قد تُستخدَم تَعْليمَة <code>return</code> أيضًا داخل حَلْقة تَكْرار (loop) لإنهاء كُلًا من الحَلْقة (loop) والبرنامج الفرعي الحاضن لها. بالمثل، قد تُستخدَم بتَعْليمَة <code>switch</code>، للخروج من كُلًا من تَعْليمَة <code>switch</code> والبرنامج الفرعي الحاضن لها، أيّ ستَجِدْ أحيانًا تَعْليمَة <code>return</code> مُستخدَمة ضِمْن سِّياقات اعْتَدْت فيها استخدام تَعْليمَة <code>break</code>.
</p>

<h2>
	أمثلة على الدوال (functions)
</h2>

<p>
	تَعرَّضنا لمسألة حِسَاب قيم عناصر مُتتالية الأعداد"3N+1" عدة مرات بما في ذلك القسم السابق. يُمكِننا تعريف دالة (function) بسيطة جدًا، تَستقبِل قيمة العنصر الحالي بالمُتتالية، ثم تُعيد قيمة عنصر المتتالية التالي. اُنظر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_11" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> nextN</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> currentN</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentN </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">     </span><span class="com">// ‫إذا كان currentN فرديًا</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">3</span><span class="pun">*</span><span class="pln">currentN </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">  </span><span class="com">// أعد تلك القيمة</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> currentN </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">    </span><span class="com">// إذا لم يكن، أعد تلك القيمة</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نُلاحِظ أن تعريف الدالة بالأعلى يَتضمَّن تَعْليمَتي <code>return</code>. ستُنفَّذ دائمًا تَعْليمَة <code>return</code> واحدة فقط بِغَضّ النظر عن عدد تلك التَعْليمَات المُستخدَمة ضِمْن التعريف. يُفضِّل بعض المبرمجين كتابة تَعْليمَة <code>return</code> وحيدة بنهاية الدالة، ويحاولوا القيام بذلك قدر الإمكان؛ خاصة وأن ذلك يُسهِل من العثور على تَعْليمَة <code>return</code> ضِمْن التعريف. فمثلًا، يُمكِننا إعادة كتابة الدالة <code>nextN()‎</code> -المُعرَّفة بالأعلى- مرة آخرى على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_13" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> nextN</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> currentN</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> answer</span><span class="pun">;</span><span class="pln">  </span><span class="com">// متغير يحمل القيمة المعادة من الدالة</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentN </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">    </span><span class="com">// ‫إذا كان currentN فرديًا</span><span class="pln">
        answer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">*</span><span class="pln">currentN</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> </span><span class="com">// أسند القيمة إلى المتغير</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
        answer </span><span class="pun">=</span><span class="pln"> currentN </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> </span><span class="com">// إذا لم يكن، أسند القيمة إلى المتغير</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> answer</span><span class="pun">;</span><span class="pln">   </span><span class="com">// لا تنسى أن تعيد المتغير</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	دَعْنَا الآن نَكتُب برنامجًا فرعيًا (subroutine) لحِسَاب قيم عناصر المُتتالية، لكن بالاعتماد على الدالة <code>nextN</code> هذه المرة. نظرًا لكَوْن الدالة <code>nextN</code> قصيرة نوعًا ما، فإن التَحْسِينات المُجراة على البرنامج الفرعي ليست ذا شأن بالموازنة مع نسخة البرنامج بالقسم ٤.٣. في المقابل، إذا كانت الدالة <code>nextN()</code>‎ طويلة لكَوْنها مثلًا تَحسِب عملية معقدة، فعندها سيَكُون من المنطقي إخفاء ذلك التعقيد بداخل دالة منفصلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_15" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> print3NSequence</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> startingValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

   </span><span class="typ">int</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">       </span><span class="com">// أحد عناصر المتتالية</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">   </span><span class="com">// عدد عناصر المتتالية</span><span class="pln">

   N </span><span class="pun">=</span><span class="pln"> startingValue</span><span class="pun">;</span><span class="pln">   </span><span class="com">// أول قيمة بالمتتالية</span><span class="pln">
   count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The 3N+1 sequence starting from "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> N</span><span class="pun">);</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">N</span><span class="pun">);</span><span class="pln">  

   </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="com">// ‫احسب قيمة عنصر المتتالية التالي باستدعاء الدالة nextN</span><span class="pln">
       N </span><span class="pun">=</span><span class="pln"> nextN</span><span class="pun">(</span><span class="pln"> N </span><span class="pun">);</span><span class="pln">   
       count</span><span class="pun">++;</span><span class="pln">          </span><span class="com">// أزد عدد عناصر المتتالية بمقدار الواحد</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">N</span><span class="pun">);</span><span class="pln">  </span><span class="com">// اطبع قيمة العنصر</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"There were "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> count </span><span class="pun">+</span><span class="pln"> </span><span class="str">" terms in the sequence."</span><span class="pun">);</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	اُنظر المثال التالي للدالة <code>letterGrade</code>، والتي تَستقبِل درجة عددية (numerical grade)، وتُحوِّلها إلى نظيرتها المحرفية (letter grade) بالاستعانة بمقياس درجات (grading scale) تقليدي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_17" style="">
<span class="com">/**
 * أعد الدرجة المحرفية المناظرة للدرجة العددية الممررة للدالة كمعامل
 */</span><span class="pln">
</span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> letterGrade</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> numGrade</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">numGrade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">90</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'A'</span><span class="pun">;</span><span class="pln">   </span><span class="com">// 90 or above gets an A</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">numGrade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">80</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'B'</span><span class="pun">;</span><span class="pln">   </span><span class="com">// 80 to 89 gets a B</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">numGrade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'C'</span><span class="pun">;</span><span class="pln">   </span><span class="com">// 65 to 79 gets a C</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">numGrade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">50</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'D'</span><span class="pun">;</span><span class="pln">   </span><span class="com">// 50 to 64 gets a D</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'F'</span><span class="pun">;</span><span class="pln">   

</span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية الدالة letterGrade</span></pre>

<p>
	تستطيع الدوال أن تُعيد قيم من أي نوع، فمثلًا، نوع القيمة المُعادة (return type) من الدالة <code>letterGrade()‎</code> -بالأعلى- هو النوع <code>char</code>، أما الدالة المُعرَّفة بالمثال التالي، فإنها تُعيد قيمة (return value) من النوع <code>boolean</code>. اُنظر الشيفرة التالية، واحْرِصْ على قراءة التعليقات (comments)؛ لأنها تُوضِح بعض النقاط المثيرة للاهتمام:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_19" style="">
<span class="com">/**
 * تعيد هذه الدالة القيمة المنطقية‫ true إذا كان N عدد أولي.
 * ‫العدد الأولي هو عدد صحيح أكبر من العدد 1 
 * بشرط ألا يكون قابلًا للقسمة ‫إلا على  نفسه وعلى الواحد. 
 * Nإذا كان لدى‫ N أي قاسم D يتراوح بين الواحد والعدد  
 * ‫فسيكون لديه قاسم يتراوح بين العدد 2 والجذر التربيعي للعدد N 
 * ‫لذلك سوف نختبر قيم القواسم المحتملة بداية من العدد 2 
 * ‫وحتى الجذر التربيعي للعدد N
 */</span><span class="pln">
</span><span class="kwd">static</span><span class="pln"> boolean isPrime</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> N</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="typ">int</span><span class="pln"> divisor</span><span class="pun">;</span><span class="pln">  </span><span class="com">// عدد يحتمل أن يكون قاسما للعدد </span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">  </span><span class="com">// العدد الأولي لابد أن يكون أكبر من الواحد</span><span class="pln">

    </span><span class="typ">int</span><span class="pln"> maxToTry</span><span class="pun">;</span><span class="pln">  </span><span class="com">// أكبر قيمة قاسم محتمل ينبغي اختبارها</span><span class="pln">

    </span><span class="com">// ‫ينبغي إجراء عملية التحويل بين الأنواع لأن Math.sqrt </span><span class="pln">
    </span><span class="com">// ‫تعيد قيمة من النوع double</span><span class="pln">
    maxToTry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">sqrt</span><span class="pun">(</span><span class="pln">N</span><span class="pun">);</span><span class="pln">

    </span><span class="com">// ‫سنحاول قسمة‫ N على الأعداد من 2 ووصولا الى قيمة maxToTry</span><span class="pln">
    </span><span class="com">// إذا لم يكن‫ N قابل للقسمة على أي عدد من تلك الأعداد</span><span class="pln">
    </span><span class="com">// ‫سيكون N عددا اوليا</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">divisor </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> divisor </span><span class="pun">&lt;=</span><span class="pln"> maxToTry</span><span class="pun">;</span><span class="pln"> divisor</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">%</span><span class="pln"> divisor </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">  </span><span class="com">// ‫إذا تمكن divisor من تقسم N</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">         </span><span class="com">// ‫إذًا N لا يمكن أن يكون عددًا أوليًا</span><span class="pln">
            </span><span class="com">// لا حاجة للاستمرار</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">// ‫إذا وصلنا إلى هنا، فإن N حتما هو عدد أولي</span><span class="pln">
    </span><span class="com">// ‫لأنه إذا لم يكن أوليًا، ستكون الدالة بالفعل قد انتهت</span><span class="pln">
    </span><span class="com">// ‫باستخدام تعليمة return الموجودة بالحلقة السابقة</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫نعم N هو عدد أولي</span><span class="pln">

</span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية الدالة isPrime</span></pre>

<p>
	نَسْتَعْرِض بالشيفرة التالية دالة آخرى، والتي تَستقبِل مُعامِل (parameter) من النوع <code>String</code>، وتُعيد قيمة (return value) من نفس النوع <code>String</code>. تَعْكِس تلك الدالة ترتيب محارف السِلسِلة النصية المُمرَّرة، وتُعيد نسخة مَعْكوسة منها، فمثلًا، النسخة المَعْكوسة من السِلسِلة النصية "Hello World" هي "dlroW olleH". يُمكِن توصيف الخوارزمية (algorithm) المطلوبة لعَكْسَ سِلسِلة نصية <code>str</code> على النحو التالي: ابدأ بسِلسِلة نصية فارغة (empty string)، ثم أَضِف إلى نهايتها كل محرف (character) موجود بالسِلسِلة النصية <code>str</code>، بحيث تبدأ بالمحرف الأخير من السِلسِلة <code>str</code>، وتعود للوراء حتى تَصِل إلى المحرف الأول. اُنظر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_21" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> reverse</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">String</span><span class="pln"> copy</span><span class="pun">;</span><span class="pln">  </span><span class="com">// النسخة المعكوسة</span><span class="pln">
    </span><span class="com">// الموضع الحالي من السلسلة النصية الممرة</span><span class="pln">
    </span><span class="com">// يأخذ القيم بداية من طول السلسلة وحتى صفر</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">        
    copy </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">    </span><span class="com">// ابدأ بسلسلة نصية فارغة</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">  i </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  i</span><span class="pun">--</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// أضف المحرف الحالي إلي نهاية النسخة المعكوسة</span><span class="pln">
        copy </span><span class="pun">=</span><span class="pln"> copy </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">  
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> copy</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحِظ أن بعض السَلاسِل النصية لا تتغَيَّر سواء قُرأت طردًا (forwards) أو عكسًا (backwards)، أي سواء قرأت من اليسار إلى اليمين أو العَكْس. يُعرَف ذلك باسم السِّياق المُتَناظِر أو القلب المستو (palindrome)، والذي يُمكِنك اختبار حُدُوثه على سِلسِلة نصية معينة <code>word</code> بالاستعانة بالدالة المُعرَّفة بالأعلى وباِستخدَام الاختبار <code>if (word.equals(reverse(word)))‎</code> تحديدًا.
</p>

<p>
	يقع كثير من المبتدئين، أثناء كتابتهم للدوال، بخطأ طباعة الإجابة بدلًا من إعادتها، وهو ما يُمثِل سوء فهم تام لماهية الدوال. إن مُهِمّة الدالة (function) ببساطة هو مجرد حِسَاب قيمة ما، ثم العودة مرة آخرى إلى سَطْر الشيفرة المسئول عن اِستدعاء الدالة، حيث ينبغي اِستخدَام القيمة المُعادة. قد يَطبَع ذلك السَطْر من الشيفرة تلك القيمة أو يُسنِدها إلى مُتَغيِّر أو يَستخدِمها ضِمْن تعبير (expression)، أو أي شيء آخر قد يَتطلَّبه البرنامج، المهم هنا هو أن تُدرِك أن أيًا كانت الطريقة التي سيُوظِّف بها المُستدعِي تلك القيمة المُعادة فهي بالنهاية أمر لا يَخُصّ الدالة.
</p>

<h2>
	مسألة متتالية "3N+1"
</h2>

<p>
	سنُحاوِل بالمثال الأخير من هذا القسم اِستخدَام الدالة <code>nextN()‎</code> التي عَرَفناها بالأعلى لتَعْديل البرنامج المسئول عن حِسَاب قيم عناصر المتتالية "3N+1". أُضيفَت بعض التَعْديلات الآخرى أيضًا، مثل طباعة قيم عناصر المتتالية بأعمدة، بحيث يَحتوِي كل سَطْر على ٥ عناصر فقط، مما سيُحسِن من هيئة الخَرْج الناتج عن البرنامج. تستطيع القيام بذلك ببساطة عن طريق الاحتفاظ بعدد العناصر المَطبوعة بالسَطْر الحالي، وبدء سَطْر خَرْج جديد عند وصول قيمة ذلك العدد إلى القيمة ٥. نُسِق الخَرْج بحيث تُصطَفَّ العناصر بأعمدة مُرتَّبة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6441_23" style="">
<span class="pln">input textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="com">/** 
 * برنامج يحسب قيم عناصر المتتالية ‫3N+1 ويطبعها. تُحدد قيمة 
 * أول عنصر بالمتتالية من قبل المستخدم، ثم تُطبع القيم بأعمدة 
 * ‫بحيث يحتوي كل سطر على 5 عناصر فقط.
 * كما تطبع عدد عناصر المتتالية بالنهاية
 */</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ThreeN2</span><span class="pln"> </span><span class="pun">{</span><span class="pln">


    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"This program will print out 3N+1 sequences"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"for starting values that you specify."</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">

        </span><span class="typ">int</span><span class="pln"> K</span><span class="pun">;</span><span class="pln">   </span><span class="com">// اقرأ مدخل المستخدم</span><span class="pln">
        </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter a starting value;"</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"To end the program, enter 0: "</span><span class="pun">);</span><span class="pln">
            K </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">  </span><span class="com">// اقرأ قيمة أول عنصر بالمتتالية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">K </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">              
                print3NSequence</span><span class="pun">(</span><span class="pln">K</span><span class="pun">);</span><span class="pln">
        </span><span class="com">// ‫اعد تكرار الحلقة إذا كان k أكبر من الصفر</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">K </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">           

    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية main</span><span class="pln">


    </span><span class="com">/**
    * يطبع‫ print3NSequence قيم المتتالية 3N+1 إلى الخرج القياسي، 
    * بحيث يكون أول عنصر بالمتتالية هو قيمة المعامل الممررة
    * كما يطبع أيضًا عدد عناصر المتتالية
    * ‫قيمة المعامل startingValue الممررة ينبغي أن تكون عددًا صحيحا موجبا
    */</span><span class="pln">
    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> print3NSequence</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> startingValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">int</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">       </span><span class="com">// أحد عناصر المتتالية</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">   </span><span class="com">// عدد العناصر حتى الآن</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> onLine</span><span class="pun">;</span><span class="pln">  </span><span class="com">// عدد العناصر المطبوعة بالسطر الحالي</span><span class="pln">

        N </span><span class="pun">=</span><span class="pln"> startingValue</span><span class="pun">;</span><span class="pln">   </span><span class="com">// ابدأ المتتالية بقيمة المعامل الممررة</span><span class="pln">
        count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">           </span><span class="com">// لدينا عنصر واحد بالمتتالية</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The 3N+1 sequence starting from "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> N</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"%8d"</span><span class="pun">,</span><span class="pln"> N</span><span class="pun">);</span><span class="pln"> 
        onLine </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">        </span><span class="com">// هناك عدد مطبوع بالسطر الآن</span><span class="pln">

        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            N </span><span class="pun">=</span><span class="pln"> nextN</span><span class="pun">(</span><span class="pln">N</span><span class="pun">);</span><span class="pln">  </span><span class="com">// احسب قيمة العنصر التالي</span><span class="pln">
            count</span><span class="pun">++;</span><span class="pln">   </span><span class="com">// أزد عناصر المتتالية بمقدار الواحد</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">onLine </span><span class="pun">==</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">  </span><span class="com">// اطبع محرف العودة الى بداية السطر</span><span class="pln">
                onLine </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">      </span><span class="com">// أعد ضبط عدد العناصر المطبوعة بالسطر</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"%8d"</span><span class="pun">,</span><span class="pln"> N</span><span class="pun">);</span><span class="pln">  </span><span class="com">// اطبع قيمة العنصر الحالي</span><span class="pln">
            onLine</span><span class="pun">++;</span><span class="pln">   </span><span class="com">// أزد قيمة عدد العنصر بالسطر بمقدار الواحد</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">  </span><span class="com">// انهي السطر الحالي من الخرج</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">  </span><span class="com">// اطبع سطر فارغ</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"There were "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> count </span><span class="pun">+</span><span class="pln"> </span><span class="str">" terms in the sequence."</span><span class="pun">);</span><span class="pln">

    </span><span class="pun">}</span><span class="pln">  </span><span class="com">// نهاية print3NSequence</span><span class="pln">


    </span><span class="com">/**
    * ‫تحسب الدالة nextN قيمة عنصر المتتالية التالي وتعيده
    * ‫بحيث تستقبل قيمة عنصر المتتالية الحالي كمعامل currentN
    */</span><span class="pln">
    </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> nextN</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> currentN</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentN </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> currentN </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> currentN </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية الدالة nextN</span><span class="pln">


</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف ThreeN2</span></pre>

<p>
	ينبغي أن تَقْرأ هذا البرنامج بتأنِّي وأن تُحاوِل اِستيعاب طريقة عَمَله.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c4/s4.html" rel="external nofollow">Section 4: Return Values</a> من فصل Chapter 4: Programming in the Large I: Subroutines من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1089</guid><pubDate>Thu, 10 Dec 2020 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x639;&#x627;&#x645;&#x644;&#x627;&#x62A; (parameters) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D9%85%D8%B9%D8%A7%D9%85%D9%84%D8%A7%D8%AA-parameters-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1088/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_12/25.png.19b08ee0d542fc7992b5cdfeea4b7925.png" /></p>

<p>
	إذا كان البرنامج الفرعي (subroutine) عبارة عن صندوق أسود، فإن المُعامِلات (parameter) هي ببساطة طريقة لتمرير بعض المعلومات إليه من العالم الخارجي، لذا فإنها تُعدّ جزءًا من واجهة (interface) البرنامج الفرعي، وتَسمَح لك بتَخْصيص طريقة عمل البرنامج الفرعي للتَكيُف مع موقف محدد.
</p>

<p>
	على سبيل المثال، إذا نظرنا لمنظم الحرارة كصندوق أسود، تتلخَّص مُهِمّته في الحفاظ على درجة حرارة معينة، فإن ذلك المنظم لديه مُعامِل، هو القرص، والذي يُستخدَم لتَخْصيص درجة الحرارة المطلوبة. سيُنفِّذ منظم الحرارة دائمًا نفس المُهِمّة، أيّ الحفاظ على درجة حرارة ثابتة، لكن قيمة درجة الحرارة تلك يُمكِن تَخْصيصها من خلال القرص.
</p>

<h2>
	استخدام المعاملات
</h2>

<p>
	سنتَطَرَّق مجددًا لمسألة متتالية الأعداد "3N+1"، والتي قد تَعرَّضنا لها بالقسم الفرعي ٣.٢.٢. تُحسَّب قيم مُتتالية الأعداد "3N+1" وفقًا للقاعدة التالية:
</p>

<p>
	"إذا كان <code>N</code> عَدَدًا فرديًا، اِحسب حاصل ضربه في العَدَد ٣، ثُمَّ أَزِد قيمة حاصل الضرب بمقدار ١، أمَا إذا كان زوجيًا، اِحسب حاصل قِسمته على العَدَد ٢، بحيث تستمر بحِسَاب قيم عناصر مُتتالية الأعداد بنفس الطريقة حتى تُصبِح قيمة <code>N</code> مُساوِية للعَدَد ١. على سبيل المثال، إذا كانت قيمة <code>N</code> المبدئية تُساوِي ٣، سنَحصُل على مُتتالية الأعداد التالية: ٣، ١٠، ٥، ١٦، ٨، ٤، ٢، ١."
</p>

<p>
	اُكْتُب برنامجًا فرعيًا (subroutine) يَطبَع قيم مُتتالية الأعداد تلك. لاحِظ أن دور البرنامج هو طباعة متتالية الأعداد "3N+1" في العموم، أي أن القيم ذاتها التي سيَطبَعها لابُدّ وأن تعتمد على قيمة <code>N</code> المبدئية، ولهذا سنُمرِّر تلك القيمة كمُعامِل (parameter) للبرنامج الفرعي. يُمكِن كتابة البرنامج الفرعي كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_7" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> print3NSequence</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> startingValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="typ">int</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">      </span><span class="com">// أحد قيم عناصر المتتالية</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">  </span><span class="com">// عدد عناصر المتتالية</span><span class="pln">

    N </span><span class="pun">=</span><span class="pln"> startingValue</span><span class="pun">;</span><span class="pln">  </span><span class="com">// أول عنصر هو القيمة الممررة</span><span class="pln">

    count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لدينا قيمة واحدة هي القيمة الممررة</span><span class="pln">

    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The 3N+1 sequence starting from "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> N</span><span class="pun">);</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">N</span><span class="pun">);</span><span class="pln">  

    </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// ‫إذا كان N عدد فردي</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">     
            N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> N </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln">
            N </span><span class="pun">=</span><span class="pln"> N </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
        count</span><span class="pun">++;</span><span class="pln">   </span><span class="com">// أزد عدد عناصر المتتالية بمقدار الواحد</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">N</span><span class="pun">);</span><span class="pln">  </span><span class="com">// اطبع العنصر</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"There were "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> count </span><span class="pun">+</span><span class="pln"> </span><span class="str">" terms in the sequence."</span><span class="pun">);</span><span class="pln">

</span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية print3NSequence</span></pre>

<p>
	تَتكوَّن قائمة المعاملات (parameter list) -بتعريف البرنامج الفرعي بالأعلى- من المُعامِل <code>int startingValue</code>، مما يَعنِي أن ذلك البرنامج الفرعي سيَستقبِل مُعامِلًا (parameter) وحيدًا من النوع العَدَدَي الصحيح <code>int</code>، وسيَتَمكَّنْ من اِستخدَام اسم ذلك المُعامِل بداخل المَتْن، بنفس الطريقة التي يَستخدِم بها اسم أيّ مُتَغيِّر آخر. لاحِظ أننا لم نُسنِد أي قيمة للمُعامِل أثناء عملية التعريف ذاتها، فهو يَحصُل على قيمته المبدئية من مصدر خارجي أثناء عملية الاستدعاء، لذا لابُدّ للمُستدعِي أن يُمرِّر قيمة معينة لذلك المُعامِل ضِمْن تَعْليمَة الاستدعاء (subroutine call statement)، وعندها فقط ستُسنَد إلى <code>startingValue</code> قبل تَّنْفيذ المَتْن. مثلًا، عندما يُنفِّذ الحاسوب تَعْليمَة استدعاء البرنامج الفرعي <code>print3NSequence(17);‎</code>، فإنه يُسنِد أولًا القيمة ١٧ إلى <code>startingValue</code>، ثم يُنفِّذ بَعْدها التَعْليمَات الموجودة بمَتْن ذلك البرنامج، والتي تَطبَع قيم مُتتالية الأعداد "3N+1" بداية من العدد ١٧. وبصورة أعم، إذا كان <code>K</code> مُتَغيِّرًا من النوع العَدََدَي الصحيح <code>int</code>، يُمكِن اِستخدَام التَعْليمَة <code>print3NSequence(K);‎</code> بهدف اِستدعاء البرنامج الفرعي، مما سيؤدي إلى إِسْناد قيمة المُتَغيِّر <code>K</code> إلى <code>startingValue</code>، ومِنْ ثَمَّ تَّنْفيذ مَتْن البرنامج الفرعي.
</p>

<p>
	يُمكِن اِستدعاء البرنامج الفرعي <code>print3NSequence</code> بواسطة أيّ برنامج فرعي -البرنامج <code>main()‎</code> أو غيره- مُعرَّف ضِمْن نفس الصَنْف المُتَضمِّن لتعريف البرنامج الفرعي <code>print3NSequence</code>. فمثلًا، يَطبَع البرنامج <code>main()</code>‎ -بالمثال التالي- قيم عناصر المُتتالية "3N+1" أكثر من مرة وبقيم مبدئية مختلفة، والتي تُخصَّص من قِبَل المُستخدِم:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_9" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"This program will print out 3N+1 sequences"</span><span class="pun">);</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"for starting values that you specify."</span><span class="pun">);</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> K</span><span class="pun">;</span><span class="pln">  </span><span class="com">// اقرأ مدخل المستخدم</span><span class="pln">
    </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter a starting value."</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"To end the program, enter 0: "</span><span class="pun">);</span><span class="pln">
        K </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getInt</span><span class="pun">();</span><span class="pln">  </span><span class="com">// اقرأ عنصر المتتالية الأول من المستخدم</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">K </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">   </span><span class="com">// اطبع المتتالية</span><span class="pln">
            print3NSequence</span><span class="pun">(</span><span class="pln">K</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">K </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">   </span><span class="com">// ‫إستمر إذا كانت قيمة k أكبر من الصفر</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// نهاية main</span></pre>

<p>
	تنبيه: لابُدّ أن يُعرَّف كُلًا من البرنامجين <code>main</code> و <code>print3NSequence</code> ضِمْن نفس الصَنْف؛ كي تتمكَّن من تَشْغِيل البرنامج بالأعلى.
</p>

<h2>
	المعاملات الصورية (formal) والفعلية (actual)
</h2>

<p>
	في الواقع، تُستخدَم كلمة "مُعامِل (parameter)" للإشارة إلى مفهومين، مُرتبطين نوعًا ما، لكنهما بالنهاية مختلفان. أولهما هو ذلك الذي نُشير إليه ضِمْن تعريفات البرامج الفرعية (definitions of subroutines)، مثل <code>startingValue</code> بالأعلى. والآخر هو ما نُشير إليه ضِمْن تَعْليمَات استدعاء البرامج الفرعية (subroutine call statements)، بحيث يُمرَّر إليها، مثل <code>K</code> بالتَعْليمَة <code>print3NSequence(K);‎</code>. يُطلَق على "المُعامِلات" من النوع الأول اسم المُعامِلات الصُّوريّة (formal parameters) أو المُعامِلات الوهمية (dummy parameters)، بينما يُطلَق على "المُعامِلات" من النوع الثاني اسم المُعامِلات الفعليّة (actual parameters) أو الوُسَطاء (arguments). عندما تَستدعِي برنامجًا فرعيًا، يُحصِّل الحاسوب قيم المُعامِلات الفعليّة بتَعْليمَة الاستدعاء، ثم يُسنِد تلك القيم إلى المُعامِلات الصُّوريّة المُصرَّح عنها بتعريف ذلك البرنامج الفرعي، وأخيرًا، يُنفِّذ مَتْن البرنامج الفرعي.
</p>

<p>
	المُعامِل الصُّوريّ (formal parameter) عبارة عن "اسم"، أو بتعبير آخر، مُعرِّف بسيط (simple identifier)، فهو في الواقع أشبه ما يَكُون بالمُتَغيِّر، وكأي مُتَغيِّر، لابُدّ أن يكون له نوع مثل <code>int</code> أو <code>boolean</code> أو <code>String</code> أو <code>double[]‎</code>. في المقابل، المُعامِل الفعلي (actual parameter) هو مجرد "قيمة" يُفْترَض اِسْنادها لمُتَغيِّر المُعامِل الصُّوريّ المُناظِر عند الاستدعاء الفعليّ للبرنامج الفرعي، لذا يُمكِن اِستخدَام أي تعبير (expression) طالما كان يَؤول إلى قيمة هي من نوع يمكن إِسْناده -بواسطة تَعْليمَة إِسْناد (assignment)- إلى نوع المُعامِل الصُّوريّ المُناظِر. فمثلًا، إذا كان لدينا مُعامِل صُّوريّ من النوع <code>double</code>، ونظرًا لإمكانية إِسْناد قيمة من النوع <code>int</code> إلى المُتَغيِّرات من النوع <code>double</code>، فإن قيمة المُعامِل الفعليّ المُمرَّرة لذلك المُعامِل الصُّوريّ يُمكِن أن تَكُون من النوع <code>int</code>. لاحِظ أنه من الضروري تَمرير مُعامِل فعليّ لكل مُعامِل صُّوريّ أثناء الاستدعاء الفعليّ للبرنامج الفرعي. اُنظر البرنامج الفرعي التالي كمثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_11" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> doTask</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> N</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> boolean test</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// تعليمات تنفيذ المهمة</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تستطيع اِستدعاء البرنامج الفرعي بالأعلى باِستخدَام تَعْليمَة الاِستدعاء التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_13" style="">
<span class="pln">doTask</span><span class="pun">(</span><span class="lit">17</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">sqrt</span><span class="pun">(</span><span class="pln">z</span><span class="pun">+</span><span class="lit">1</span><span class="pun">),</span><span class="pln"> z </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span></pre>

<p>
	يُمكِن تَوصِيف ما يُنفِّذه الحاسوب -أثناء تَّنْفيذه لتَعْليمَة الاستدعاء بالأعلى- إلى تَعْليمَة الكُتلة (block statement) التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_15" style="">
<span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">       </span><span class="com">// خصص مساحة بالذاكرة للمعاملات الصورية</span><span class="pln">
    </span><span class="kwd">double</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
    boolean test</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// اسند القيمة 17 للمعامل الصوري الأول </span><span class="pln">
    N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">17</span><span class="pun">;</span><span class="pln">              
    </span><span class="com">// احسب قيمة التعبير واسندها للمعامل الصوري الثاني</span><span class="pln">
    x </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">sqrt</span><span class="pun">(</span><span class="pln">z</span><span class="pun">+</span><span class="lit">1</span><span class="pun">);</span><span class="pln">  
    </span><span class="com">// احسب قيمة التعبير المنطقي واسندها للمعامل الصوري الثالث</span><span class="pln">
    test </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">z </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">    
    </span><span class="com">// تعليمات تنفيذ المهمة</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إلى جانب الاختلاف الجَلِيّ بحجم الشيفرة التي تَتَطلَّبها كِلا الطريقتين، هناك أيضًا اختلافات آخرى مُتعلقة بنِطاق (scope) المُتَغيِّرات، وكيفية التَعامُل في حالة وجود عدة مُتَغيِّرات أو مُعامِلات بنفس الاسم.
</p>

<p>
	قد تَكُون فكرة اِستخدَام مُعامِل (parameter) لتمرير بعض المعلومات إلى برنامج فرعي (subroutine) معين بديهية نوعًا ما، ولذلك فإن اِستدعاء التوابع الفرعية المُعرَّفة مُسْبَّقًا ليس بمشكلة، وهو ما يَختلِف تمامًا عن كتابة تعريف البرنامج الفرعي ذاته (subroutine definition)، والذي عادة ما يُرْبِك دَارسِي البرمجة المبتدئين، بالأخص ما يتعلق منها بكيفية عَمَل المُعامِلات. في الواقع، يَقع الكثيرون منهم في خطأ إِسْناد قيم إلى المُعامِلات الصُّوريّة (formal parameters) ببداية مَتْن البرنامج الفرعي، وهو ما يُمثِل سوء فهم تام لماهية مُعامِلات البرامج الفرعية؛ فعندما يُنفِّذ الحاسوب تَعْليمَة اِستدعاء برنامج فرعي معين، فإنه يُسنِد قيم المُعامِلات الفعليّة (actual parameters) المُمرَّرة بتَعْليمَة الاستدعاء إلى المُعامِلات الصُّوريّة، وذلك قَبْل البدء بتَّنْفيذ مَتْن البرنامج الفرعي، أيّ أنه حينما يبدأ الحاسوب بتَّنْفيذ ذلك المَتْن، تَكُون المُعامِلات الصُّوريّة قد هُيئت بالفعل بقيمها المبدئية المُمرَّرة، ولذلك لا معنى من بدء المَتْن بإِسْناد قيم إلى تلك المُعامِلات. تَذكَّر أن البرنامج الفرعي ليس مُستقلًا؛ فبالنهاية هو يُستدعَى بواسطة برنامج آخر (routine)، ولذا تَقع مسئولية تَوْفِير قيم مُعامِلاته على تَعْليمَة الاستدعاء، ومِنْ ثَمَّ على ذلك البرنامج المُستدعِي.
</p>

<h2>
	التحميل الزائد (overloading)
</h2>

<p>
	يَتَطلَّب استدعاء برنامج فرعي معين مَعرِفة بعض المعلومات عنه، والتي يُطلَق عليها اسم "بَصْمَة البرنامج الفرعي (subroutine's signature)". تَتَكوَّن تلك البَصْمَة من كُلًا من اسم البرنامج الفرعي، وعدد المُعامِلات الصُّوريّة (formal parameters) المُعرَّفة ضِمْن قائمة مُعامِلاته، بالإضافة إلى نوعها. على سبيل المثال، يُمكِنك كتابة بَصْمَة البرنامج الفرعي <code>doTask</code> المذكور بالأعلى كالتالي: <code>doTask(int,double,boolean)‎</code>. لاحِظ أن بَصْمَة البرنامج الفرعي لا تَتضمَّن أسماء المُعامِلات، وهو في الواقع أمر يَسهُل تبريره؛ فليس هناك أيّ نَفْع من مَعرِفة أسماء المُعامِلات الصُّوريّة إذا كان كل غرضك هو مجرد اِستخدَام ذلك البرنامج الفرعي، ولذلك لا تُعدّ أسماء المُعامِلات جزءًا من واجهة البرنامج الفرعي (subroutine's interface).
</p>

<p>
	تَسمَح لغة الجافا باِستخدَام نفس الاسم لأكثر من برنامج فرعي داخل نفس الصَنْف، بشَّرْط اختلاف البَصْمَة (signatures) الخاصة بهم، فيما يُعرَف باسم "التحميل الزائد (overloading)" لاسم البرنامج الفرعي؛ حيث أصبح ذلك الاسم يَمتلك عدة معاني مختلفة. لا يَخلِط الحاسوب بين تلك البرامج الفرعية التي تَحمِل نفس الاسم، ويَستطيع تَّمييز أي منها تَرغَب باستدعائه، وذلك بالاعتماد على عدد المُعامِلات الفعليّة المُمرَّرة ضِمْن تَعْليمَة الاستدعاء، وأنواع تلك المُعامِلات. في الواقع، يَستخدِم الكائن (object)‏ <code>System.out</code> التحميل الزائد (overloading)؛ حيث تَتَوفَّر له العديد من التوابع (methods) المختلفة، والتي تَحمِل جميعها الاسم <code>println</code> مع اختلاف بَصْمَاتها (signatures) بالتأكيد. اُنظر على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_17" style="">
<span class="pln">println</span><span class="pun">(</span><span class="typ">int</span><span class="pun">)</span><span class="pln">                   println</span><span class="pun">(</span><span class="kwd">double</span><span class="pun">)</span><span class="pln">
println</span><span class="pun">(</span><span class="kwd">char</span><span class="pun">)</span><span class="pln">                  println</span><span class="pun">(</span><span class="pln">boolean</span><span class="pun">)</span><span class="pln">
println</span><span class="pun">()</span></pre>

<p>
	يَعتمِد الحاسوب على نوع المُعامِل الفعليّ (actual parameter) المُمرَّر بتَعْليمَة الاستدعاء لمَعرِفة أي بَصْمَة من تلك البرامج الفرعية ترغب بتَّنْفيذها. فمثلًا، عند اِستخدَام التَعْليمَة <code>System.out.println(17)</code>‎، فإنه يَستدعِي البرنامج الفرعي ذو البَصْمَة <code>println(int)</code>‎، أما في حالة اِستخدَام التَعْليمَة <code>System.out.println('A')‎</code>، فإنه يَستدعِي البرنامج الفرعي ذو البَصْمَة <code>println(char)‎</code>. تُعدّ جميع البرامج الفرعية بالأعلى مرتبطة نوعًا ما من الناحية الدلالية، فجميعها يقوم بالطباعة، وهو ما يُبرِّر تسميتها جميعًا بنفس الاسم، ولكن فيما يتعلق بالحاسوب، فإن طباعة عدد صحيح من النوع <code>int</code> تختلف تمامًا عن طباعة محرف من النوع <code>char</code>، والتي بدورها تختلف عن طباعة قيمة منطقية من النوع <code>boolean</code>، وهو ما يُبرِّر تعريف برنامج فرعي منفصل لكُلًا من تلك العمليات المختلفة.
</p>

<p>
	لا يُعدّ نوع القيمة المُعادة من البرنامج الفرعي (return type) جزءًا من البَصْمَة، ولهذا لا يُسمَح بتعريف برنامجين فرعيين بصَنْف معين إذا كان لهما نفس الاسم والبَصْمَة (signature)، حتى مع اختلاف نوع القيمة المُعادة منهما. فمثلًا، سيُؤدي تعريف البرنامجين الفرعيين التاليين بنفس الصَنْف إلى حُدوث خطأ في بناء الجملة (syntax error):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_19" style="">
<span class="typ">int</span><span class="pln">    getln</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> getln</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	وفي الواقع، هذا هو السبب وراء عدم تسمية جميع البرامج الفرعية المُعرَّفة ضِمْن الصَنْف <code>TextIO</code>، والمُستخدَمة لقراءة الأنواع المختلفة، بنفس الاسم <code>getln()‎</code>، وإنما يُستخدَم اسم مختلف لكل نوع مثل <code>getlnInt()‎</code> و <code>getlnDouble()</code>‎؛ لأن الصَنْف <code>TextIO</code> لا يُمكِن أن يَتَضمَّن أكثر من برنامج فرعي دون مُعامِلات، ويَحمِل نفس الاسم <code>getln</code>.
</p>

<h2>
	أمثلة لبرامج فرعية
</h2>

<p>
	تَتكوَّن البرمجة باستخدام البرامج الفرعية من شقّين، الأول هو تصميم البرنامج (program design)، أيّ تَقسِّيم مُهِمّة البرنامج (program) إلى مَهَامّ فرعية (subtasks) صغيرة بحيث يُسنَد كل منها إلى برنامج فرعي (subroutine)، أما الشقّ الآخر، فيَتعلَّق بعملية كتابة تعريف تلك البرامج الفرعية الصغيرة، والتي هي مسئولة عن تَّنْفيذ المَهَامّ الفرعية. سنقوم الآن بكتابة عدة أمثلة لبعض من تلك البرامج الفرعية الصغيرة، بينما سنُعود إلى مناقشة موضوع تصميم البرامج (program design) بالقسم ٤.٧.
</p>

<p>
	أول مثال هو كتابة برنامج فرعي يَستقبِل عددًا صحيحًا موجبًا كمُعامِل، ثم يَحسِب جميع قواسم (divisors) هذا العدد، ويَطبَعها. يُكتَب أيّ برنامج فرعي بالصيغة (syntax) التالية:
</p>

<pre class="ipsCode">
&lt;modifiers&gt;  &lt;return-type&gt;  &lt;subroutine-name&gt;  ( &lt;parameter-list&gt; ) {
    &lt;statements&gt;
}
</pre>

<p>
	تَتلخَّص كتابة أي برنامج فرعي (subroutine) في مَلْئ هذه الصيغة، لذا دَعْنَا نقوم بذلك لمسألة حِسَاب القواسم. أولًا، تَنُصّ المسألة على اِستقبال البرنامج الفرعي لمُعامِل (parameter) وحيد من النوع <code>int</code>، كما تُبيِّن المُهِمّة المطلوب تَّنْفيذها بواسطة التَعْليمَات المَكًتوبة بمَتْن ذلك البرنامج. ثانيًا، لمّا كان حديثنا في الوقت الراهن مقصورًا على البرامج الفرعية الساكنة (static subroutines)، فإننا سنَستخدِم المُبدِّل <code>static</code> بالتعريف. ثالثًا، قد نُضيف مُبدِّل وصول (access modifier) بالتعريف، مثل <code>public</code> أو <code>private</code>، ولكن نظرًا لعدم النَصّ بذلك صراحة ضِمْن نَّصّ المسألة، فلن نَستخدِم أيًا منهما. رابعًا، لم تَنُصّ المسألة على وجود أي قيمة مُعادة، ولذلك سيَكُون النوع المُعاد (return type) هو <code>void</code>. أخيرًا، لمّا لم تُحدِّد المسألة كُلًا من اسم البرنامج الفرعي (subroutine)، وأسماء المُعامِلات الصُّوريّة (formal parameter) صراحةً، فإننا سنَضَطرّ لاختيار تلك الأسماء بأنفسنا، ولذلك سيُستخدَم <code>N</code> كاسم للمُعامِل، و <code>printDivisors</code> كاسم للبرنامج الفرعي. اُنظر تعريف البرنامج الفرعي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_22" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> printDivisors</span><span class="pun">(</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> N </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">&lt;statements&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ينبغي لنا الآن كتابة مجموعة التَعْليمَات التي ستُكوِّن مَتْن البرنامج (routine body)، وهو ليس أمرًا صعبًا. تَذكَّر فقط أن المُعامِل <code>N</code> سيَكُون لديه قيمة بالفعل ببداية تَّنْفيذ المَتْن. يُمكِن كتابة تَوصِيف الخوارزمية كالتالي:
</p>

<p>
	"لكل عدد يُحتمَل أن يَكُون قَاسِمًا <code>D</code>، أيّ بدايةً من الواحد ووصولًا للعَدَد <code>N</code>، إذا تَمكَّن العدد <code>D</code> من تَقسِّيم العَدَد <code>N</code> تَقسِّيمًا مُتعادلًا، اِطبَع قيمة <code>D</code>."
</p>

<p>
	تُصبح الخوارزمية كالتالي بعد ترجمتها إلى لغة الجافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_24" style="">
<span class="com">/**
 * اطبع قواسم‫ N
 * ‫بفرض أن N هو عدد صحيح موجب
 */</span><span class="pln">
</span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> printDivisors</span><span class="pun">(</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> N </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> D</span><span class="pun">;</span><span class="pln">   
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The divisors of "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> N </span><span class="pun">+</span><span class="pln"> </span><span class="str">" are:"</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> D </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> D </span><span class="pun">&lt;=</span><span class="pln"> N</span><span class="pun">;</span><span class="pln"> D</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">%</span><span class="pln"> D </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">  </span><span class="com">// ‫إذا نجح D في تقسيم N تقسيما متعادلا</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">D</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمثِل التعليق (comment)، المُضاف قَبْل تعريف البرنامج الفرعي (subroutine definition)، ما يُعرَف باسم المواصفة الاصطلاحية للبرنامج (subroutine contract)، والمُكوَّنة من: بَيان هدف البرنامج الفرعي، بالإضافة إلى التَّصْريح عن أيّ اِفتراضات ينبغي مَعرفِتها قَبْل اِستخدَام ذلك البرنامج. مثلًا، في المثال بالأعلى، ذُكِر أن <code>N</code> ينبغي أن يَكُون عددًا صحيحًا موجبًا، ولذلك ينبغي لمُستدعِي البرنامج الفرعي التَأكُّد من تَوْفِية ذلك الفَرْض.
</p>

<p>
	لنَفْحَص مثالًا آخر، تَنُصّ المسألة على التالي:
</p>

<p>
	"اُكتب برنامجًا فرعيًا خاصًا <code>private</code> اسمه <code>printRow</code>، بحيث يَستقبِل ذلك البرنامج كُلًا من المُعامِلين: <code>ch</code> من النوع <code>char</code>، و <code>N</code> من النوع <code>int</code>. يَتلخَّص دور ذلك البرنامج بطباعة المحرف <code>ch</code> عدد <code>N</code> من المرات وذلك بسَطْر نصي مُنفصِل."
</p>

<p>
	بخلاف المسألة السابقة، نَصَّت هذه المسألة صراحةً على كُلًا من اسم البرنامج الفرعي وأسماء المُعامِلات، كما نَصَّت على ضرورة كَوْنه خاصًا، أيّ ينبغي اِستخدَام مُبدِّل الوصول <code>private</code>، ولذلك نحن مقيدين نوعًا ما فيما يتعلق بالسطر الأول من تعريف البرنامج الفرعي (subroutine definition). أخيرًا، مُهِمّة البرنامج بسيطة جدًا، ولذا يَسهُل كتابة مَتْن البرنامج الفرعي. اُنظر شيفرة البرنامج بالكامل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_26" style="">
<span class="com">/**
 * ‫ اطبع المحرف `ch` عدد `N` من المرات وذلك بسَطْر نصي مُنفصِل
 * ‫إذا كان N أقل من أو يساوي الصفر، اطبع سطرًا فارغًا 
 */</span><span class="pln">
</span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> printRow</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> ch</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> N </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> N</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln"> ch </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لَمْ تُصَرِّح المواصفة الاصطلاحية (contract) للبرنامج بالأعلى عن وجود أية افتراضات فيما يَخُص المُعامِل <code>N</code>، ولكنها في المقابل أوْضَحَت طريقة استجابة البرنامج الفرعي لجميع الحالات المُمكِنة، بما فيها الحالة غَيْر المُتوقَّعة من كَوْن <code>N &lt;= 0</code>.
</p>

<p>
	لنَفْحَص مثالًا آخر، ولكن في هذه المرة، سنُوضِح كيف يُمكِن لبرنامجين فرعيين أن يتفاعلا. تحديدًا، سنَكتُب برنامجًا فرعيًا يَستقبِل مُعامِلًا من النوع <code>String</code>، بحيث يَطبَع كل محرف بالسِلسِلة النصية (string) المُمرَّرة ٢٥ مرة وبسَطْر مُنفصِل. ينبغي أن تَستعين بالبرنامج الفرعي <code>printRow()‎</code> الذي كتبناه للتو لطباعة ذلك الخَرْج.
</p>

<p>
	في هذا المثال، لمّا لم تُحدِّد المسألة كُلًا من اسم البرنامج الفرعي (subroutine)، وأسماء المُعامِلات الصُّوريّة (formal parameter) صراحةً، فإننا سنضطر لاختيار تلك الأسماء، ولذلك سيُستخدَم <code>str</code> كاسم للمُعامِل، و<code>printRowsFromString</code> كاسم للبرنامج الفرعي. يُمكِن كتابة تَوصِيف الخوارزمية كالتالي:
</p>

<p>
	"لكل مَوْضِع <code>i</code> بالسِلسِلة النصية <code>str</code>، اِستدعِي البرنامج الفرعي <code>printRow(str.charAt(i),25)‎</code>؛ لطباعة سَطْر الخَرْج."
</p>

<p>
	تُصبِح الخوارزمية كالتالي بَعْد ترجمتها إلى لغة الجافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_28" style="">
<span class="com">/**
 * لكل محرف بالسلسلة النصية، اطبع سطر مكون من 25 نسخة من ذلك المحرف
 */</span><span class="pln">
</span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> printRowsFromString</span><span class="pun">(</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> str </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">  
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        printRow</span><span class="pun">(</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">),</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستطيع الآن استدعاء البرنامج الفرعي <code>printRowsFromString</code> المُعرَّف بالأعلى داخل البرنامج <code>main()‎</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_30" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">String</span><span class="pln"> inputLine</span><span class="pun">;</span><span class="pln">  </span><span class="com">// السطر النصي المدخل من قبل المستخدم</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter a line of text: "</span><span class="pun">);</span><span class="pln">
    inputLine </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
    printRowsFromString</span><span class="pun">(</span><span class="pln"> inputLine </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحِظ أنه من الضروري تَضْمِين تعريف البرامج الثلاثة <code>main()‎</code> و <code>printRowsFromString()‎</code> و <code>printRow()‎</code> بنفس الصَنْف. على الرغم من كَوْن البرنامج بالأعلى عديم الفائدة نوعًا ما، لكنه على الأقل يُبيِّن طريقة اِستخدَام البرامج الفرعية. يُمكِنك الإطلاع على البرنامج كاملًا بالملف <code>RowsOfChars.java</code>.
</p>

<h2>
	المصفوفات كمعامل
</h2>

<p>
	بالإضافة إلى إمكانية تمرير المُعامِلات من الأنواع البسيطة (primitive types) إلى البرامج الفرعية، يُسمَح أيضًا بتمرير المُعامِلات من أنواع المصفوفة (array types)، ما يَعنِي تمرير مصفوفة كاملة من القيم (المُتَغيِّرات إذا شِئنا الدقة) من خلال مُعامِل وحيد. لنَكتُب، على سبيل المثال، برنامجًا فرعيًا يَستقبِل مُعامِلًا من نوع المصفوفة <code>int[]‎</code>؛ ثم يَطبَع جميع الأعداد الصحيحة الموجودة بها، بحيث يُفصَل بين كل عدد والذي يَليه فاصلة (comma)، وبحيث تُحاط جميع تلك الأعداد بزوج من الأقواس <code>[]</code>، اُنظر تعريف البرنامج الفرعي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_32" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> printValuesInList</span><span class="pun">(</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">list</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">'['</span><span class="pun">);</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">list</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">','</span><span class="pun">);</span><span class="pln"> 
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="typ">list</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">']'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لكي نَستدعِي البرنامج الفرعي بالأعلى، سنحتاج إلى مصفوفة فعليّة (actual). تُنشِئ الشيفرة التالية مصفوفة أعداد صحيحة (array of ints)، وتُمرِّرها كوسيط (argument) للبرنامج الفرعي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_34" style="">
<span class="typ">int</span><span class="pun">[]</span><span class="pln"> numbers</span><span class="pun">;</span><span class="pln">
numbers </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="lit">3</span><span class="pun">];</span><span class="pln">
numbers</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pun">;</span><span class="pln">
numbers</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">17</span><span class="pun">;</span><span class="pln">
numbers</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">256</span><span class="pun">;</span><span class="pln">
printValuesInList</span><span class="pun">(</span><span class="pln"> numbers </span><span class="pun">);</span></pre>

<p>
	سنَحصُل على الخَرْج <code>[42,17,256]</code>.
</p>

<h2>
	وسطاء سطر الأوامر (command-line arguments)
</h2>

<p>
	لمّا كان البرنامج (routine)‏ <code>main</code> يَستقبِل مُعامِل مصفوفة من النوع <code>String[]‎</code>، كان لزامًا على مُستدعِيه -أيّ النظام (system) في هذه الحالة- أن يُمرِّر مصفوفة سَلاسِل نصية (array of String) فعليّة (actual) كقيمة لذلك المُعامِل الصُّوريّ (formal parameter). لذا لابُدّ أن يَحصُل النظام على قيم السَلاسِل النصية بتلك المصفوفة بطريقة ما، فما الذي يعنيه ذلك؟ وكيف سيَتحصَّل النظام على تلك القيم؟ في الواقع، تَتَكوّن تلك القيم من وُسَطاء سطر الأوامر (command-line arguments)[*] المُمرَّرين إلى الأمر المُستخدَم لتَشْغِيل البرنامج، وبالتالي يُسنِد النظام قيم هؤلاء الوُسَطاء إلى مصفوفة سَلاسِل نصية (array of strings)، ثم يُمرِّرها إلى البرنامج <code>main()</code>‎.
</p>

<p>
	[*] يستطيع المُستخدِم عمومًا تَشْغِيل أحد البرامج من خلال كتابة أمر (command) معين بواجهة سَطْر الأوامر (command-line interface). يَتَكوّن الأمر عمومًا من اسم البرنامج المطلوب تَشْغِيله، ولكن يُمكِن أيضًا كتابة مُدْخَلات إضافية ضِمْن الأمر. تُسمَى تلك المُدْخَلات الإضافية باسم وُسَطاء سَطْر الأوامر (command-line arguments). فمثلًا، إذا كان اسم برنامج معين هو <code>myProg</code>، تستطيع تَشْغِيله باِستخدَام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_36" style="">
<span class="pln">java myProg</span></pre>

<p>
	ولكن، في هذه الحالة، لا يوجد أي وُسَطاء (arguments)، في المقابل، تستطيع تمرير وسيط واحد أو أكثر باِستخدَام الأمر التالي:
</p>

<pre class="ipsCode">
java myProg one two three
</pre>

<p>
	في المثال بالأعلى، تُمثِل السَلاسِل النصية "one"، و "two"، و "three" قيم الوُسَطاء، ولذلك سيُسنِد النظام هذه السَلاسِل النصية إلى مصفوفة من النوع <code>String[]‎</code>، ثم يُمرِّرها كمُعامِل إلى البرنامج <code>main()‎</code>. على سبيل المثال، تَطبَع الشيفرة التالية قيمة أي وسيط (argument) أَدْخَله المُستخدِم:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_39" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CLDemo</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You entered "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> args</span><span class="pun">.</span><span class="pln">length
                           </span><span class="pun">+</span><span class="pln"> </span><span class="str">" command-line arguments"</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">args</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"They were:"</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> args</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"   "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> args</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية main</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف CLDemo</span></pre>

<p>
	إذا لم يُخصِّص المُستخدِم أي وسيط (arguments) بأمر تَشْغِيل البرنامج، فإن المُعامِل <code>args</code> سيَكُون عبارة عن مصفوفة فارغة، طولها (length) يُساوي الصفر.
</p>

<p>
	عمليًا، يُستخدَم وُسَطاء سَطْر الأوامر عادةً بهدف تمرير أسماء بعض الملفات إلى البرنامج. فمثلًا، يَنسَخ البرنامج التالي محتويات ملف نصي معين إلى ملف نصي آخر، ولذلك فإنه يَستخدِم الصَنْف <code>TextIO</code> ضِمْن حَلْقة تَكْرار، بحيث يَقْرأ سَطْرًا واحدًا من الملف الأصلي في كل مرة، ثم يَنسَخُه إلى الملف الآخر. يَستمِر في القيام بذلك حتى يَصِل إلى نهاية الملف، والتي يُستدَلّ عليها من القيمة المنطقية المُعادة من الدالة (function)‏ <code>TextIO.eof()‎</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_41" style="">
<span class="pln">input textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">
</span><span class="com">/** 
 * يتطلب ذلك الأمر وسيطين، هما أسماء الملفات
 * الأول ينبغي أن يكون اسم ملف موجود
 * والثاني ينبغي أن يكون اسم الملف الذي سينسخ البرنامج إليه بيانات الملف الأول
 * سيقوم البرنامج بنسخ محتويات الملف الأول إلى الملف الثاني
 * تحذير: إذا كان الملف الثاني موجود عند تشغيل البرنامج، ستتم الكتابة على البيانات السابقة
 * يعمل هذا البرنامج مع الملفات النصية فقط
 */</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CopyTextFile</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="pln"> </span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">args</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Two command-line arguments are required!"</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">readFile</span><span class="pun">(</span><span class="pln"> args</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">   </span><span class="com">// افتح الملف الأصلي بهدف القراءة</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">writeFile</span><span class="pun">(</span><span class="pln"> args</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">  </span><span class="com">// افتح الملف المراد النسخ إليه</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> lineCount</span><span class="pun">;</span><span class="pln">  </span><span class="com">// عدد الأسطر المنسوخة</span><span class="pln">
        lineCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">eof</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="com">// اقرأ سطر من الملف الأصلي وانسخه للملف الآخر</span><span class="pln">
            </span><span class="typ">String</span><span class="pln"> line</span><span class="pun">;</span><span class="pln">
            line </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">
            </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(</span><span class="pln">line</span><span class="pun">);</span><span class="pln">
            lineCount</span><span class="pun">++;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%d lines copied from %s to %s%n"</span><span class="pun">,</span><span class="pln">
                          lineCount</span><span class="pun">,</span><span class="pln"> args</span><span class="pun">[</span><span class="lit">0</span><span class="pun">],</span><span class="pln"> args</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	تُنفَّذ معظم البرامج حاليًا من خلال واجهة مُستخدِم رسومية (GUI environment)، ولذلك لم يَعُدْ وُسَطاء سَطْر الأمر (command-line arguments) بنفس ذات الأهمية في الوقت الحالي. مع ذلك ما يزال البرنامج بالأعلى مثالًا جيدًا لبيان كيفية اِستخدَام مُعامِلات المصفوفة (array parameters) على الأقل.
</p>

<h2>
	التبليغ عن الاعتراضات (exceptions)
</h2>

<p>
	ذَكَرَنا، منذ قليل، مصطلح المواصفة الاصطلاحية للبرنامج (subroutine contract)، والذي يُوضِح وظيفة البرنامج الفرعي في حالة تمرير قيم صالحة -وفقًا لما هو مُوضَّح بنفس المواصفة الاصطلاحية- لجميع المُعامِلات الخاصة به. تَتَبقَّى الحاجة إلى مَعرِفة كيفية تَصرُّف البرنامج الفرعي في حالة تمرير قيم غَيْر صالحة للمُعامِلات.
</p>

<p>
	تَعرَّضنا بالفعل لعدة أمثلة بالقسم ٣.٧، والتي تُبلِّغ فيها البرامج الفرعية عن اِعتراضات (throwing exceptions) في حالة تمرير قيم غَيْر صالحة، فمثلًا، تَنُصّ المواصفة الاصطلاحية للبرنامج الفرعي المَبنِى مُسْبَّقًا (built-in)‏ <code>Double.parseDouble</code> على ضرورة أن يَكُون المُعامِل المُمرَّر إليها عبارة عن تمثيل نصي (string representation) لعَدََدَ من النوع <code>double</code>. إذا كانت قيمة المُعامِل المُمرَّرة مُتماشية مع ذلك الشَّرْط، سيُحوِّل البرنامج الفرعي السِلسِلة النصية (string) المُمرَّرة إلى قيمتها العَدَدية المكافئة، أما إذا لم تَكُن مُتماشية معها، سيُبلِّغ البرنامج الفرعي عن اِعتراض (exception) من النوع <code>NumberFormatException</code>.
</p>

<p>
	تُبلِّغ الكثير من البرامج الفرعية عن اعتراض من النوع <code>IllegalArgumentExceptions</code> في حالة تمرير قيم غَيْر صالحة لمُعامِلاتها، وهو ما قد تَرغب في اتباعه بالبرامج الفرعية الخاصة بك. أيّ اعتراض (exception) هو بالنهاية عبارة عن كائن (object)، ستَضطرّ إلى إنشائه قَبْل التَبْليغ عنه باِستخدَام التَعْليمَة <code>throw</code>. سنتناول كيفية القيام بذلك تفصيليًا بالفصل الخامس، ولكن، إلى ذلك الحين، تستطيع اِستخدَام الصيغة (syntax) التالية لتَعْليمَة <code>throw</code>؛ للتَبْليغ عن اِعتراض من النوع <code>IllegalArgumentException</code> تحديدًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_43" style="">
<span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln">  </span><span class="typ">IllegalArgumentException</span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">error</span><span class="pun">-</span><span class="pln">message</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	تَتَكوّن رسالة الخطأ <strong><error-message></error-message></strong> بالأعلى من سِلسِلة نصية (string) تَشرَح الخطأ المُكْتشَف بينما تُستخدَم <code>new</code> لإنشاء كائن الاعتراض (exception object). كل ما عليك القيام به هو فَحْص قيم المُعامِلات المُمرَّرة؛ لمَعرِفة ما إذا كانت صالحة أم لا، ثم التَبْليغ عن اعتراض باِستخدَام التَعْليمَة بالأعلى إذا لم تَكُن صالحة. على سبيل المثال، لابُدّ أن تَكُون قيمة المُعامِل المُمرَّرة إلى البرنامج الفرعي <code>print3NSequence</code> -المُعرَّف ببداية هذا القسم- عددًا صحيحًا موجبًا، لذلك يُمكِننا، في حالة انتهاك هذا الشَّرْط، تَعْدِيل تعريف البرنامج الفرعي (subroutine definition) بالصورة التالية؛ وذلك لكي نَتَمَكَّن من التَبْليغ عن الاِعتراض:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3615_45" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> print3NSequence</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> startingValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">startingValue </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">  </span><span class="com">// إذا حدث انتهاك للمواصفة الاصطلاحية</span><span class="pln">
        </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">IllegalArgumentException</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Starting value must be positive."</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

    </span><span class="com">// بقية البرنامج الفرعي مثلما بالأعلى</span></pre>

<p>
	إذا كانت القيمة المُمرَّرة إلى المُعامِل <code>startingValue</code> غَيْر صالحة، فستُنهِي تَعْليمَة <code>throw</code> بالأعلى البرنامج الفرعي فورًا بدون تَّنْفيذ بقية المَتْن، كما قد ينهار (crash) البرنامج بالكامل في حالة عدم اِلتقاط ذلك الاِعتراض (catching exception) بمكان آخر ضِمْن البرنامج باِستخدَام التَعْليمَة <code>try..catch</code> بحيث يُستدعَى البرنامج الفرعي <code>print3NSequence</code> داخل الجزء <code>try</code>، كما ناقشنا بالقسم ٣.٧.
</p>

<h2>
	المتغيرات العامة (global) والمحلية (local)
</h2>

<p>
	كملاحظة أخيرة بهذا القسم، يُمكِننا القول أننا نستطيع الآن اِستخدَام ثلاثة أنواع مختلفة من المُتَغيِّرات داخل أيّ برنامج فرعي، هي كالتالي: أولًا، المُتَغيِّرات المحليّة (local variables) والتي يُصرَّح عنها داخل البرنامج الفرعي. ثانيًا، أسماء المُعامِلات الصُّوريّة (formal parameter) ضِمْن تعريف البرنامج الفرعي. ثالثًا، المُتَغيِّرات الأعضاء الساكنة (static member variables)، والتي يُصرَّح عنها خارج البرنامج الفرعي.
</p>

<p>
	تُعدّ المُتَغيِّرات المحليّة (local variables) من صميم أعمال البرنامج الفرعي الداخلية، وليس لها أيّ اتصال مع ما هو خارج البرنامج الفرعي.
</p>

<p>
	تُمرِّر المُعامِلات الصُّوريّة (formal parameter) قيم خارجية إلى البرنامج الفرعي أثناء الاستدعاء، ولكنها مع ذلك تَتَصرَّف بطريقة مشابهة للمُتَغيِّرات المحليّة بمجرد بدء تَّنْفيذ البرنامج الفرعي. يَعنِي ذلك أنه في حالة حُدوث تَغْيِير بقيمة أحد المُعاملات الصُّوريّة (من النوع الأوَّليّ [primitive type] تحديدًا) أثناء تَّنْفيذ البرنامج الفرعي، فإن ذلك التَغْيِير لا يُؤثِر نهائيًا على بقية البرنامج. لاحِظ أنه في حالة كان المُعامِل الصُّوريّ عبارة عن مصفوفة أو كائن (object)، فإن الأمور تُصبِح أكثر تعقيدًا كما سنرى لاحقًا.
</p>

<p>
	أخيرًا، بخلاف المُتَغيِّرات المحليّة (local variables) المُعرَّفة داخل البرامج الفرعية، فإن المُتَغيِّرات العامة (global variables) تُعرَّف خارج أي برنامج فرعي، ولذا فإنها تُعدّ مستقلة عنها، كما أنها قابلة للاِستخدَام ضِمْن أجزاء عديدة من البرنامج (program). في الواقع، يُمكِن اِستخدَام المُتَغيِّر العام (global variable) بأيّ مكان داخل الصَنْف المُُعرَّف بداخله، بل يُمكِن استخدامه بأي صنف آخر طالما لم يُصرَّح عنه باِستخدَام المُبدِّل <code>private</code>. لاحظ أنه إذا حَدَثَ تغيير على مُتَغيِّر عام (global variable) داخل برنامج فرعي معين، فإن تأثير ذلك التغيير يمتد إلى ما هو أبعد من مجرد ذلك البرنامج الفرعي الذي أَحَدَث التغيير، وهو ما قد تعرضت له بالفعل بالمثال الأخير بالقسم السابق؛ حيث عَدَّلت إحدى البرامج الفرعية قيم المُتَغيِّرات العامة <code>gamesPlayed</code> و <code>gamesWon</code>، ثم طُبعت بواسطة برنامج فرعي آخر هو <code>main()‎</code>.
</p>

<p>
	إذا اِستخدَمت مُتَغيِّرًا عامًا (global variable) ضِمْن برنامج فرعي معين، فإن ذلك البرنامج الفرعي يُصبِح قادرًا على الاتصال مع بقية البرنامج (program) فيما يُشبه الاتصال السري (back-door communication)، ولهذا نستطيع القول أن المُتَغيِّرات العامة قد أصبحت بذلك جزءًا من واجهة البرنامج الفرعي (subroutine's interface). يُعدّ الاتصال السري عمومًا أقل وضوحًا وصراحةً من ذلك المُقام باستخدام المُعامِلات، ولهذا فإنه قد يَتَسبَّب بكسر القاعدة التي تَنُصّ على ضرورة كَوْن واجهة (interface) "الصندوق الاسود (black box)" صريحة وسهلة الفهم. قد يَدْفَعك ذلك إلى الظّنّ بأن اِستخدَام المُتَغيِّرات العامة داخل البرامج الفرعية أمر سيئ عمومًا، ولكن هذا غَيْر صحيح، فهناك على الأقل سببًا واحدًا جيدًا قد يَدْفَعك للقيام بذلك: مثلًا إذا فكرت بالصَنْف (class) بكَوْنه نوعًا من "الصندوق الاسود (black box)"، يُصبِح من المعقول تمامًا السماح للبرامج الفرعية الواقعة ضِمْن ذلك الصندوق بالاتصال سريًا مع بعضها البعض (back-door communication) خاصة إذا ساهم ذلك بتبسيط الصَنْف ككل من الخارج. لهذا يَنصَح الكاتب بعدم اتخاذ أيّ موقف عدائي مُطْلَق من اِستخدَام المُتَغيِّرات العامة (global variables) داخل البرامج الفرعية، فقط عليك أن تُفكِر مَلِيًّا قَبْل اِستخدَام مُتَغيِّر عام (global variable) داخل برنامج فرعي للتَأكُّد مما إذا كان ذلك ضروريًا.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c4/s3.html" rel="external nofollow">Section 3: Parameters</a> من فصل Chapter 4: Programming in the Large I: Subroutines من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1088</guid><pubDate>Tue, 08 Dec 2020 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x628;&#x631;&#x627;&#x645;&#x62C; &#x627;&#x644;&#x641;&#x631;&#x639;&#x64A;&#x629; &#x648;&#x627;&#x644;&#x645;&#x62A;&#x63A;&#x64A;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x633;&#x627;&#x643;&#x646;&#x629; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%A7%D9%84%D9%81%D8%B1%D8%B9%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B3%D8%A7%D9%83%D9%86%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1087/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_12/24.png.4ce21bc4f69e31e1b352e685e27b2236.png" /></p>

<p>
	تَسمَح بعض اللغات البرمجية -بل غالبيتها في الواقع- بتعريف البرامج الفرعية (subroutines) بصورة مستقلة خارج أي صَنْف، لكن تختلف لغة الجافا عنهم في تلك النقطة، حيث لابُدّ أن يُعرَّف أيّ برنامج فرعي (subroutine) بلغة الجافا ضِمْن صَنْف (class). الهدف من الصَنْف عمومًا هو تجميع البرامج الفرعية والمُتَغيِّرات المُرتبطة معًا ضِمْن وحدة واحدة. نظرًا لأن البرامج المكتوبة بلغة الجافا عادة ما تَستخدِم عددًا ضخمًا من البرامج الفرعية المَكْتوبة بواسطة مبرمجين مختلفين، فإن احتمالية الخلط بين أسمائها يَكُون كبيرًا، لذا حَرَص مُصمِّمي الجافا على وَضع تقييد حازم على الطرق التي يُمكِن بها تسمية الأشياء، ومن هنا كانت ضرورة تعريف البرامج الفرعية وتجميعها ضِمْن أصناف (classes) لها اسم وبالتبعية تجميع تلك الأصناف ضِمْن حزم (packages) لها اسم أيضًا كما سنرى لاحقًا.
</p>

<p>
	تُميز لغة الجافا بشكل واضح بين البرامج الفرعية الساكنة (static) وغَيْر الساكنة (non-static). يُمكِن لأي صَنْف أن يَتضمَّن كِلا النوعين، ولكن كيفية اِستخدَامهما مختلفة تمامًا. تُعدّ البرامج الفرعية الساكنة (static subroutine) عمومًا أسهل في الفهم، فببساطة أي برنامج فرعي ساكن هو عضو (member) ينتمي للصنف ذاته المُعرَّف بداخله. في المقابل، تعريف البرامج الفرعية غَيْر الساكنة (non-static subroutine) موجود فقط ضِمْن الصَنْف حتى تَتَمكَّن كائنات (objects) ذلك الصنف -عند إنشائها- من اِستخدَام تلك البرامج الفرعية، وتُصبِح عندها تلك البرامج أعضاء بتلك الكائنات (objects). يُمكِن تطبيق ذلك الاختلاف على المُتَغيِّرات (variables) الساكنة وغَيْر الساكنة بنفس الكيفية، بل وعلى أي شيء آخر قد يَقع ضمن تعريف الأصناف (class definition). سنتناول في هذا الفصل كُلًا من البرامج الفرعية الساكنة والمُتَغيِّرات الساكنة فقط، وسننتقل بالفصل التالي إلى البرمجة كائنية التوجه (object-oriented programming) وعندها سنستطيع مناقشة الأعضاء غَيْر الساكنة.
</p>

<p>
	عادة ما يُطلَق مصطلح "التابع (method)" على البرامج الفرعية (subroutines) المُعرَّفة ضِمْن صَنْف، وهو الاسم الذي يُفضِّله غالبية مبرمجي الجافا مع أن المصطلحان عمومًا مترادفان خاصة فيما يَتعلَّق بلغة الجافا. ستَجِدْ أيضًا البعض يَستخدِم مصطلحات آخرى للإشارة إلى البرامج الفرعية مثل "الإجراء (procedure)" أو "الدالة (function)". يُفضِّل الكاتب الاستمرار باِستخدَام المصطلح الأعم "البرنامج الفرعي (subroutine)" ضِمْن هذا الفصل للإشارة إلى البرامج الفرعية الساكنة على الأقل، ولكنه سيبدأ في اِستخدَام مصطلح "التابع (method)" من حين لآخر، كما أنه سيَستخدِم مصطلح "الدالة (function)" فقط للإشارة إلى البرامج الفرعية التي تَحسِب قيمة وتُعيدها مع أن بعض اللغات البرمجية الآخرى تَستخدِم ذلك المصطلح للإشارة إلى البرامج الفرعية (subroutines) بمفهومها الأعم.
</p>

<h2>
	تعريف البرامج الفرعية
</h2>

<p>
	ينبغي أن يُعرَّف (define) أيّ برنامج فرعي (subroutine)، تَنوِي اِستخدَامه، بمكان ما بالبرنامج، بحيث يَتضمَّن ذلك التعريف (subroutine definition) كُلًا من الآتي: اسم البرنامج الفرعي (subroutine name)، والمعلومات اللازمة لاستدعائه (subroutine call)، وأخيرًا، الشيفرة الفعليّة المطلوب تَّنْفيذها مع كل عملية استدعاء. يُكتَب تعريف البرنامج الفرعي (subroutine definition) بالجافا بالصياغة التالية:
</p>

<pre class="ipsCode">
&lt;modifiers&gt;  &lt;return-type&gt;  &lt;subroutine-name&gt;  ( &lt;parameter-list&gt; ) {
    &lt;statements&gt;
}
</pre>

<p>
	قد تكون الصيغة بالأعلى مألوفة بالنسبة لك؛ فقد تَعرَّضنا بالفعل خلال الفصول السابقة لبعض البرامج الفرعية، مثل البرنامج <code>main()‎</code> المُعرَّف بأيّ برنامج، والبرنامج <code>drawFrame()‎</code> ببرامج التحريكة (animation) بالقسم ٣.٩. ومع ذلك، لاِستيعاب ما تَعنيه تلك الصيغة تفصيليًا، سنحتاج إلى مُناقشتها باستفاضة، وهو ما سنفعله بغالبية هذا الفصل.
</p>

<p>
	أولًا، تُكوِّن التَعْليمَات <strong><statements></statements></strong> -الواقعة بين القوسين المعقوصين <code>{}</code>- مَتْن البرنامج الفرعي (subroutine body)، وتُمثِل الجزء التَّنْفيذي (implementation) أو الداخلي "للصندوق الأسود (black box)" كما ذَكَرنا بالقسم السابق. يُنفِّذ الحاسوب تلك التَعْليمَات عند إجراء عملية اِستدعاء لذلك البرنامج (أو التابع [method]). لاحظ أن تلك التَعْليمَات قد تَتكوَّن من أي تَعْليمَة قد تَعرَّضنا لها خلال الفصلين الثاني والثالث.
</p>

<p>
	ثانيًا، تُكتَب المُبدِّلات <strong><modifiers></modifiers></strong> ببداية التعريف، وهي عبارة عن كلمات تُستخدَم لضَبْط بعض خاصيات البرنامج الفرعي، مثل ما إذا كان ساكنًا (static) أم غير ساكن (non-static). تُوفِّر لغة الجافا عمومًا ستة مُبدِّلات (modifiers) يُمكنك اِستخدَامها، ولقد تَعرَّضنا لاثنين منها فقط حتى الآن، وهي المُبدِّل الساكن <code>static</code>، والمُبدِّل العام <code>public</code>.
</p>

<p>
	ثالثًا، يُستخدَم النوع المُعاد <strong><return-type></return-type></strong> لتَخْصِيص نوع القيمة المُعادة من البرنامج الفرعي. تحديدًا، إذا كان البرنامج الفرعي بالأساس هو عبارة عن دالة (function) تَحسِب قيمة معينة، عندها قد تَستخدِم أي نوع، مثل <code>String</code> أو <code>int</code> أو حتى أنواع المصفوفة مثل <code>double[]‎</code>. أما إذا كان البرنامج الفرعي ليس بدالة، أيّ لا يُعيد قيمة، فعندها تُستخدَم القيمة الخاصة <code>void</code>، والتي تُشير إلى عدم وجود قيمة مُعادة، أيّ أنها إِما أن تَكُون فارغة (empty) أو غَيْر موجودة. سنتناول الدوال (functions)، والأنواع المُعادة (return types) تفصيليًا بالقسم ٤.٤.
</p>

<p>
	وأخيرًا، قائمة المُعامِلات <strong><parameter-list></parameter-list></strong> الخاصة بالتابع (method). تُعدّ المُعامِلات جزءًا من وَاجهة البرنامج الفرعي (subroutine interface)، وتُمثِل المعلومات المُمرَّرة (passed) إليه من الخارج، والتي قد يَستخدِمها لحِسَاب بعض العمليات الداخلية الخاصة به. فمثلًا، بفَرْض وجود الصَنْف <code>Television</code>، والذي يَتضمَّن التابع <code>changeChannel()‎</code>. في تلك الحالة، يُفْترَض أن يُطرَح سؤالًا تلقائيًا عن رقم القناة التي تُريد من البرنامج الفرعي الانتقال إليها، وهنا يأتي دور المُعامِلات (parameter)؛ حيث يُمكِن اِستخدَام مُعامِل للإجابة على مثل هذا السؤال، ولمّا كان رقم القناة هو عدد صحيح، فسيَكُون نوع ذلك المُعامِل (parameter type) هو <code>int</code>، ولهذا يُمكِنك التَّصْريح (declaration) عن التابع <code>changeChannel()‎</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_8" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> changeChannel</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> channelNum</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	يُشير التَّصْريح بالأعلى إلى أن التابع <code>changeChannel()‎</code> لديه مُعامِل يَحمِل اسم <code>channelNum</code> من النوع العددي الصحيح <code>int</code>. لاحظ أن قيمة المُعامِل <code>channelNum</code> غير مُتوفِّرة حتى الآن، وإنما تَتوفَّر عند عملية الاستدعاء الفعليّ للتابع الفرعي، على سبيل المثال: <code>changeChannel(17);‎</code>.
</p>

<p>
	قد تتكوَّن قائمة المُعامِلات (parameter list) -بتعريف البرنامج الفرعي- من تَّصْريح عن مُعامِل (parameter declaration) واحد أو أكثر، وذلك على الصورة <strong><type parameter-name=""></type></strong>، بحيث يَتكوَّن كل تَّصْريح من مُعامِل وحيد، كما يُفصَل بين كل تَّصْريح والذي يليه باستخدام فاصلة (comma). على سبيل المثال، في حالة أردت التَّصْريح عن مُعامِلين من النوع <code>double</code>، فستضطر إلى كتابة <code>double x, double y</code> وليس <code>double x, y</code>. لاحِظ أن قائمة المُعامِلات قد تَكُون فارغة أيضًا.
</p>

<p>
	سنتناول المُعامِلات (parameters) تفصيليًا بالقسم التالي.
</p>

<p>
	ها هي التعريفات الخاصة ببعض البرامج الفرعية (subroutine definitions)، ولكن بدون الجزء التَّنْفيذي (implementation) منها، أي بدون التَعْليمَات الفعليّة التي تُعرِّف ما تُنفِّذه تلك البرامج الفرعية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_10" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> playGame</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// المبدلات هي‫ public و static</span><span class="pln">
    </span><span class="com">// ‫النوع المعاد هو void</span><span class="pln">
    </span><span class="com">// ‫اسم البرنامج الفرعي هو playGame</span><span class="pln">
    </span><span class="com">// قائمة المعاملات فارغةً</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">int</span><span class="pln"> getNextN</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> N</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// لا يوجد مبدلات</span><span class="pln">
    </span><span class="com">// ‫النوع المعاد هو int</span><span class="pln">
    </span><span class="com">// ‫اسم البرنامج الفرعي هو getNextN</span><span class="pln">
    </span><span class="com">// ‫قائمة المعاملات تتضمن معامل اسمه N من النوع int</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">static</span><span class="pln"> boolean lessThan</span><span class="pun">(</span><span class="kwd">double</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫المبدلات هي static</span><span class="pln">
    </span><span class="com">// ‫النوع المعاد هو boolean</span><span class="pln">
    </span><span class="com">// ‫اسم البرنامج الفرعي هو lessThan</span><span class="pln">
    </span><span class="com">// ‫قائمة المعاملات تتضمن معاملين x و y كلاهما من النوع double</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بالمثال الثاني بالأعلى، لمّا كان تعريف التابع <code>getNextN</code> لا يَتضمَّن المُبدل <code>static</code>، فإنه يُعدّ بصورة افتراضية تابعًا غَيْر ساكن (non-static method)، ولذلك لن نَفْحصه بهذا الفصل! اُستخدِم المُبدل <code>public</code> بالمثال الأول، والذي يُشير إلى إِمكانية استدعاء التابع (method) من أي مكان بالبرنامج، حتى من خارج الصَنْف (class) الذي عُرِّف فيه هذا التابع. في المقابل، يَتوفَّر المُبدل <code>private</code>، والذي يُشير إلى إمكانية استدعاء التابع من داخل نفس الصَنْف فقط. يُطلَق على كُلًا من المُبدلين <code>public</code> و <code>private</code> مُحدِّدات الوصول أو مُبدِّلات الوصول (access specifiers/access modifier). يَتوفَّر مُبدل وصول (access modifier) أخير، هو <code>protected</code>، والذي ستتضح أهميته عندما ننتقل إلى البرمجة كائنية التَوجه (object-oriented programming) بالفصل الخامس. في حالة عدم تخصيص مُحدِّد وصول لتابع معين، فإنه، وبصورة افتراضية، يُصبِح قابلًا للاستدعاء من أيّ مكان بالحزمة (package) التي تَتضمَّن صَنْفه، ولكن ليس من خارج تلك الحزمة. سنُناقش الحزم (packages) خلال هذا الفصل، تحديدًا بالقسم ٤.٦.
</p>

<p>
	يَتَّبِع البرنامج <code>main()‎</code>، المُعرَّف بأي برنامج، نفس قواعد الصيغة (syntax rules) المُعتادة لأي برنامج فرعي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_12" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	بفَحْص التعريف بالأعلى، تَجد أن المُبدلات المُستخدَمة هي <code>public</code> و <code>static</code>، أما النوع المُعاد فهو <code>void</code>، أما اسم البرنامج الفرعي فهو <code>main</code>، وأخيرًا، قائمة المعاملات هي <code>String[] args</code>، أيّ أن نوع المُعامِل المُمرَّر هو نوع المصفوفة <code>String[]‎</code>.
</p>

<p>
	إذا كنت قد قرأت الفصول السابقة، فلديك بالفعل الخبرة الكافية لكتابة الجزء التَّنْفيذي من البرنامج الفرعي (implementation of a subroutine). في هذا الفصل، سنتعلَّم كتابة التَعرِيف بالكامل بما في ذلك جزء الواجهة (interface).
</p>

<h2>
	استدعاء البرامج الفرعية
</h2>

<p>
	يُعدّ تعريف البرنامج الفرعي (subroutine definition) بمثابة إعلام للحاسوب بوجود ذلك البرنامج الفرعي وبالوظيفة التي يُؤديها، لكن يُرجئ التَّنْفيذ الفعليّ للبرنامج الفرعي إلى حين استدعائه (call). يَنطبِق ذلك حتى على البرنامج (routine)‏ <code>main()</code>‎، والذي يَستدعيه النظام (system) -لا أنت- عند تَّنْفيذه للبرنامج (program) ككل. تُستخدَم، مثلًا، تَعْليمَة استدعاء البرنامج الفرعي (subroutine call) التالية؛ لاستدعاء التابع <code>playGame()‎</code> المذكور بالأعلى:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_14" style="">
<span class="pln">playGame</span><span class="pun">();</span></pre>

<p>
	يُمكن عمومًا كتابة تَعْليمَة الاستدعاء بالأعلى بأيّ مكان داخل نفس الصَنْف (class) الذي عَرَّف التابع <code>playGame()‎</code>، سواء كان ذلك بالتابع‏ <code>main()‎</code>، أو بأيّ برنامج فرعي آخر. علاوة على ذلك، لمّا كان التابع <code>playGame()‎</code> مُعرَّف باِستخدَام المُبدل <code>public</code>، وهو ما يَعنِي كَوْنه تابعًا عامًا، فإنه من الممكن لأيّ صَنْف آخر استدعائه أيضًا، ولكن ينبغي أن تُعلِم الحاسوب، في تلك الحالة، باسم التابع كاملًا أثناء الاستدعاء، أيّ بذكر الصَنْف الذي ينتمي إليه ذلك التابع. ولأن التابع <code>playGame()‎</code> مُعرَّف باِستخدَام المُبدل <code>static</code>، وهو ما يَعنِي كَوْنه تابعًا ساكنًا، فإن اسمه الكامل يَتضمَّن اسم الصنف ذاته المُعرَّف بداخله. على سبيل المثال، إذا كان التابع <code>playGame()‎</code> مُعرَّف بالصَنْف <code>Poker</code>، تُستخدَم التَعْليمَة التالية لاستدعائه من خارج هذا الصَنْف:
</p>

<pre class="ipsCode">
Poker.playGame();
</pre>

<p>
	يُعلِم اسم الصَنْف -بالأعلى- الحاسوب بأيّ صَنْف ينبغي له أن يَجِد التابع. بالإضافة إلى ذلك، يُساعدنا وجود اسم الصَنْف أثناء الاستدعاء على التمييز بين التابع <code>Poker.playGame()‎</code> وأي توابع اخرى لها نفس الاسم ومُعرَّفة بأصناف آخرى، مثل <code>Roulette.playGame()‎</code> أو <code>Blackjack.playGame()</code>‎.
</p>

<p>
	تُكتَب عمومًا تَعْليمَة استدعاء أي برنامج فرعي ساكن <code>static</code> ‏(static subroutine call) بالجافا بالصيغة التالية إذا كان البرنامج الفرعي المُستدعَى مُعرَّفًا بنفس الصَنْف (class):
</p>

<pre class="ipsCode">
&lt;subroutine-name&gt;(parameters);
</pre>

<p>
	أو كالتالي إذا كان البرنامج الفرعي مُعرَّفًا بصَنْف آخر:
</p>

<pre class="ipsCode">
&lt;class-name&gt;.&lt;subroutine-name&gt;(parameters);
</pre>

<p>
	يَختلف ذلك عن التوابع غَيْر الساكنة (non-static methods) -سنتناولها لاحقًا-، والتي تنتمي إلى كائنات (objects) وليس أصناف (classes)، ولهذا يُستدعَى ذلك النوع من التوابع من خلال الكائنات (objects) ذاتها لا من خلال أسماء الأصناف.
</p>

<p>
	لاحظ أنه في حين يُمكِن لقائمة المُعامِلات (parameter list) أن تَكُون فارغة (empty)، كما هو الحال بالمثال <code>playGame()‎</code>، فإن كتابة الأقواس (parentheses) بتَعْليمَة الاستدعاء ما تزال ضرورية حتى مع كَوْن ما بينها فارغًا. أما في حالة تخصيص مُعامِل (parameter) أو أكثر بقائمة المُعامِلات (parameter list) بالتعريف الخاص ببرنامج فرعي ما (subroutine definition)، فينبغي عمومًا أن يَتطابَق عدد المُعامِلات المُمرَّرة أثناء استدعاء ذلك البرنامج الفرعي مع العَدَدَ المُخصَّص بذلك التعريف، كما لابُدّ بطبيعة الحال أن تَتطابَق أنواع تلك المُعامِلات المُمرَّرة بتَعْليمَة الاستدعاء مع نوعها المُناظِر بنفس ذلك التعريف.
</p>

<h2>
	البرامج الفرعية بالبرامج
</h2>

<p>
	سنُعطي الآن مثالًا عما قد يبدو عليه البرنامج (program) عند تَضمُّنه لبرنامج فرعي آخر غَيْر البرنامج <code>main()‎</code>. سنَكتُب تحديدًا برنامجًا للعبة تخمين، يَختار فيه الحاسوب عددًا عشوائيًا بين العددين ١ و ١٠٠، ثُمَّ يُحاول المُستخدِم تخمين ذلك العدد، ليُخبره الحاسوب بَعْدها عما إذا كان تخمينه أكبر أو أقل أو يُساوِي العَدَد الصحيح، وبحيث يَفوز المُستخدِم بالمباراة إذا تَمكَّن من تخمين العدد الصحيح خلال ٦ تخمينات كحد أقصى. أخيرًا، يَستطيع المُستخدِم اختيار الاستمرار بلعب مباراة إضافية بنهاية كل مباراة.
</p>

<p>
	لمّا كانت كل مباراة هي بالنهاية مُهِمّة مُترابطة مُفردة، كان بديهيًا كتابة برنامج فرعي <code>playGame()‎</code> بهدف لعب مباراة تخمين واحدة مع المُستخدِم. سيَستخدِم البرنامج <code>main()‎</code> حَلْقة تَكْرار (loop)، والتي ستَستدعِي ذلك البرنامج الفرعي مع كل مرة يختار فيها المُستخدِم الاستمرار بلعب مباراة إضافية. نحتاج الآن إلى تصميم البرنامج الفرعي <code>playGame()</code>‎ وكتابته، وفي الواقع، يُصمَّم أي برنامج فرعي بنفس طريقة تَصْميم البرنامج <code>main()‎</code>، أيّ نبدأ بكتابة توصيف للخوارزمية (algorithm)، ثم نُطبِق التَصْميم المُتدرج (stepwise refinement). اُنظر الخوارزمية التالية لبرنامج لعبة التخمين مكتوبًا بالشيفرة الوهمية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_18" style="">
<span class="com">// اختر عددًا عشوائيًا </span><span class="pln">
</span><span class="typ">Pick</span><span class="pln"> a random number
</span><span class="com">// طالما لم تنته المباراة</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> the game is not over</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// اقرأ تخمين المستخدم</span><span class="pln">
    </span><span class="typ">Get</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s guess
    </span><span class="com">// اخبر المستخدم عما إذا كان تخمينه صحيحًا أم أكبر أم أقل</span><span class="pln">
    </span><span class="typ">Tell</span><span class="pln"> the user whether the guess is high</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> or correct</span><span class="pun">.</span></pre>

<p>
	يُعدّ الاختبار "طالما لم تنته المباراة" معقدًا نوعًا ما؛ وذلك لأن المباراة قد تنتهي لسببين: إما لأن تخمين المُستخدِم كان صحيحًا أو لوصوله للحد الأقصى من عدد التخمينات المُمكنة، أيّ ٦. أحد أسهل الطرائق للقيام بذلك هو اِستخدَام حَلْقة تَكْرار لا نهائية <code>while (true)‎</code> تحتوي على تَعْليمَة <code>break</code>؛ بهدف إِنهاء الحَلْقة في الوقت المناسب. لاحِظ أننا سنحتاج إلى الاحتفاظ بعَدَد تخمينات المُستخدِم؛ حتى نَتمكَّن من إِنهاء المباراة في حالة وصول المُستخدِم للحد الأقصى من التخمينات. تُصبِح الخوارزمية كالتالي بعد إِجراء التعديلات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_20" style="">
<span class="com">// أسند قيمة عشوائية بين 1 و 100 إلى المتغير computersNumber</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> computersNumber be a random number between </span><span class="lit">1</span><span class="pln"> and </span><span class="lit">100</span><span class="pln">
</span><span class="com">// اضبط قيمة العداد المستخدم لعدّ عدد تخمينات المستخدم</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> guessCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="com">// استمر بتنفيذ الآتي</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">):</span><span class="pln">
    </span><span class="com">// اقرأ تخمين المستخدم</span><span class="pln">
    </span><span class="typ">Get</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s guess
    </span><span class="com">// أزد قيمة العداد بمقدار الواحد</span><span class="pln">
    </span><span class="typ">Count</span><span class="pln"> the guess by adding </span><span class="lit">1</span><span class="pln"> to guess count
    </span><span class="com">// إذا كان تخمين المستخدم صحيحًا</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s guess equals computersNumber</span><span class="pun">:</span><span class="pln">
        </span><span class="com">// بلغ المستخدم بفوزه بالمباراة</span><span class="pln">
        </span><span class="typ">Tell</span><span class="pln"> the user he won
        </span><span class="com">// اخرج من الحلقة</span><span class="pln">
        </span><span class="kwd">break</span><span class="pln"> out of the loop
    </span><span class="com">// إذا وصل العداد للحد الأقصى 6</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> the number of guesses is </span><span class="lit">6</span><span class="pun">:</span><span class="pln">
        </span><span class="com">// بلغ المستخدم بخسارته للمباراة</span><span class="pln">
        </span><span class="typ">Tell</span><span class="pln"> the user he lost
        </span><span class="com">// اخرج من الحلقة</span><span class="pln">
        </span><span class="kwd">break</span><span class="pln"> out of the loop
    </span><span class="com">// إذا كان كان تخمين المستخدم أقل من العدد</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s guess is less than computersNumber</span><span class="pun">:</span><span class="pln">
        </span><span class="com">// بلغ المستخدم بكَوْن التخمين أقل من العدد</span><span class="pln">
        </span><span class="typ">Tell</span><span class="pln"> the user the guess was low
    </span><span class="com">// إذا كان كان تخمين المستخدم أعلى من العدد</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s guess is higher than computersNumber</span><span class="pun">:</span><span class="pln">
        </span><span class="com">// بلغ المستخدم بكَوْن التخمين أكبر من العدد</span><span class="pln">
        </span><span class="typ">Tell</span><span class="pln"> the user the guess was high</span></pre>

<p>
	يُستخدَم التعبير <code>‎(int)(100 * Math.random()) + 1</code> لاختيار عدد عشوائي يقع بين العددين ١ و ١٠٠. اُنظر الشيفرة التالية بلغة الجافا، والتي تَتضمَّن تعريف البرنامج <code>playGame()‎</code> بعد التَّصْريح عن المُتَغيِّرات (variable declarations):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_22" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> playGame</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> computersNumber</span><span class="pun">;</span><span class="pln"> </span><span class="com">// العدد العشوائي</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> usersGuess</span><span class="pun">;</span><span class="pln">      </span><span class="com">// إحدى تخمينات المستخدم</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> guessCount</span><span class="pun">;</span><span class="pln">      </span><span class="com">// عدد تخمينات المستخدم</span><span class="pln">
    computersNumber </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">100</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

    guessCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"What is your first guess? "</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        usersGuess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getInt</span><span class="pun">();</span><span class="pln">  </span><span class="com">// اقرأ تخمين المستخدم</span><span class="pln">
        guessCount</span><span class="pun">++;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">==</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You got it in "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> guessCount
                               </span><span class="pun">+</span><span class="pln"> </span><span class="str">" guesses!  My number was "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> computersNumber</span><span class="pun">);</span><span class="pln">
            </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">  </span><span class="com">// انتهت المباراة بفوز المستخدم</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">guessCount </span><span class="pun">==</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You didn't get the number in 6 guesses."</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You lose.  My number was "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> computersNumber</span><span class="pun">);</span><span class="pln">
            </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">  </span><span class="com">// انتهت المباراة بخسارة المستخدم</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="com">// بلغ المستخدم عما إذا كان تخمينه أكبر أم أصغر من العدد</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">&lt;</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"That's too low.  Try again: "</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">&gt;</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"That's too high.  Try again: "</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// end of playGame()</span></pre>

<p>
	الآن، وبعد انتهائنا من كتابة تعريف البرنامج الفرعي بالأعلى، فإننا سنحتاج إلى معرفة المكان الذي يُفْترَض أن نضع به هذا التعريف؟ ينبغي أن نضعه عمومًا ضِمْن نفس الصَنْف المُتضمِّن للبرنامج <code>main()‎</code>، ولكن ليس داخل البرنامج <code>main</code> ذاته؛ فمن غَيْر المسموح كتابة برنامج فرعي ضِمْن آخر (nested). لمّا كانت لغة الجافا لا تَشترِط أيّ ترتيب معين للبرامج الفرعية المُعرَّفة ضِمْن نفس الصَنْف، فيُمكِنك وضع تعريف <code>playGame()‎</code> قَبْل البرنامج <code>main()‎</code> أو بَعْده. لاحِظ أن البرنامج <code>main()‎</code> سيَستدعِي البرنامج الفرعي <code>playGame()‎</code>، وهو ما يَعنِي مُجرد تَضمُّنه لتَعْليمَة استدعاء (call statement) لذلك البرنامج الفرعي، لا تَضمُّنه لتعريفها الكامل (definition). يتبقَّى لنا الآن كتابة البرنامج <code>main</code>، وهو ما قد تراه أمرًا بغاية السهولة خاصة مع رؤيتنا لكثير من الأمثلة المشابهة مُسْبَّقًا.
</p>

<p>
	سيبدو البرنامج كاملًا كالتالي مع مُراعاة إِمكانية إضافة المزيد من التعليقات (comments):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_24" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">GuessingGame</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Let's play a game.  I'll pick a number between"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"1 and 100, and you try to guess it."</span><span class="pun">);</span><span class="pln">
        boolean playAgain</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            playGame</span><span class="pun">();</span><span class="pln">  </span><span class="com">// اِستدعي البرنامج الفرعي لإجراء مباراة    </span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Would you like to play again? "</span><span class="pun">);</span><span class="pln">
            playAgain </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnBoolean</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">playAgain</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Thanks for playing.  Goodbye."</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية main </span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> playGame</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> computersNumber</span><span class="pun">;</span><span class="pln"> </span><span class="com">// العدد العشوائي</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> usersGuess</span><span class="pun">;</span><span class="pln">      </span><span class="com">// إحدى تخمينات المستخدم</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> guessCount</span><span class="pun">;</span><span class="pln">      </span><span class="com">// عدد تخمينات المستخدم</span><span class="pln">

        computersNumber </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">100</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

        guessCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"What is your first guess? "</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            usersGuess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getInt</span><span class="pun">();</span><span class="pln">  </span><span class="com">// اقرأ تخمين المستخدم</span><span class="pln">
            guessCount</span><span class="pun">++;</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">==</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You got it in "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> guessCount
                                   </span><span class="pun">+</span><span class="pln"> </span><span class="str">" guesses!  My number was "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> computersNumber</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">  </span><span class="com">// انتهت المباراة بفوز المستخدم</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">guessCount </span><span class="pun">==</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You didn't get the number in 6 guesses."</span><span class="pun">);</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You lose.  My number was "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> computersNumber</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">  </span><span class="com">// انتهت المباراة بخسارة المستخدم</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="com">// بلغ المستخدم عما إذا كان تخمينه أكبر أم أصغر من العدد</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">&lt;</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"That's too low.  Try again: "</span><span class="pun">);</span><span class="pln">
            </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">&gt;</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"That's too high.  Try again: "</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية البرنامج الفرعي playGame</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف GuessingGame</span></pre>

<p>
	اِستغرِق الوقت الكافي لقراءة شيفرة البرنامج بالأعلى، وحَاول اِستيعاب طريقة عملها. رُبما تَكُون قد لاحَظت أن تَقسيم البرنامج إلى تابعين (methods) قد جَعل البرنامج عمومًا أسهل في القراءة، وربما حتى في الكتابة حتى مع كَوْنه بسيطًا، أما إذا لم تَلحَظ ذلك، فحاول إقناع نفسك به في الوقت الحالي.
</p>

<h2>
	المتغيرات الأعضاء (Member Variables)
</h2>

<p>
	قد تَتضمَّن الأصناف (classes) أعضاء (members) آخرى، غير البرامج الفرعية، كالمُتَغيِّرات (variables)، فيُمكِن لأي صَنْف التَّصْريح عن مُتَغيِّر ما (variable declaration)، ولا يُقصَد بذلك تلك المُتَغيِّرات المُعرَّفة داخل برنامج فرعي معين، والمَعروفة باسم المُتَغيِّرات المحليّة (local variable)، وإنما تلك المُعرَّفة بمكان يقع خارج أيّ برنامج فرعي ضِمْن الصَنْف. تُعرَف تلك المُتَغيِّرات باسم المُتَغيِّرات العامة (global variable) أو المُتَغيِّرات الأعضاء (member variables)؛ وذلك لكَوْنهم أعضاء (members) ضِمْن الصنف (class).
</p>

<p>
	مثلما هو الحال مع البرامج الفرعية، يُمكِن لأي مُتَغيِّر عضو (member variable) أن يُعرَّف بعدّه عضوًا ساكنًا (static) أو عضوًا غير ساكن (non-static). سنقتصر في هذا الفصل على الساكن منها. بدايةً، ينتمي أي مُتَغيِّر عضو، مُعرَّف باِستخدَام المُبدل <code>static</code>، إلى الصَنْف ذاته المُعرَّف بداخله -لا إلى كائنات ذلك الصَنْف-، فعندما يُحَمِّل مُفسر الجافا (Java interpreter) صَنْف معين، فإنه يُخصِّص مساحة بالذاكرة لكل مُتَغيِّر عضو ساكن ضِمْن ذلك الصَنْف. تُعدِّل أي تَعْليمَة إِسْناد (assignment) إلى واحد من تلك المُتَغيِّرات، وبغض النظر عن مكانها بالبرنامج، من محتوى نفس المساحة بالذاكرة، وكذلك يَلج (access) أي تعبير (expression) يَتضمَّن واحدًا من تلك المُتَغيِّرات، وبغض النظر عن مكانه بالبرنامج، إلى نفس المساحة بالذاكرة ويُعيد نفس القيمة، أيّ تتشارك البرامج الفرعية الساكنة المُعرَّفة بصَنْف ما قيم المُتَغيِّرات الأعضاء الساكنة المُعرَّفة ضِمْن نفس ذلك الصَنْف، فيُمكِن لبرنامج فرعي مُعين ضَبْط قيمة مُتَغيِّر عضو ساكن ما، بحيث يَستخدِمها برنامج فرعي آخر، وهو ما يَختلِف عن المُتَغيِّرات المحليّة المُعرَّفة (local variable) داخل أحد البرامج الفرعية؛ حيث تَتوفَّر فقط بينما يُنفَّذ ذلك البرنامج الفرعي، ثم لا يَعُدْ بالإمكان الوُلوج إليها (inaccessible) من خارج ذلك البرنامج الفرعي.
</p>

<p>
	تتشابه تَعْليمَة التَّصْريح (declaration) عن مُتَغيِّر عضو (member variable) مع تلك المَسئولة عن التَّصْريح عن أي مُتَغيِّر محليّ تقليدي باستثناء شيئين. الأول هو وقوع التَّصْريح عن المُتَغيِّر العضو بمكان خارج أي برنامج فرعي (مع ذلك ما يزال التَّصْريح ضِمْن الصَنْف نفسه)، والثاني هو إمكانية اِستخدَام المُبدلات (modifiers) مثل <code>static</code> و <code>public</code> و <code>private</code> ضِمْن التَّصْريح. يقتصر هذا الفصل على الأعضاء الساكنة فقط، ولهذا ستَتضمَّن أي تَعْليمَة تَّصْريح عن مُتَغيِّر عضو (member variable) المُبدل <code>static</code>، وربما قد يُستخدَم أيًا من المُبدلين <code>public</code> أو <code>private</code>. على سبيل المثال، انظر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_26" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> usersName</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> numberOfPlayers</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">double</span><span class="pln"> velocity</span><span class="pun">,</span><span class="pln"> time</span><span class="pun">;</span></pre>

<p>
	إذا لم تَستخدِم المُبدل <code>private</code> ضِمْن تَعْليمَة التَّصْريح عن مُتَغيِّر عضو ساكن معين، فإنه يُعامَل افتراضيًا كعضو عام <code>public</code>، أي يُمكن الوُلوج إليه بأي مكان سواء من داخل الصَنْف المُعرَّف به أو من خارج ذلك الصنف. ولكن لاحِظ أنك ستحتاج إلى اِستخدَام مُعرِّف (identifier) مُركَّب على الصورة <strong><class-name>.<variable-name></variable-name></class-name></strong> عند محاولة الإشارة إليه من خارج الصَنْف. فمثلًا، يحتوي الصَنْف <code>System</code> على مُتَغيِّر عضو ساكن عام اسمه هو <code>out</code>، لذلك تستطيع الإشارة إلى ذلك المُتَغيِّر باِستخدَام <code>System.out</code> بأيّ صَنْف خاص بك. مثال آخر هو المُتَغيِّر العضو الساكن العام <code>Math.PI</code> بالصَنْف <code>Math</code>. مثال أخير، وبفَرْض أن لدينا الصَنْف <code>Poker</code>، والذي يُصَرِّح عن مُتَغيِّر عضو ساكن عام، وليَكُن <code>numberOfPlayers</code>، فإنه يُمكِن الإشارة إلى ذلك المُتَغيِّر داخل الصَنْف <code>Poker</code> ببساطة باِستخدَام <code>numberOfPlayers</code>، في المقابل، يُمكِن الإشارة إليه باِستخدَام <code>Poker.numberOfPlayers</code> من خارج الصَنْف.
</p>

<p>
	والآن، لنضيف عدة مُتَغيِّرات أعضاء ساكنة إلى الصَنْف <code>GuessingGame</code> الذي كتبناه مُسْبَّقًا بهذا القسم: أولًا، المُتَغيِّر العضو <code>gamesPlayed</code> بهدف الاحتفاظ بعَدَدَ المباريات التي لعبها المُستخدِم إجمالًا. ثانيًا، المُتَغيِّر العضو <code>gamesWon</code> بهدف الاحتفاظ بعَدَدَ المباريات التي كَسَبها المُستخدِم. يُصَرَّح عن تلك المُتغيرات كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_28" style="">
<span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> gamesPlayed</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> gamesWon</span><span class="pun">;</span></pre>

<p>
	ستَزداد قيمة المُتَغيِّر <code>gamesPlayed</code> بمقدار الواحد دائمًا مع كل عملية اِستدعاء للبرنامج <code>playGame()‎</code>، بينما ستَزداد قيمة المُتَغيِّر <code>gamesWon</code> بمقدار الواحد في حالة فوز المُستخدِم بالمباراة فقط، ثم تُطبَع قيمة المُتَغيِّرين بنهاية البرنامج <code>main()‎</code>. لمّا كان ضروريًا لكِلا البرنامجين الفرعيين <code>playGame()‎</code> و <code>main()‎</code> أن يَلجا إلى نفس قيمتي المُتَغيِّرين، فإنه يَستحِيل اِستخدَام المُتَغيِّرات المحليّة للقيام بنفس الشيء؛ ففي الواقع، يَقتصِر الولوج إلى قيمة مُتَغيِّر محليّ معين على برنامج فرعي وحيد، هو البرنامج الفرعي الذي عَرَّفه، وضِمْن نفس الاستدعاء؛ حيث تُسنَد قيمة جديدة للمُتَغيِّرات المحليّة (local variables) مع كل عملية استدعاء للبرنامج الفرعي الشامل لها، وهو ما يَختلِف عن المُتَغيِّرات العامة (global variables)، والتي تَحتفِظ بنفس قيمها بين كل استدعاء والاستدعاء الذي يَليه.
</p>

<p>
	تُهيَئ (initialized) المُتَغيِّرات الأعضاء تلقائيًا بقيم افتراضية بعد التَّصْريح عنها، وهو ما يَختلِف عن المُتَغيِّرات المحليّة ضِمْن البرامج الفرعية، والتي لابُدّ من إِسْناد قيمة لها صراحةً قَبْل اِستخدَامها. تلك القيم الافتراضية هي ذاتها القيم الافتراضية لعناصر المصفوفات، فتُسنَد القيمة صفر افتراضيًا إلى المُتَغيِّرات العددية، بينما تُسنَد القيمة <code>false</code> للمُتَغيِّرات من النوع <code>boolean</code>، في حين يُسنَد المحرف المقابل لقيمة ترميز اليونيكود (Unicode code)‏ <code>‎\u0000</code> للمُتَغيِّرات من النوع المحرفي <code>char</code>، أما القيمة الافتراضية المبدئية للكائنات (objects)، كالسَلاسِل النصية من النوع <code>String</code>، فهي القيمة الفارغة <code>null</code>.
</p>

<p>
	لمّا كان المُتَغيِّرين <code>gamesPlayed</code> و <code>gamesWon</code> من النوع <code>int</code>، فإنهما يُهيَئا أتوماتيكيًا إلى القيمة المبدئية صفر، وهو ما تَصادَف أن يَكُون القيمة المبدئية المناسبة لمُتَغيِّر يُنوَى اِستخدَامه كعَدَّاد (counter). مع ذلك، إذا لم تُناسبك القيمة المبدئية الافتراضية أو حتى إذا كنت تُريد مُجرد التَّصْريح عن نفس القيمة المبدئية لكن بصورة أكثر وضوحًا، فما يزال بإمكانك إِجراء عملية إِسْناد إلى أي من تلك المُتَغيِّرات ببداية البرنامج <code>main()</code>‎.
</p>

<p>
	اُنظر نسخة البرنامج <code>GuessingGame.java</code> بَعْد التعديل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8754_30" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">GuessingGame2</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> gamesPlayed</span><span class="pun">;</span><span class="pln">   </span><span class="com">// العدد الإجمالي للمباريات</span><span class="pln">
    </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> gamesWon</span><span class="pun">;</span><span class="pln">      </span><span class="com">// عدد المباريات التي فاز فيها المستخدم</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       gamesPlayed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       gamesWon </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  </span><span class="com">// لا فائدة فعلية من ذلك لأن الصفر هو القيمة الافتراضية</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Let's play a game.  I'll pick a number between"</span><span class="pun">);</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"1 and 100, and you try to guess it."</span><span class="pun">);</span><span class="pln">
       boolean playAgain</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          playGame</span><span class="pun">();</span><span class="pln">  </span><span class="com">// استدع البرنامج الفرعي للعب مباراة</span><span class="pln">
          </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Would you like to play again? "</span><span class="pun">);</span><span class="pln">
          playAgain </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnBoolean</span><span class="pun">();</span><span class="pln">
       </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">playAgain</span><span class="pun">);</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You played "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> gamesPlayed </span><span class="pun">+</span><span class="pln"> </span><span class="str">" games,"</span><span class="pun">);</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"and you won "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> gamesWon </span><span class="pun">+</span><span class="pln"> </span><span class="str">" of those games."</span><span class="pun">);</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Thanks for playing.  Goodbye."</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// end of main()            </span><span class="pln">

    </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> playGame</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> computersNumber</span><span class="pun">;</span><span class="pln"> </span><span class="com">// العدد العشوائي</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> usersGuess</span><span class="pun">;</span><span class="pln">      </span><span class="com">// إحدى تخمينات المستخدم</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> guessCount</span><span class="pun">;</span><span class="pln">      </span><span class="com">// عدد تخمينات المستخدم</span><span class="pln">

        gamesPlayed</span><span class="pun">++;</span><span class="pln">  </span><span class="com">// أزد العدد الإجمالي للمباريات</span><span class="pln">
        computersNumber </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">100</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

        guessCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"What is your first guess? "</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           usersGuess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getInt</span><span class="pun">();</span><span class="pln">  </span><span class="com">// اقرأ تخمين المستخدم</span><span class="pln">
           guessCount</span><span class="pun">++;</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">==</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You got it in "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> guessCount
                      </span><span class="pun">+</span><span class="pln"> </span><span class="str">" guesses!  My number was "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> computersNumber</span><span class="pun">);</span><span class="pln">
              gamesWon</span><span class="pun">++;</span><span class="pln"> 
              </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">  </span><span class="com">// انتهت المباراة بفوز المستخدم</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">guessCount </span><span class="pun">==</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You didn't get the number in 6 guesses."</span><span class="pun">);</span><span class="pln">
              </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You lose.  My number was "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> computersNumber</span><span class="pun">);</span><span class="pln">
               </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">  </span><span class="com">// انتهت المباراة بخسارة المستخدم</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           </span><span class="com">// بلغ المستخدم عما إذا كان تخمينه أكبر أم أصغر من العدد</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">&lt;</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln">
              </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"That's too low.  Try again: "</span><span class="pun">);</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usersGuess </span><span class="pun">&gt;</span><span class="pln"> computersNumber</span><span class="pun">)</span><span class="pln">
              </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"That's too high.  Try again: "</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية البرنامج الفرعي playGame</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف GuessingGame2</span></pre>

<p>
	بالمناسبة، لم يُستخدَم أي من المُبدلين <code>public</code> و <code>private</code> مع البرامج الفرعية أو المُتَغيِّرات الساكنة <code>static</code> بالأعلى، فما الذي يَعنيه ذلك؟ في الواقع، إذا لم يُخصَّص أي مُبدل وصول (access modifier) لمُتَغيِّر عام (global variable) أو لبرنامج فرعي (subroutine)، فإنه يُصبِح قابلًا للوصول بأيّ مكان يقع ضِمْن حزمة (package) الصَنْف الحاضن له، ولكن ليس بأي حزم آخرى. تقع الأصناف التي لا تُصَرِّح عن وجودها ضِمْن حزمة معينة بالحزمة الافتراضية (default package)، لذا تستطيع جميع الأصناف ضِمْن الحزمة الافتراضية -وهو ما يَشمَل أغلبية الأصناف بهذا الكتاب- الوصول إلى كِلا المُتَغيِّرين <code>gamesPlayed</code> و <code>gamesWon</code> وكذلك استدعاء البرنامج الفرعي <code>playGame()‎</code>. مع ذلك، يُعدّ اِستخدَام المُبدل <code>private</code> أثناء التَّصْريح عن كُلًا من المُتَغيِّرات الأعضاء والبرامج الفرعية عمومًا واحدًا من الممارسات الجيدة إلا إذا كان هناك سببًا يَدعوك لمخالفة ذلك، كما يُفضَّل تَجَنُّب اِستخدَام الحزمة الافتراضية (default package).
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c4/s2.html" rel="external nofollow">Section 2: Static Subroutines and Static Variables</a> من فصل Chapter 4: Programming in the Large I: Subroutines من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1087</guid><pubDate>Sun, 06 Dec 2020 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x635;&#x646;&#x627;&#x62F;&#x64A;&#x642; &#x627;&#x644;&#x633;&#x648;&#x62F;&#x627;&#x621;: &#x627;&#x644;&#x628;&#x631;&#x627;&#x645;&#x62C; &#x627;&#x644;&#x641;&#x631;&#x639;&#x64A;&#x629; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%B5%D9%86%D8%A7%D8%AF%D9%8A%D9%82-%D8%A7%D9%84%D8%B3%D9%88%D8%AF%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%A7%D9%84%D9%81%D8%B1%D8%B9%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1086/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_12/23.png.8288126d15329dbb05fb35ef17d6eb34.png" /></p>

<p>
	تستطيع عمومًا أن تقتطع مجموعة من التَعْليمَات (instructions) المسئولة عن إنجاز مُهِمّة واحدة مُحدَّدة، وتُضمِّنها معًا تحت اسم معين، ومِنْ ثَمَّ، تستطيع التَعامُل مع تلك المُهِمّة كوحدة واحدة مهما بَلغت درجة تعقيدها، يُطلق على تلك الوحدات اسم البرنامج الفرعي (subroutine). والآن، لَمْ يَعُدْ هناك أيّ داعي للقلق بشأن أيّ من تلك الخطوات التي قد يَكُون الحاسوب مضطرًا لتَّنْفيذها أثناء إنجازه لمُهِمّة معينة، وإنما تحتاج فقط لتَذَكُّر اسم البرنامج الفرعي (subroutine) الخاص بتلك المُهِمّة؛ لكي تتَمكَّنْ من استدعائه (call). تُعدّ البرامج الفرعية عمومًا أحد أهم الأدوات الأساسية لتبسيط المسائل المعقدة.
</p>

<p>
	في الواقع، البرامج الفرعية (subroutine) هي أشبه ما تَكُون بـ"صندوق أسود (black box)"؛ لا يُمكِنك رؤية ما بداخله، أو بتعبير أدق، لا ترغب برؤيته؛ لأنك إذا فعلت، فستكون مُضطرًا للتعامل مع ذلك الكم الهائل من التعقيد الذي يُفْترَض لذلك البرنامج الفرعي إخفائه بالأساس. على الجانب الآخر، لا يُمكِن أن يَقْتصِر ذلك الصندوق على عالمه الداخلي، وإلا سيكون عديم الفائدة، بل ينبغي له التَفاعُل مع العالم الخارجي، ولهذا فإنه يحتاج إلى ما يُشبه الواجهة (interface) التي تَسمَح بتَفاعُل ما بداخل الصندوق مع ما هو خارجه. على سبيل المثال، قد يُوفِّر صندوق أسود مادي عدة أزرار قابلة للضغط، أو قرص قابل للضبط، أو عدة فتحات لتمرير المعلومات جيْئةَ وذَهابًا. يحاول الصندوق عمومًا التخلص من التعقيد بإخفائه، ولذلك فإن القاعدة الأولى لأيّ صندوق أسود هي كالتالي: "ينبغي لواجهة (interface) أيّ صندوق أسود أن تَكُون مُبسَّطة، وسَهلة الفهم، ومُعرَّفة بصورة جيدة."
</p>

<p>
	هل توجد صناديق سوداء ضِمْن عالمنا الذي نعيش فيه؟ في الواقع، إنها تُحيط بك من كل جانب: تلفازك، وسيارتك، وهاتفك المحمول، وثلاجتك هي مجرد أمثلة قليلة. على سبيل المثال، تَتَكوَّن واجهة (interface) التلفاز من عدة عناصر هي مفتاحي التَشْغِيل والغَلْق، وجهاز التحكم -ولا تنس بالطبع وضع قابس الكهرباء-، والتي تستطيع من خلالها غَلْق التلفاز، وتَشْغِيله، أو تَغْيِير القناة، أو ضَبْط الصوت، وذلك بدون أيّ فهم لكيفية عَمَل تلك الأشياء. يَنْطَبِق نفس الشيء على هاتفك المحمول على الرغم من كَوْن واجهته أكثر تعقيدًا بعدّة مراحل.
</p>

<p>
	يُسمَى الجزء الداخلي من الصندوق الأسود بالتَّنْفيذ (implementation)، والذي قد يَتمثَل في صورة مجموعة الالكترونيات داخل عُدَّة التلفاز أو في صورة شيفرة البرنامج الفرعي الفعليّة المسئولة عن تَّنْفيذ مهمة البرنامج، وعليه تَكُون القاعدة الثانية لأيّ صندوق أسود كالتالي: "لا حاجة لمَعرِفة أيّ شيء عن الجزء التَّنْفيذي (implementation) الخاص بصندوق أسود لكي تَتَمكَّنْ من اِستخدَامه، وإنما يَكفيك مَعرِفة واجهته (interface)."
</p>

<p>
	تستطيع عمومًا إعادة كتابة الجزء التَّنْفيذي (implementation) لبرنامج فرعي معين طالما لم تتأثر واجهته بذلك التَغْيِير. على سبيل المثال، عندما تغَيَّرت عُدَّة التلفاز الداخلية من اعتمادها على الصمامات المُفْرغَة (vacuum tubes) إلى الترانزستور (Transistor)، لَمْ يَكُن هناك داعي لمَعرِفة أي شيء عن ذلك أو مَعرِفة حتى ما قد يَعنِيه، وبالمثل، يُمكِن إعادة كتابة الجزء الداخلي لأيّ برنامج فرعي؛ ربما بهدف كتابة شيفرة أكثر كفاءة، وذلك بدون إِحداث أي تَغْيِير على البرامج المُستخدِمة لذلك البرنامج الفرعي (subroutine).
</p>

<p>
	تَحَصُّلك على صندوق أسود يَعنِي بالضرورة أن شخصًا ما كان قد صمم تَّنْفيذه (implementation) وبناه، وفي الواقع، يَستفيد كُلًا من المُنفِّذ (implementor) والمُستخدِم من فكرة وجود صندوق أسود، فبالنهاية، يُمكِن اِستخدَام ذلك الصندوق بعَدََدَ لا محدود من المواضع المختلفة، والتي لا يحتاج المُنفِّذ (implementor) أن يَعلم عنها شيئًا، وإنما يَقْتصِر دوره على التأَكُّد من أن ذلك الصندوق يُنفِّذ مُهِمّته المُوكلة إليه تَّنْفيذًا صحيحًا، مع تَوْفِيره لواجهة (interface) سليمة تَسمَح للصندوق بالتَفاعُل مع العالم الخارجي. وعليه تَكُون القاعدة الثالثة لأيّ صندوق أسود كالتالي: "لا يحتاج مُنفِّذ صندوق أسود معين مَعرِفة أيّ شيء عن تلك الأنظمة الأكبر التي ربما قد تُوظِّف ذلك الصندوق داخلها."
</p>

<p>
	يُمكِن القول أن أيّ صندوق أسود يُقسِّم العالم إلى جزئين: الجزء الداخلي أو التَّنْفيذي (implementation) والجزء الخارجي، بحيث تَقع الواجهة (interface) على الحد الفاصل بينهما وتربطهما معًا.
</p>

<p>
	لاحِظ أن الواجهة (interface) ليست مجرد رابط مادي بين صندوق معين وعالمه الخارجي، وإنما تَتضمَّن أيضًا تَوصِيفًا (specification) لما يُنجزه الصندوق بالإضافة إلى تبيان واضح لطريقة اِستخدَام تلك الواجهة. فمثلًا، لا يكفي أن تقول أن التلفاز يُوفِّر مفتاح تَشْغِيل، وإنما لابُدّ من تَحْدِيد إمكانية اِستخدَام ذلك المفتاح لأغراض تَشْغِيل التلفاز وغَلْقه.
</p>

<p>
	دَعْنَا نُعيد صياغة ما تَعنيه الواجهة (interface) بمصطلحات علم الحاسوب (computer science). تَتَكوَّن واجهة أيّ برنامج فرعي (subroutine) من مُكوّنين رئيسيين، الأول هو تَوصِيف صياغي أو نَحوِي (syntactic specification)، والآخر تَوصِيف دلالي (semantic specification). يخبرك الأول بالكيفية التي يُسْتَدعى (call) بها ذلك البرنامج الفرعي، بينما يُحدِّد الثاني المُهِمّة (task) المُوكَلة لذلك البرنامج والتي يُفْترَض له إنجازها. لابدّ من مَعرِفة التوصيف الصياغي (syntactic specification) لبرنامج فرعي معين؛ وذلك لاستدعائه استدعاءً سليمًا، بينما لابُدّ من مَعرِفة توصيفه الدلالي (semantic specification)؛ وذلك لفهم الغرض منه، واِستخدَامه بطريقة فعالة. عادةً ما يُستخدَم مصطلح المواصفة الاصطلاحية للبرنامج الفرعي (contract of subroutine) للإشارة إلى مُكوّني الواجهة -الصياغي والدلالي- معًا.
</p>

<p>
	تقول المواصفة الاصطلاحية (contract) لأيّ برنامج فرعي: "ها هو ما ينبغي القيام به لإستدعائي، وها هو ما سأُنْجِزُه بالمقابل". ينبغي للتعليقات (comments) المكتوبة لبرنامج فرعي معين أن تُبرز مُواصفته الاصطلاحية بصورة واضحة، وهو في الواقع ما لا يَحدُث عمليًا، مما يُؤدي إلى انزعاج المبرمجين الذين قد يكونوا مُضطرّين لاِستخدَام ذلك البرنامج الفرعي.
</p>

<p>
	سأنتقل ببقية هذا الفصل من مجرد الحديث عن الفكرة العامة للصندوق الأسود والبرامج الفرعية إلى تفاصيل كتابة تلك البرامج بلغة الجافا وكيفية اِستخدَامها. ولكن حَاوِل دومًا اِستحضار تلك الأفكار والمبادئ العامة بذهنك؛ لأنها تُبرز الغرض الأساسي من وجود البرامج الفرعية، وتُرشدك لكيفية اِستخدَامها. سيَكُون ذلك أكثر وُضوحًا بوصولنا للقسم ٤.٧ حيث سنناقش البرامج الفرعية كأداة لتطوير البرامج.
</p>

<p>
	تَذكَّر دائمًا أن البرامج الفرعية (subroutines) ليست الصناديق السوداء الوحيدة بعالم البرمجة. على سبيل المثال، يُعدّ الصنف (class) صندوقًا أسودًا، يَتكوَّن من جزئين، أحدهما عام (public) يُمثِل واجهته (interface)، والآخر خاص (private) يُمثِل تَّنْفيذه (implementation) الخَفي. تَنْطَبِق مبادئ الصناديق السوداء عمومًا على كُلًا من الأصناف (classes) والبرامج الفرعية (subroutines).
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c4/s1.html" rel="external nofollow">Section 1: Black Boxes</a> من فصل Chapter 4: Programming in the Large I: Subroutines من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1086</guid><pubDate>Thu, 03 Dec 2020 13:00:00 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x625;&#x644;&#x649; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x648;&#x627;&#x62C;&#x647;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x633;&#x62A;&#x62E;&#x62F;&#x645; &#x627;&#x644;&#x631;&#x633;&#x648;&#x645;&#x64A;&#x629; (GUI) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-gui-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1070/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/22.png.261d2e404f3475264ce1d9537f7fafda.png" /></p>

<p>
	لقد تَعلَّمت، على مدار الفصلين السابقين، نوعية البرمجة المُستخدَمة أثناء كتابة برنامج فرعي وحيد (subroutine)، فيما أطلقنا عليه اسم "البرمجة في نطاق ضيق". سنُركز أكثر خلال الفصول المُتبقّية من الكتاب على بناء البرامج ضِمْن نطاق أوسع، ولكن ما يزال ما تَعلَّمته حتى الآن هو البذرة الأساسية والضرورية لكل ما ستَتَعرَّض له فيما بَعْد.
</p>

<p>
	سنرى، في هذا القسم، كيف يُمكِن تطبيق ما قد تَعلَّمته خلال الفصول السابقة ضِمْن سياق برمجة واجهات المُستخدِم الرسومية (graphical user interface)، والتي تُعرَف اختصارًا باسم GUI، وهو سِّياق مُختلف نوعًا ما عما اعتدته من برامج الطرفيّة النصية. ستَعتمِد برمجة الواجهات الرسومية (GUI) سواء التي سنَتَعرَّض لها خلال هذا القسم أو خلال بقية الكتاب على منصة <code>JavaFX</code>، والتي تَضُمّ مجموعة من الأصناف (classes) المُستخدَمة لكتابة هذه النوعية من البرامج، أيّ أن جميع الأصناف (classes) المذكورة بهذا القسم هي جزء من منصة <code>JavaFX</code>، وبالتالي يَنبغي أن تقوم باستيرادها (import) إلى البرنامج حتى تَتَمكَّن من اِستخدَامها. اُنظر القسم ٢.٦ لمزيد من المعلومات عن تَصرِّيف (compiling) البرامج المُستخدِمة لمنصة <code>JavaFX</code> وكيفية تَشْغِيلها.
</p>

<p>
	عند تَشْغِيل برامج واجهات المُستخدِم الرسومية (GUI)، ستُفتَح نافذة واحدة (window) أو أكثر على شاشة الحاسوب الخاصة بك. يُمكِنك، كمبرمج، التَحكُّم الكامل بما يَظهر على تلك النافذة، وكذلك بالكيفية التي يُمكِن للمُستخدِم التَفاعُل (interact) بها مع النافذة. سنَفْحَص خلال هذا القسم أمثلة بسيطة مثل طباعة بعض الأشكال البسيطة كالخطوط والمستطيلات على النافذة بدون أي تَفاعُل من المُستخدِم، فالنقطة المُهمّة، في الوقت الحالي، هو أن تتعرَّف على الطريقة التي تُستخدَم بها أساليب "البرمجة في نطاق ضيق" ضِمْن سياقات اخرى غَيْر برامج الطرفية المُعتمدة على النصوص، وسترى بنفسك أنه يمكن تطبيق نفس تلك الأساليب لكتابة أيّ برنامج فرعي (subroutine) وليس فقط البرنامج <code>main</code>.
</p>

<h2>
	رسم الأشكال
</h2>

<p>
	ستحتاج إلى أن تَكُون على دراية ببعض المفاهيم كالبكسل (pixels)، وأنظمة الإِحداثيَّات (coordinate systems)؛ كي يتَسَنَّى لك فهم الرسومات الحاسوبية (computer graphics)، ولذلك سنمر على بعض المفاهيم الأساسية سريعًا.
</p>

<p>
	تتكون عامةً شاشة الحاسوب (computer screen) من مربعات صغيرة تُسمى البكسل (pixels)، مُرَتَّبة بصورة صفوف وعواميد، بدقة تَصِل عادةً إلى ١٠٠ بكسل لكل بُوصَة (pixels per inch). تَحتوِي الكثير من الشاشات حاليًا على عدد أكبر بكثير من البكسلات المَلْموسة (physical pixels) لكل بُوصَة، لدرجة أنه مِنْ المُحتمَل لبكسل منصة <code>JavaFX</code> أن يُشير إلى بكسل مَلْموس (physical pixel) بمثل هذه الشاشات عالية الدقة (high-resolution)، ولكنه على الأرجح يُشيِر إلى بكسل مَنطقي (logical pixel)، والتي هي وَحدة قياس تُعادِل ٠.٠١ بوصة تقريبًا.
</p>

<p>
	لمّا كان باستطاعة الحاسوب التَحكُّم بلون البكسل، فإنه، في الواقع، يَرسِم (drawing) الأشكال عن طريق تَغْيِير ألوان البكسلات المُفردة (individual pixels). كل بكسل له زوج من الإِحداثيَّات (coordinates)، يُشار إليها عادة باسم الإِحداثيّ <code>x</code> والإِحداثيّ <code>y</code>، وتُستخدَم لتَحْدِيد المَوْضِع الأفقي (horizontal) والرأسي (vertical) للبكسل على الترتيب. عند الرسم بمساحة مستطيلية الشكل على الشاشة، تَكُون إِحداثيَّات البكسل بالرُكْن العُلوِي الأيسر (upper left corner) هي (٠،٠)، وبحيث تزداد قيمة الإِحداثيّ <code>x</code> من اليسار إلى اليمين، بينما تزداد قيمة الإِحداثيّ <code>y</code> من الأعلى إلى الأسفل. يُستخدَم البكسل لتَحْدِيد الأشكال وتَعرَيفها، فعلى سبيل المثال، يُعرَّف أيّ مستطيل من خلال الإِحداثيّ <code>x</code> والإِحداثيّ <code>y</code> بالرُكْن العُلوِي الأيسر للمستطيل، بالإضافة إلى كُلًا من عَرْضه (width)، وارتفاعه (height) بوَحدة البكسل.
</p>

<p>
	تَعرَض مساحة الرسم (drawing area) بالصورة التالية نطاق كلًا من الإِحداثيَّات <code>x</code> و <code>y</code>، ويُمثِل العَرْض والارتفاع بها حجم مساحة الرسم بوَحدة البكسل:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="53629" data-unique="oyx29kpbl" src="https://academy.hsoub.com/uploads/monthly_2020_11/001Coords_AndShapes.png.4928c0bf92d66d55b9aa615c87167359.png" alt="001Coords_AndShapes.png"></p>

<p>
	بفَرْض أن مساحة الرسم (drawing area) -بالأعلى- مُكوَّنة من ٨٠٠*٥٠٠ بكسل، سيكون المستطيل، الواقع بالجزء العُلوِي الأيسر من الصورة، تقريبًا بعَرْض ٢٠٠ بكسل وارتفاع ١٥٠ بكسل، كما يَقع الرُكْن العُلوِي الأيسر (upper left corner) للمستطيل بالإِحداثيَّات (٥٠،٥٠) تقريبيًا.
</p>

<p>
	يَتمّ الرسم بلغة الجافا باِستخدَام كائن سِّياق رُسومي (graphics context) من النوع <code>GraphicsContext</code>. يَشتمِل هذا الكائن على بعض البرامج الفرعية (subroutines)، مثل برامج (routines) لرسم الأشكال البسيطة كالخطوط، والمستطيلات، والأشكال البيضاوية، والنصوص. (عندما يَظهر النص على الشاشة، يَرسِم الحاسوب حروف النص مثلما يَرسِم أيّ أشكال آخرى). بالإضافة إلى ذلك، يَشتمِل كائن السِّياق الرُسومي (graphics context) أيضًا على مجموعة من البيانات (data)، مثل نوع الخط المُختار حاليًا للرَسْم ولونه. (يُحدِّد نوع الخط كلًا من حجم وشكل الحروف). تَشتمِل بيانات كائن السِّياق أيضًا على سطح رسم (drawing surface)، وهو ما يَتمّ الرسم عليه، وفي حالتنا، سيكون سطح الرسم هو مساحة مُحتوَى النافذة بدون الحواف (border) وشريط العنوان (title bar)، ولكن تَتوفَّر أسطح رَسْم مختلفة يمكن الرَسْم عليها أيضًا.
</p>

<p>
	تُوفِّر منصة <code>JavaFX</code> طريقتين لرسم الأشكال: إِمّا بمَلْئ الشكل (filling) أو بتَحْدِيد حوافه (stroking). مَلْئ الشكل (filling) هو ضَبْط لون كل بكسل بداخله، أمَا تَحْدِيد حواف الشكل (stroking) فهو ضَبْط لون البكسلات الواقعة بحوافه (border)، وهو ما يُشبه عملية سَحب قلم على طول حواف الشكل، وفي هذه الحالة، تُعدّ صفات القلم -كحجمه (width/size) أو ما إذا كان يَستخدِم خط صلب (solid line) أو مُتقطِّع (dashed line)- خاصيات (properties) ضِمْن كائن السِّياق الرُسومي (graphics context). يُخصِّص كائن السِّياق الرُسومي أيضًا لونين مُنفصلين، أحدهما لمَلْئ الأشكال (filling)، والآخر لتَحْدِيد حوافها (stroking). لاحظ اقتصار بعض الأشكال -كالخطوط- على طريقة تَحْدِيد الحواف فقط.
</p>

<p>
	يُستخدَم مُتَغيِّر من النوع <code>GraphicsContext</code> لتَمثيِل السِّياق الرُسومي (graphics context)، ويَحمِل هذا المُتَغيِّر عادةً الاسم <code>g</code>. ليس هذا ضروريًا بالطبع، حيث يَتوقَف اسمه بالنهاية على المُبرمج. نَعرِض هنا بعض البرامج الفرعية (subroutines) المُتوفرة ضِمْن كائن السِّياق الرُسومي <code>g</code>. لاحظ أن كل قيم المُعامِلات العددية هي من النوع <code>double</code>:
</p>

<ul>
<li>
		<p>
			البرنامج الفرعي <code>g.setFill(c)</code>‎: يَضبُط اللون المُستخدَم لمَلْئ الأشكال (filling)، حيث المُعامِل <code>c</code> هو كائن من الصَنْف <code>Color</code>. تَتوفَّر الكثير من الثوابت (constants) المُمثِلة للألوان القياسية (standard colors)، والتي يُمكِن اِستخدَامها كمُعامِل لهذا البرنامج الفرعي. تتراوح الألوان القياسية من الألوان الشائعة مثل <code>Color.BLACK</code> و <code>Color.WHITE</code> و <code>Color.RED</code> و <code>Color.GREEN</code> و <code>Color.BLUE</code> و <code>Color.YELLOW</code>، إلى بعض الألوان الغريبة مثل <code>Color.CORNFLOWERBLUE</code>. (يُمكِنك أيضًا إِنشاء ألوان جديدة مُخصَّصة). على سبيل المثال، إذا أردت مَلْئ الأشكال باللون الأحمر، فإنك ستَستدعِي البرنامج الفرعي <code>g.setFill(Color.RED);</code>‎. لاحظ أن اللون المُخصَّص أثناء الاستدعاء سيُستخدَم لجميع عمليات المَلْئ التالية وحتى الاستدعاء التالي لنفس البرنامج الفرعي، أما الأشكال المَرسومة مُسْبَّقًا فلا تتأثر بهذا التَغْيِير.
		</p>
	</li>
	<li>
		<p>
			البرنامج الفرعي <code>g.setStroke(c)‎</code>: يَضبُط اللون المُستخدَم لتَحْدِيد حواف الأشكال (stroking)، ويَعمَل بصورة مشابهة للبرنامج الفرعي <code>g.setFill</code>.
		</p>
	</li>
	<li>
		<p>
			البرنامج الفرعي <code>g.setLineWidth(w)‎</code>: يَضبُط حجم القلم المُستخدَم خلال عمليات تَحْدِيد الحواف التالية (stroking). لاحظ أن المُعامِل <code>w</code> يَستخدِم وَحدة البكسل.
		</p>
	</li>
	<li>
		<p>
			البرنامج الفرعي <code>g.strokeLine(x1,y1,x2,y2)‎</code>: يَرسِم خطًا مُمتدًا من إِحداثيَّات نقطة البداية (x1,y1) وحتى إِحداثيَّات نقطة النهاية (x2,y2). يُرسَم الخط باللون الأسود وبحجم ١ بكسل افتراضيًا، ومع ذلك، يُمكِنك تَخْصِيص كلًا منهما باستدعاء <code>g.setStroke()‎</code> و <code>g.setLineWidth()</code>‎ على الترتيب.
		</p>
	</li>
	<li>
		<p>
			البرنامج الفرعي <code>g.strokeRect(x,y,w,h)‎</code>: يَرسِم الحواف الخارجية (stroking) لمستطيل مع جوانبه الأفقية والرأسية، بحيث يَبعُد الرُكْن العُلوِي الأيسر (top-left corner) لهذا المستطيل مسافة قدرها <code>x</code> بوَحدة البكسل عن الحافة اليسرى لمساحة الرسم (drawing area)، ومسافة قدرها <code>y</code> بوَحدة البكسل عن حافتها العُلوِية. يُحدِّد كلًا من المُعامِلين <code>w</code> و <code>h</code> عَرْض المستطيل الأفقي وارتفاعه الرأسي بوَحدة البكسل على الترتيب. يُمكِن ضَبْط لون الخط المُستخدَم وحجمه باستدعاء <code>g.setStroke()‎</code> و <code>g.setLineWidth()</code>‎ على الترتيب.
		</p>
	</li>
	<li>
		<p>
			البرنامج الفرعي <code>g.fillRect(x,y,w,h)</code>‎: يَعمَل بصورة مشابهة للبرنامج الفرعي <code>g.strokeRect()</code>‎ باستثناء أنه يَملْئ المستطيل (filling) بدلًا من رسم حوافه الخارجية (stroking). اِستدعي <code>g.setFill</code> لضَبْط اللون المُستخدَم.
		</p>
	</li>
	<li>
		<p>
			البرنامج الفرعي <code>g.strokeOval(x,y,w,h)‎</code>: يَرسِم الحواف الخارجية لشكل بيضاوي. يُرسَم الشكل البيضاوي بحيث يَقع ضِمْن المستطيل الذي كان سيُرسَم في حالة استدعاء <code>g.strokeRect(x,y,w,h)‎</code> بنفس قيم المُعامِلات. لاحِظ أنه يُمكِنك اِستخدَام نفس القيمة لكُلًا من المُعامِلين <code>w</code> و <code>h</code> لرسم حواف دائرة.
		</p>
	</li>
	<li>
		<p>
			البرنامج الفرعي <code>g.fillOval(x,y,w,h)‎</code>: يَعمَل بصورة مشابهة للبرنامج الفرعي <code>g.strokeOval()</code>‎ باستثناء أنه يَملْئ الشكل البيضاوي بدلًا من رَسْم حوافه الخارجية.
		</p>
	</li>
</ul>
<p>
	تُعدّ هذه البرامج الفرعية كافية لرَسْم بعض الصور باِستخدَام الجافا. لنبدأ بشئ بسيط مثل رَسْم عشرة خطوط متوازية، كالتالي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="53630" data-unique="bwhkl0vn1" src="https://academy.hsoub.com/uploads/monthly_2020_11/002Parallel_Lines.png.000011e10eb13a9e48b923c8ca78582c.png" alt="002Parallel_Lines.png"></p>

<p>
	نحتاج أولًا لمجموعة افتراضات هي كالتالي: سيكون طول الخطوط حوالي ٢٠٠ بكسل، والمسافة بين كل خط والخط الذي يَليه حوالي ١٠ بكسل، وأخيرًا، سنفْترِض أن نقطة بداية (start) أول خط تقع بالإِحداثيَّات (١٠٠،٥٠). الآن، كل ما نحتاج إليه لرَسْم خط هو استدعاء البرنامج الفرعي <code>g.strokeLine(x1,y1,x2,y2)‎</code> بقيم مُعامِلات مناسبة. نلاحِظ أن نقطة البداية (start) لجميع الخطوط لها نفس قيمة الإِحداثيّ <code>x</code> ‏(x-coordinate) وتُساوِي ١٠٠، ومِنْ ثَمَّ، سنَستخدِم قيمة ثابتة تُساوِي ١٠٠ كقيمة للمُعامِل <code>x1</code>. لمّا كانت جميع الخطوط بطول ٢٠٠ بكسل، فإننا سنَستخدِم قيمة ثابتة تُساوِي ٣٠٠ كقيمة للمُعامِل <code>x2</code>. في المقابل، تَختلف إِحداثيَّات <code>y</code> ‏(y-coordinates) بكل خط عن الخط الذي يَليه، ولكن يُمكِننا أن نرى أن قيمة الإِحداثيّ <code>y</code> بنقطتي البداية (start) والنهاية (end) لكل خط منها هو نفسه، وعليه، سنَستخدِم مُتَغيِّر وحيد لكُلًا من قيمتي <code>y1</code> و <code>y2</code>، هو المُتَغيِّر <code>y</code>. الآن، أصبح أمر الاستدعاء لرَسْم أحد الخيوط كالتالي <code>g.strokeLine(100,y,300,y)</code>‎. اِفْترَضنا قبلًا أن قيمة المُتَغيِّر <code>y</code> لأول خط هي ٥٠، ثم ستزداد تلك القيمة بمقدار ١٠ مع كل انتقال للخط التالي، مما يَعنِي أننا سنحتاج إلى التأكد من أن قيمة <code>y</code> تأخذ القيمة الصحيحة من متتالية الأعداد. يُمكِننا اِستخدَام حَلْقة تَكْرار <code>for</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_7" style="">
<span class="typ">int</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">   </span><span class="com">// ‫إحداثي y للخط</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">   </span><span class="com">// المتغير المتحكم بالحلقة</span><span class="pln">
y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">50</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫تبدأ y بالقيمة 50 لأول خط</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    g</span><span class="pun">.</span><span class="pln">strokeLine</span><span class="pun">(</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> </span><span class="lit">300</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">);</span><span class="pln">
    y </span><span class="pun">=</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫أزد y بمقدار 10 قبل رسم الخط التالي</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستطيع أيضًا اِستخدَام المُتَغيِّر <code>y</code> ذاته كمُتحكِّم بالحَلْقة (loop control variable). لاحِظ أن قيمة <code>y</code> للخط الأخير هي ١٤٠. انظر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_9" style="">
<span class="typ">int</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">50</span><span class="pun">;</span><span class="pln"> y </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">140</span><span class="pun">;</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    g</span><span class="pun">.</span><span class="pln">strokeLine</span><span class="pun">(</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> </span><span class="lit">300</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">);</span></pre>

<p>
	إذا أردت تلوين الخطوط باللون الأزرق، اِستدعي البرنامج الفرعي <code>g.setStroke(Color.BLUE)‎</code> قبل رَسْمها، حيث سيُستخدَم اللون الأسود افتراضيًا إذا قُمت برَسْمها دون ضَبْط اللون. أما إذا أردت أن يَكُون حجم تلك الخطوط ٣ بكسل، اِستدعي البرنامج الفرعي <code>g.setLineWidth(3)‎</code> قَبْل رَسْمها.
</p>

<p>
	لننتقل إلى مثال أكثر تعقيدًا، فمثلًا، لنَرسِم عددًا كبيرًا من الدوائر بشكل عشوائي سواء فيما يَخُص مَوْضِعها (position) أو لونها. لمّا كنا على علم بعدد قليل من الألوان المُتوفرة، فإننا سنختار عشوائيًا واحدًا من الألوان التالية : الأحمر، والأخضر، والأزرق، والأصفر. سنستعمل تَعْليمَة <code>switch</code> بسيطة للاختيار، وذلك بطريقة شبيهة للمثال بالقسم الفرعي ٣.٦.٤:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_11" style="">
<span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">4</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
        g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Color</span><span class="pun">.</span><span class="pln">RED </span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
        g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Color</span><span class="pun">.</span><span class="pln">GREEN </span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
        g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Color</span><span class="pun">.</span><span class="pln">BLUE </span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
        g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Color</span><span class="pun">.</span><span class="pln">YELLOW </span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لمّا كنا نريد للدوائر أن تكون عشوائية التَموْضع، فسنحتاج إلى اختيار مركز الدوائر (center of circles) بصورة عشوائية. بفَرْض أن عَرْض مساحة الرسم (drawing area) وارتفاعها مُعطيين من خلال المُتَغيِّرين <code>width</code> و <code>height</code> على الترتيب، فسينبغي للمَوْضِع الأفقي (horizontal position) للمركز أن يكون قيمة عشوائية تتراوح من القيمة ٠ وحتى <code>width-1</code>. بالمثل، يَنبغي للمَوْضِع الرأسي (vertical position) لمركز الدائرة أن يَكُون قيمة عشوائية تتراوح من القيمة ٠ وحتى <code>height-1</code>. أخيرًا، ما زِلنا بحاجة لتَحْدِيد حجم الدائرة. سنكتفي، في هذا المثال، باِستخدَام نصف قطر (radius) ثابت لجميع الدوائر مُساوِي للقيمة ٥٠ بكسل. تُرسَم الدائرة باِستخدَام التَعْليمَة <code>g.fillOval(x,y,w,h)‎</code>، لكن، في الواقع، لا يُمثِل المُعامِلان <code>x</code> و <code>y</code>، بهذا الأمر (command)، إِحداثيَّات مركز الدائرة؛ وإنما إِحداثيَّات الرُكْن العُلوِي الأيسر (upper left corner) للمستطيل المرسوم حول الدائرة، ولهذا سنحتاج إلى تَحرِيك مركز الدائرة بمسافة قدرها يُساوِي نصف قطر الدائرة أي ٥٠ بكسل؛ وذلك للحصول على قيم <code>x</code> و <code>y</code> المُناظِرة. في المقابل، يُمثِل المُعامِلان <code>w</code> و <code>h</code> عَرْض وارتفاع المستطيل على الترتيب، واللذين ستكون قيمتهما مُساوِية لضعف نصف قطر الدائرة أي ١٠٠ بكسل بهذا المثال. تُراعِي الشيفرة التالية جميع النقاط المذكورة بالأعلى، وتُستخدَم لرَسْم دائرة عشوائية واحدة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_13" style="">
<span class="pln">centerX </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="pln">width</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
centerY </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="pln">height</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
g</span><span class="pun">.</span><span class="pln">fillOval</span><span class="pun">(</span><span class="pln"> centerX </span><span class="pun">-</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> centerY </span><span class="pun">-</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	لاحِظ أن الشيفرة بالأعلى تُستدَعى بَعْد استدعاء الشيفرة المسئولة عن ضَبْط اللون. تبدو الصورة عامةً بشكل أفضل بَعْد تَحْدِيد حافة الدائرة (border) باللون الأسود (stroking)، ولذلك أضيفت الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_15" style="">
<span class="pln">g</span><span class="pun">.</span><span class="pln">setStroke</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Color</span><span class="pun">.</span><span class="pln">BLACK </span><span class="pun">);</span><span class="pln">
g</span><span class="pun">.</span><span class="pln">strokeOval</span><span class="pun">(</span><span class="pln"> centerX </span><span class="pun">-</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> centerY </span><span class="pun">-</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	وأخيرًا، للحصول على عدد كبير من الدوائر، ضُمِّنت الشيفرة بالأعلى داخل حَلْقة تَكْرار <code>for</code>، ونُفِّذت ٥٠٠ مرة، فكانت الرسمة الناتجة عن البرنامج كالتالي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="53631" data-unique="gzasrozly" src="https://academy.hsoub.com/uploads/monthly_2020_11/003Random_Circles.png.c4939f26b33d5ca92c3447ab7426d5d7.png" alt="003Random_Circles.png"></p>

<h2>
	الرسم داخل برنامج
</h2>

<p>
	كما تعلم، لا يُمكِن لأيّ شيفرة بلغة الجافا أن تكون مُستقلة بذاتها، فلابُدّ لها أن تُكتَب ضِمْن برنامج فرعي (subroutine)، والذي بدوره يَكُون مُعرَّفًا داخل صَنْف (class)، ولهذا تَعرِض الشيفرة التالية التَعرِيف الكامل لبرنامج فرعي (subroutine definition)، والذي يُستخدَم لرَسْم الصورة من المثال السابق :
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_17" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> drawPicture</span><span class="pun">(</span><span class="typ">GraphicsContext</span><span class="pln"> g</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> height</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="typ">Color</span><span class="pun">.</span><span class="pln">WHITE</span><span class="pun">);</span><span class="pln">
    g</span><span class="pun">.</span><span class="pln">fillRect</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">);</span><span class="pln"> </span><span class="com">// املأ لون الخلفية بالأبيض</span><span class="pln">

    </span><span class="com">// As an example, draw a large number of colored disks.</span><span class="pln">
    </span><span class="com">// To get a different picture, erase this code, and substitute your own. </span><span class="pln">

    </span><span class="typ">int</span><span class="pln"> centerX</span><span class="pun">;</span><span class="pln">     </span><span class="com">// ‫احداثي x لمركز القرص</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> centerY</span><span class="pun">;</span><span class="pln">     </span><span class="com">// ‫احداثي y لمركز القرص</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> colorChoice</span><span class="pun">;</span><span class="pln"> </span><span class="com">// قيمة اللون العشوائي</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">       </span><span class="com">// المتغير التحكم بالحلقة</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> count </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln"> count</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        centerX </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="pln">width</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
        centerY </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="pln">height</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">

        colorChoice </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">4</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">());</span><span class="pln">
        </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">colorChoice</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
                g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="typ">Color</span><span class="pun">.</span><span class="pln">RED</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
                g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="typ">Color</span><span class="pun">.</span><span class="pln">GREEN</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
                g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="typ">Color</span><span class="pun">.</span><span class="pln">BLUE</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
                g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="typ">Color</span><span class="pun">.</span><span class="pln">YELLOW</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        g</span><span class="pun">.</span><span class="pln">fillOval</span><span class="pun">(</span><span class="pln"> centerX </span><span class="pun">-</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> centerY </span><span class="pun">-</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
        g</span><span class="pun">.</span><span class="pln">setStroke</span><span class="pun">(</span><span class="typ">Color</span><span class="pun">.</span><span class="pln">BLACK</span><span class="pun">);</span><span class="pln">
        g</span><span class="pun">.</span><span class="pln">strokeOval</span><span class="pun">(</span><span class="pln"> centerX </span><span class="pun">-</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> centerY </span><span class="pun">-</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية drawPicture()</span></pre>

<p>
	هذه هي المرة الأولى التي تَتعرَّض فيها لتَعرِيف برنامج فرعي (subroutine definition) -إلى جانب <code>main()</code>‎-. سنتناول هذا الموضوع تفصيليًا بالفصل التالي، ولكن سنَمر عليه سريعًا هنا، يُتيِح السَطْر الأول من التَعرِيف الولوج لبعض القيم التي يَحتاجها البرنامج الفرعي، وهي السِّياق الرُسومي <code>g</code>، وكلًا من عَرْض وارتفاع مساحة الرسم <code>width</code> و <code>height</code>. يَستقبِل البرنامج الفرعي هذه القيم من مصدر خارجي، ويستطيع اِستخدَامها. ما يَهمّ هنا هو أن تُدرِك أنه لكي تَرِسم شيئًا (يَقصِد الكاتب أن هذا هو هدف البرنامج الفرعي، فاِسم البرنامج الفرعي هو <code>drawPicture</code>)، فستحتاج فقط إلى كتابة مُحتوَى البرنامج الفرعي، مثلما تَكتُب مُحتوَى البرنامج <code>main()‎</code> عند كتابة برنامج (الهدف من <code>main()‎</code>).
</p>

<p>
	يَنبغي لتَعرِيف البرنامج الفرعي (subroutine definition) أن يَكُون بالصَنْف (class) الذي يُعرِّف البرنامج، وهو في هذه الحالة الصَنْف <code>SimpleGraphicsStarter</code>. شَّغِل البرنامج -مُتاح بالكامل بالملف <code>SimpleGraphicsStarter.java</code>- لترى الرَسمة، كما يُمكِنك اِستخدَام هذا البرنامج كنقطة بداية لرَسْم الصور الخاصة بك.
</p>

<p>
	لاحِظ أنك لن تَفهم كل الشيفرة المكتوبة بالبرنامج، لكن ما يزال بإمكانك التَعديل عليها، فلا حاجة إلى فهم الشيفرة بأكملها، كل ما قد يَعَنيك هو الشيفرة الموجودة بالبرنامج الفرعي <code>drawPicture()</code>‎. اِحذف تلك الشيفرة، وضَعْ مكانها شيفرة الرسوم خاصتك، وستَتمكَّن بعدها من عَرْض رسوماتك.
</p>

<p>
	بالمناسبة، قد تُلاحِظ أن الكلمة <code>static</code> مُستخدَمة بتَعرِيف البرنامج الفرعي <code>main()‎</code>، بعكس البرنامج الفرعي <code>drawPicture()‎</code>، الذي لا يَستخدِمها، وهو ما يَعنِي أن البرنامج الفرعي <code>drawPicture()‎</code> موجود بكائن (object) وليس بصَنْف (class). تُعدّ البرامج الفرعية التي تَستخدِم الكلمة <code>static</code> بتَعرِيفعها ساكنة (static)، أما التي لا تَستخدِمها فتُعدّ غَيْر ساكنة (non-static). الفرق بينهما مُهِمّ، ولكنه ليس بالأمر الذي يَنبغي أن تَقْلَق حِياله في الوقت الحاضر؛ حيث سنتناوله تفصيليًا بالفصل الخامس على أية حال.
</p>

<h2>
	التحريكة (Animation)
</h2>

<p>
	يَعتمِد التَحرِيك الحاسوبي (computer animation) على متتالية من الصور المُنفصلة، يُطلَق على كُل منها اسم الإطار (frame). تُعرَض هذه الصور بشكل سريع واحدة تلو الآخرى، فإذا كان التَغْيِير بين كل صورة والصورة التي تَليها طفيفًا، ستبدو متتالية الصور وكأنها تَحرِيكة مُستمرة (continuous animation). يُمكِنك اِستخدَام المثال التوضيحي بالملف <code>SimpleAnimationStarter.java</code> كنقطة بداية، حيث يَحتوِي على البرنامج الفرعي <code>drawFrame()‎</code> المَسؤول عن رَسْم إطار (frame) وحيد ضِمْن تَحرِيكة (animation)، بالإضافة إلى ذلك، يُنفَّذ البرنامج الفرعي <code>drawFrame()‎</code> أتوماتيكيًا حوالي ٦٠ مرة بالثانية، مما يَضمَن استمرار عَرْض الأُطُر (frames)، أيّ أنك تستطيع إِنشاء تَحرِيكة (animation) بمُجرَّد إضافة الشيفرة إلى هذا البرنامج الفرعي. تستطيع تمييز المرة الحالية من التَّنْفيذ من خلال مُتَغيِّرين إضافيين -إلى جانب السِّياق الرُسومي وكُلًا من عَرْض وارتفاع مساحة الرسم- يَستقبِلهما البرنامج الفرعي، وهما <code>frameNumber</code> و <code>elapsedSeconds</code>؛ حيث يأخذ المُتَغيِّر <code>frameNumber</code> القيم ٠، ١، ٢، ٣، .. والتي تَزداد بمقدار الواحد مع كل اِستدعاء للبرنامج الفرعي، أمَا قيمة المُتَغيِّر <code>elapsedSeconds</code> فتُشيِر إلى عدد الثواني التي مَرَّت على تَّنْفيذ التَحرِيكة حتى الآن. إجمالًا، تَستطيع رَسْم صورة مختلفة في كل مرة يُستدَعى فيها البرنامج الفرعي (subroutine) بالاعتماد على قيمة أيًا من هذين المُتَغيِّرين.
</p>

<p>
	سنَرسِم بالمثال التالي مجموعة من المستطيلات المُتداخِلة (nested rectangles)، والتي ستنكمش باتجاه مركز الرَسْمة، مما سيُعطِي انطباعًا زائفًا بوجود حركة لا نهائية (infinite motion). تَعرِض الصورة التالية إِطارًا واحدًا من التَحرِيكة (animation):
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="53632" data-unique="kketfi3uq" src="https://academy.hsoub.com/uploads/monthly_2020_11/004Moving_Rects.png.18b8d1217107d63a5bcc3b3391a18cf7.png" alt="004Moving_Rects.png"></p>

<p>
	لنُفكر كيف يُمكِن رَسْم مثل هذه الصورة. عامةً، يُمكِن اِستخدَام حَلْقة التَكْرار <code>while</code> لرَسْم المستطيلات، بحيث تبدأ أولًا برَسْم المستطيل الخارجي، ثُمَّ تنتقل إلى الداخل وهكذا. يَنبغي الآن أن نُفكر بالمُتَغيِّرات التي سنحتاج إليها خلال حَلْقة التَكْرار (loop)، وكذلك بالطريقة التي ستَتغَيَّر بها قيم تلك المُتَغيِّرات من تَكْرار (iteration) معين إلى التَكْرار الذي يليه. ستساعدنا الملاحظات التالية على مَعرِفة تلك المُتَغيِّرات، أولًا، مع كل تَكْرار، يكون المستطيل المرسوم أصغر منه في المرة السابقة، كما أنه يَتحرك للداخل قليلًا. يتركز عامةً الفارق بين أيّ مستطيلين على حجمهما وإِحداثيَّات (coordinates) رُكْنيهما اليساريين العُلوِيين (upper left corners)، ولهذا سنحتاج، أولًا، إلى مُتَغيِّرين لتَمثيِل كلًا من عَرْض المستطيل وارتفاعه، وهما المُتَغيِّران <code>rectWidth</code> و <code>rectHeight</code> على الترتيب. أما بالنسبة لإِحداثيَّات الرُكْن الأيسر العُلوِي <code>x</code> و <code>y</code>، فيُمكِن تَمثيِل كليهما بمُتَغيِّر وحيد للمستطيل الواحد، هو المُتَغيِّر <code>inset</code>؛ لأن قيمتهما مُتساوِية؛ حيث يَبعُد أيّ مستطيل عن حافتي مساحة الرسم (drawing area) بنفس مقدار المسافة. نُلاحِظ أنه مع كل تَكْرار، تَنقُص قيمة كلًا من عَرْض المستطيل <code>rectWidth</code> وارتفاعه <code>rectHeight</code>، بينما تزداد المسافة <code>inset</code> التي يَبعُدها المستطيل عن الحافتين. أخيرًا، تنتهي حَلْقة التَكْرار <code>while</code> عندما يُصبِح عَرْض المستطيل أو ارتفاعه أقل من أو يُساوِي الصفر. اُنظر خوارزمية رَسْم إِطار (frame) وحيد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_19" style="">
<span class="com">// املأ مساحة الرسم باللون الأبيض</span><span class="pln">
</span><span class="typ">Fill</span><span class="pln"> the drawing area with white
</span><span class="com">// ‫اضبط قيمة inset المبدئية للمستطيل الأول الخارجي</span><span class="pln">
</span><span class="typ">Set</span><span class="pln"> the amount of inset </span><span class="kwd">for</span><span class="pln"> the first rectangle
</span><span class="com">// اضبط قيمة عرض وارتفاع المستطيل الأول الخارجي</span><span class="pln">
</span><span class="typ">Set</span><span class="pln"> the width and height </span><span class="kwd">for</span><span class="pln"> the first rectangle
</span><span class="com">// اضبط اللون المستخدم لتحديد الحواف إلى اللون الأسود</span><span class="pln">
</span><span class="typ">Set</span><span class="pln"> the stroke color to black
</span><span class="com">// طالما كان العرض والارتفاع أكبر من الصفر</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> the width and height are both greater than zero</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// ‫ارسم مستطيل باستخدام البرنامج الفرعي g.strokeRect</span><span class="pln">
    draw a rectangle </span><span class="pun">(</span><span class="kwd">using</span><span class="pln"> the g</span><span class="pun">.</span><span class="pln">strokeRect subroutine</span><span class="pun">)</span><span class="pln">
    </span><span class="com">// ‫أزد قيمة inset حتى ينتقل المستطيل التالي إلى الداخل</span><span class="pln">
    increase the inset </span><span class="pun">(</span><span class="pln">to move the next rectangle over and down</span><span class="pun">)</span><span class="pln">
    </span><span class="com">// ‫انقص عرض وارتفاع المستطيل التالي حتى يصبح المستطيل التالي أصغر</span><span class="pln">
    decrease the width and height </span><span class="pun">(</span><span class="pln">to make the next rectangle smaller</span><span class="pun">)</span></pre>

<p>
	ضُبطَت هذه النسخة من البرنامج بحيث يَبعُد كل مستطيل مسافة قدرها ١٥ بكسل عن المستطيل المُحيِط به، ولهذا فإن قيمة المُتَغيِّر <code>inset</code> تَزداد بمقدار ١٥ بكسل مع كل تَكْرار. في المقابل، يَتقَلص المستطيل حوالي ١٥ بكسل يمينًا ويسارًا، أيّ يَنقُص عَرْض المستطيل بمقدار ٣٠ بكسل. وبالمثل، يَنقُص ارتفاعه بمقدار ٣٠ بكسل مع كل تَكْرار ضِمْن الحلقة.
</p>

<p>
	يَسهُل إعادة كتابة الخوارزمية بلغة الجافا، لكن تتبقَى فقط حاجتنا إلى معرفة القيم المبدئية للمُتَغيِّرات <code>inset</code> و <code>width</code> و <code>height</code> لأول مستطيل-(المستطيل الخارجي). لحساب ذلك، سنُفكر في حقيقة كَوْن الصورة متحركة (animated)، أي يَعتمِد ما نَرسِمه بطريقة ما على رقم الإِطار (frame number) الحالي. لمّا كان الرُكْن الأيسر العُلوِي (top-left corner) للمستطيل الخارجي يتحرك للأسفل وللداخل من أيّ إِطار إلى الإِطار الذي يَليه، فإن قيمة المُتَغيِّر <code>inset</code> المبدئية تزداد مع كل إِطار. قد تُفكر إذًا بضَبْط قيمة المُتَغيِّر <code>inset</code> المبدئية إلى القيمة ٠ بالإِطار رقم ٠، وإلى القيمة ١ بالإطار رقم ١ وهكذا. للأسف، لن يكون هذا صالحًا إلى الأبد؛ فعندما تَصِل التحريكة للإِطار ١٥، يَنبغِي أن يَظهر مستطيل خارجي جديد بمساحة الرَسْم (drawing area)، هو في الواقع ليس جديدًا، وإنما أُعيد فقط ضَبْط قيمة المُتَغيِّر <code>inset</code> المبدئية إلى القيمة ٠. إجمالًا، يَنبغِي لقيمة المُتَغيِّر <code>inset</code> أن تأخذ القيم ٠، ١، ٢، ٣،… حتى تَصِل إلى القيمة ١٤، لتُعاد الكَرَّة من جديد، وهو ما يُمكِن إنجازه باِستخدَام الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_21" style="">
<span class="pln">inset </span><span class="pun">=</span><span class="pln"> frameNumber </span><span class="pun">%</span><span class="pln"> </span><span class="lit">15</span><span class="pun">;</span></pre>

<p>
	لاحِظ أن المستطيل يَملأ مساحة الرسم باستثناء حافة (border) تُحيِط به، عَرْضها يُساوِي قيمة المُتَغيِّر <code>inset</code>، أي بعبارة آخرى، عَرْض المستطيل هو عَرْض مساحة الرسم مطروحًا منه ضعف قيمة المُتَغيِّر <code>inset</code>، وبالمثل لارتفاعه. انظر شيفرة البرنامج الفرعي <code>drawFrame()</code>‎ كاملة بالأسفل والمسئولة عن تَحرِيك المستطيل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4194_23" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> drawFrame</span><span class="pun">(</span><span class="typ">GraphicsContext</span><span class="pln"> g</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> frameNumber</span><span class="pun">,</span><span class="pln"> 
                      </span><span class="kwd">double</span><span class="pln"> elapsedSeconds</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> height</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    g</span><span class="pun">.</span><span class="pln">setFill</span><span class="pun">(</span><span class="typ">Color</span><span class="pun">.</span><span class="pln">WHITE</span><span class="pun">);</span><span class="pln">
    g</span><span class="pun">.</span><span class="pln">fillRect</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="pln">width</span><span class="pun">,</span><span class="pln">height</span><span class="pun">);</span><span class="pln">  </span><span class="com">// املأ مساحة الرسم باللون الأبيض</span><span class="pln">

    </span><span class="com">// المسافة بين بين المستطيل الخارجي ومساحة الرسم</span><span class="pln">
    </span><span class="kwd">double</span><span class="pln"> inset</span><span class="pun">;</span><span class="pln"> 

    </span><span class="kwd">double</span><span class="pln"> rectWidth</span><span class="pun">,</span><span class="pln"> rectHeight</span><span class="pun">;</span><span class="pln">   </span><span class="com">// عرض وطول أحد المستطيلات</span><span class="pln">

    </span><span class="com">// اضبط اللون المستخدم لرسم حواف المستطيل</span><span class="pln">
    g</span><span class="pun">.</span><span class="pln">setStroke</span><span class="pun">(</span><span class="typ">Color</span><span class="pun">.</span><span class="pln">BLACK</span><span class="pun">);</span><span class="pln">  

    </span><span class="com">// إضافة القيمة 0.5 هو أسلوب للحصول على صورة أكثر وضوحًا</span><span class="pln">
    inset </span><span class="pun">=</span><span class="pln"> frameNumber </span><span class="pun">%</span><span class="pln"> </span><span class="lit">15</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">;</span><span class="pln">  

    rectWidth </span><span class="pun">=</span><span class="pln"> width </span><span class="pun">-</span><span class="pln"> </span><span class="lit">2</span><span class="pun">*</span><span class="pln">inset</span><span class="pun">;</span><span class="pln">
    rectHeight </span><span class="pun">=</span><span class="pln"> height </span><span class="pun">-</span><span class="pln"> </span><span class="lit">2</span><span class="pun">*</span><span class="pln">inset</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">rectWidth </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> rectHeight </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        g</span><span class="pun">.</span><span class="pln">strokeRect</span><span class="pun">(</span><span class="pln">inset</span><span class="pun">,</span><span class="pln"> inset</span><span class="pun">,</span><span class="pln"> rectWidth</span><span class="pun">,</span><span class="pln"> rectHeight</span><span class="pun">);</span><span class="pln">
        inset </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">15</span><span class="pun">;</span><span class="pln">       </span><span class="com">// تبعد المستطيلات عن بعضها بمقدار 15 بكسل</span><span class="pln">
        rectWidth </span><span class="pun">-=</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">
        rectHeight </span><span class="pun">-=</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	البرنامج مُتاح بالكامل بالملف <code>MovingRects.java</code>. يُمكِنك أيضًا الإِطلاع على مثال توضيحي آخر للتحريك (animation) بالملف <code>RandomCircles.java</code>، والذي يُضيِف قرصًا ملونًا (colored disk) بشكل عشوائي مع كل إِطار جديد. سيُظهِر لك هذا المثال أن صورة الإِطار لا تُحذَف تلقائيًا قبل إِعادة رسم الإِطار التالي.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s9.html" rel="external nofollow">Section 9: Introduction to GUI Programming</a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1070</guid><pubDate>Sat, 28 Nov 2020 08:46:32 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x625;&#x644;&#x649; &#x627;&#x644;&#x645;&#x635;&#x641;&#x648;&#x641;&#x627;&#x62A; (Arrays) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1069/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/21.png.64062fbce007fd7bd313d4b1dfde826c.png" /></p>

<p>
	تناولنا، بالأقسام السابقة من هذا الفصل، جميع بُنَى التحكُّم (control structures) المُدعَّمة بلغة الجافا، ولكن قبل الانتقال إلى الفصل التالي، سنُلقِي نظرة مبدئية على موضوعين إِضافيين مُرتبطين نوعًا ما ببُنَى التحكُّم.
</p>

<p>
	سنُلقِي في هذا القسم نظرة خاطفة على المصفوفات (arrays)، والتي تُعدّ واحدة من أكثر هياكل البيانات (data structure) شيوعًا. بالإضافة إلى ذلك، تَتطلَّب معالجة المصفوفات (array processing) اِستخدَام بُنَى التحكُّم، وهو ما سيمنحك الفرصة لتطبيق بعضًا مما تَعلَّمته عن بُنَى التحكُّم. سنتحدث في الفصل التالي عن الرسومات الحاسوبية (computer graphics)، والتي ستسمح لك أيضًا باستخدام بُنَى التحكُّم، ولكن بسياق مُختلِف نوعًا ما.
</p>

<h2>
	إنشاء المصفوفات واستخدامها
</h2>

<p>
	يتكون الهيكل البياني (data structure) من مجموعة من العناصر (items)، مُجمَّعة معًا بحيث يُمكِن التَعامُل معها كوحدة واحدة (unit). تُعدّ المصفوفة (array) هيكلًا بيانيًا (data structure)، تُرتَّب فيه العناصر كمتتالية مُرقَّمَة (numbered sequence)، بحيث يُمكِن الإشارة إلى كل عنصر مُفرد بها بواسطة رقم المَوْضِع (position number) خاصته. تَشترِط لغة الجافا -بخلاف بعض لغات البرمجة الأخرى- أن تكون جميع عناصر (items) المصفوفة من نفس النوع، كما يبدأ العدّ فيها دائمًا من الصفر. ستحتاج إلى التَعرُّف على عدة مصطلحات جديدة لتتمكَّن من الحديث عن المصفوفات: أولًا، طول/حجم المصفوفة (length/size of array) هو عدد العناصر (items) الموجودة بها، أما نوع المصفوفة الأساسي (base type of array) فهو نوع عناصرها المُفردة، وأخيرًا، فهرس العنصر (index) هو رقم المَوْضِع (position number) الخاص بالعنصر داخل المصفوفة.
</p>

<p>
	لنفْترِض أنك تريد كتابة برنامج يُمكِنه معالجة الأسماء الخاصة بألف شخص، يَعنِي ذلك أنك في حاجة إلى طريقة للتَعامُل مع كل هذه البيانات. ربما ظننت -قبل تَعرُّفك على هيكل المصفوفة البياني (array)- أن البرنامج سيحتاج إلى ألف مُتَغيِّر ليَحمِل أسماء كل هذه الأشخاص، وأنك ربما ستحتاج إلى ألف تَعْليمَة طباعة كي تَتَمكَّن من طباعة كل هذه الأسماء. سيكون ذلك ضَرْبًا من العبث بكل تأكيد. تستطيع، في الواقع، وضع جميع الأسماء بمصفوفة (array)، يُمثِلها مُتَغيِّر وحيد يَحمِل قائمة الأسماء كاملة. في هذا المثال، لمّا كان هناك ألف اسم مفرد، فإن طول المصفوفة (length) سيُساوِي 1000. ولمّا كان كل عنصر بالمصفوفة من النوع <code>String</code>، فإن نوع المصفوفة الأساسي (base type) هو الصَنْف <code>String</code>. وأخيرًا، سيكون أول اسم داخل المصفوفة بالفهرس 0 (index)، بينما سيكون ثاني اسم بالفهرس 1، وهكذا حتى نَصِل إلى الاسم الأخير، والذي سيكون بالفهرس 999.
</p>

<p>
	يُمكِن لنوع المصفوفة الأساسي (base type of array) أن يكون أي نوع مُدعَّم بلغة الجافا، ولكننا سنكتفي حاليًا بمعالجة المصفوفات التي إِمّا أن يكون نوعها الأساسي هو النوع <code>String</code> أو أن يكون واحدًا من الأنواع الأوَّليّة (primitive types) الثمانية. يُطلَق اسم مصفوفة الأعداد الصحيحة (array of ints) على المصفوفات التي يكون نوعها الأساسي هو <code>int</code>، بينما يُطلَق اسم مصفوفة السَلاسِل النصية (array of Strings) على المصفوفات التي يكون نوعها الأساسي هو <code>String</code>. مع ذلك، لا تُعدّ المصفوفة -إذا أردنا تَحرِي الدقة- قائمة من قيم الأعداد الصحيحة (integers) أو قيم السَلاسِل النصية (strings) أو حتى أيّ قيم اخرى، فمن الأفضل أن تُفكِر بها كقائمة من المُتَغيِّرات من النوع العددي <code>int</code> أو كقائمة من المُتَغيِّرات من النوع <code>String</code> أو من أي نوع آخر، فدائمًا ما يكون هناك خَلطًا (confusion) مُحتمَلًا بين اِستخدَام المُتَغيِّرات (variables) كاسم لمَوْضِع ما بالذاكرة (memory location)، واِستخدَامها كاسم للقيمة المُخزَّنة بهذا المَوْضِع. يُعامَل أي مَوْضِع (position) بالمصفوفة كمُتَغيِّر (variable)، فيُمكِن لهذا المَوْضِع أن يَحمِل قيمة من نوع معين (نوع المصفوفة الأساسي) مثلما يُمكِن لأيّ مُتَغيِّر أن يَحمِل قيمة، كما يُمكِن لتلك القيمة أن تَتغيَّر بأيّ وقت مثلما يُمكِن لقيمة أي مُتَغيِّر أن تَتغيَّر. عادة ما يُطلَق اسم عناصر المصفوفة (elements of array) على مجموعة المُتَغيِّرات المُفردة (individual variables) الموجودة بالمصفوفة وتُكَوِّنها إجمالًا.
</p>

<p>
	عندما تُستخدَم مصفوفة ببرنامج ما، فيُمكِنك -كما ذَكَرت مُسْبَّقًا- الإشارة إليها ككل باِستخدَام مُتَغيِّر، لكنك عادةً ما ستحتاج إلى الإشارة إلى عناصر المصفوفة المُفردة (elements of array) من خلال اسم معين، والذي يَعتمِد على كُلًا من اسم المصفوفة ككل وفهرس (index) العنصر، فتكون صياغة (syntax) الاسم كالتالي <code>namelist[7]‎</code>، حيث <code>namelist</code> هو المُتَغيِّر الذي يُمثِل المصفوفة ككل، بينما يُشيِر <code>namelist[7]‎</code> إلى العنصر الموجود بالفهرس ٧ بتلك المصفوفة. أي يُستخدَم اسم المصفوفة متبوعًا بفهرس العنصر ضِمْن أقواس معقوفة (square brackets) <code>[ ]</code> للإشارة إلى هذا العنصر بتلك المصفوفة. يُعامَل اسم العنصر بهذه الصياغة كأي مُتَغيِّر آخر، فيمكنك أن تُسنِد قيمة إليه، أو أن تَطبَعه، أو أن تَستخدِمه بأيّ تعبير (expression).
</p>

<p>
	تَحتوِي أيّ مصفوفة على مُتَغيِّر -نوعًا ما- يُمثِل طولها (length). فعلى سبيل المثال، إذا كان لديك مصفوفة <code>namelist</code>، فإنك تَستطيع اِستخدَام <code>namelist.length</code> للإشارة إلى طولها. ومع ذلك، لا يُمكِنك إسْنَاد (assign) قيمة إلى ذلك المُتَغيِّر؛ لأنه لا يُمكِن تَغْيِير طول المصفوفة.
</p>

<p>
	يجب أولًا أن تُصَرِّح (declaration) عن مُتَغيِّر مصفوفة (array variable)؛ حتى تَتَمكَّن من اِستخدَامه للاشارة إلى مصفوفة معينة. تَتوفَّر أنواع المصفوفة (array types) لتَخْصِيص نوع تلك المُتَغيِّرات، وبشكل عام، فإن نوع مصفوفة معينة (array type) يتكون من نوع المصفوفة الأساسي (base type) متبوعًا بزوج من الأقواس المعقوفة (square brackets) الفارغة. فمثلًا، يكون مُتَغيِّر مصفوفة (array variable) من النوع <code>String[]‎</code> في حالة إشارته إلى مصفوفة سَلاسِل نصية (array of Strings)، بينما يكون من النوع <code>int[]‎</code> في حالة إشارته إلى مصفوفة أعداد صحيحة (array of ints). اُنظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_7" style="">
<span class="typ">String</span><span class="pun">[]</span><span class="pln"> namelist</span><span class="pun">;</span><span class="pln">
</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> A</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">double</span><span class="pun">[]</span><span class="pln"> prices</span><span class="pun">;</span></pre>

<p>
	يُمكِن للمُتَغيِّرات المُصرَّح عنها بتلك الطريقة الإشارة إلى المصفوفات، لكن لاحِظ أن مُجرَّد التَّصْريح عن المُتَغيِّر (variable declaration) لا يَتسبَّب بالإنشاء الفعليّ للمصفوفة. ينبغي إِسْناد قيمة لمُتَغيِّر المصفوفة (array variable) قبل اِستخدَامه -مثلما هو الحال مع جميع المُتَغيِّرات-، وفي هذه الحالة، تكون القيمة عبارة عن مصفوفة. تَتوفَّر صياغة خاصة (special syntax) للإِنشاء الفعليّ للمصفوفة؛ وذلك لأن المصفوفات -بلغة الجافا- هي بالأساس كائنات (objects)، وهو ما سنؤجل الحديث عنه؛ فهو غَيْر ذي صلة هنا. إجمالًا، يُستخدَم العَامِل <code>new</code> لإنشاء المصفوفات، انظر الأمثلة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_9" style="">
<span class="pln">namelist </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">String</span><span class="pun">[</span><span class="lit">1000</span><span class="pun">];</span><span class="pln">
A </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="lit">5</span><span class="pun">];</span><span class="pln">
prices </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">double</span><span class="pun">[</span><span class="lit">100</span><span class="pun">];</span></pre>

<p>
	تكون الصياغة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_11" style="">
<span class="pun">&lt;</span><span class="pln">array</span><span class="pun">-</span><span class="pln">variable</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">base</span><span class="pun">-</span><span class="pln">type</span><span class="pun">&gt;[&lt;</span><span class="pln">array</span><span class="pun">-</span><span class="pln">length</span><span class="pun">&gt;];</span></pre>

<p>
	يُمكِن اِستخدَام عدد صحيح (integer) أو تعبير من النوع العددي (integer-valued expression) لتَحْدِيد طول المصفوفة <strong><array-length></array-length></strong>. بَعْد تَّنْفيذ تَعْليمَة الإِسْناد <code>A = new int[5];</code>‎، أَصبح المُتَغيِّر <code>A</code> يُشير إلى مصفوفة مُكوَّنة من ٥ عناصر (elements) من النوع العددي (integer)، هي <code>A[0]‎</code> و <code>A[1]‎</code> و <code>A[2]</code>‎ و <code>A[3]‎</code> و <code>A[4]‎</code>، كما أصبح <code>A.length</code> يَحمِل القيمة ٥.
</p>

<p>
	اُنظر الصورة التالية:
</p>

<p style="text-align: center;">
	<img alt="001Array_OfInts.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53626" data-unique="hx51p635t" src="https://academy.hsoub.com/uploads/monthly_2020_11/001Array_OfInts.png.7a47200d91a129afd34c690e0d7a23c8.png"></p>

<p>
	عند إِنشاء مصفوفة أعداد صحيحة (array of int)، تُهيَئ (initialized) جميع عناصر المصفوفة أُتوماتيكيًا بحيث تَحمِل القيمة صفر، مما يَعنِي أن قيم جميع عناصر أيّ مصفوفة أعداد تكون مُساوِية للصفر بمُجرَّد إِنشاؤها. في المقابل، تَحمِل جميع عناصر أيّ مصفوفة قيم منطقية (array of boolean) القيمة المنطقية <code>false</code> بمُجرَّد إِنشاؤها. أمّا عناصر أيّ مصفوفة محارف (array of char) فتحتوي على المحرف المقابل لقيمة ترميز اليونيكود (Unicode code) رقم صفر <code>‎\u0000</code> بمُجرَّد إِنشاؤها. وأخيرًا، فإن القيمة المبدئية لعناصر أيّ مصفوفة سَلاسِل نصية (array of String) تكون القيمة الفارغة <code>null</code> (تُستخدَم تلك القيمة مع الكائنات [objects] ولن نتَعرَّض لها حتى القسم ٥.١ لاحقًا).
</p>

<h2>
	المصفوفات وحلقات التكرار <code>For</code>
</h2>

<p>
	تُعدّ إِمكانية اِستخدَام مُتَغيِّر من النوع العددي (integer) أو حتى اِستخدَام تعبير من النوع العددي (integer-valued expression) كفهرس للعنصر (index of an element) واحدة من أهم مميزات المصفوفات. فعلى سبيل المثال، إذا كان لديك مصفوفة <code>list</code>، ومُتَغيِّر من النوع العددي الصحيح <code>i</code>، فبإمكانك اِستخدَام <code>list‎</code> أو حتى <code>list[2*i+1]</code>‎ كأسماء مُتَغيِّرات، بحيث تُؤثِر قيمة <code>i</code> على ما يُشيِر إليه المُتَغيِّر فعليًا. يُساعدك ذلك في حالة أردت إِجراء معالجة معينة على جميع عناصر المصفوفة؛ حيث ستستطيع القيام بذلك ضِمْن حَلْقة التَكْرار <code>for</code>. فمثلًا، لطباعة جميع عناصر المصفوفة <code>list</code>، يُمكننا كتابة الآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_13" style="">
<span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">  </span><span class="com">// فهرس المصفوفة</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">list</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في أول مرة تُنْفَّذ فيها الحَلْقة (loop) -أيّ خلال أول تَكْرار (iteration)-، ستكون قيمة <code>i</code> مُساوِية للصفر، أيّ سيُشيِر <code>list</code>‎ إلى <code>list[0]‎</code>، ولذا تُطبَع القيمة المُخزَّنة بالمُتَغيِّر <code>list[0]‎</code>. في المرة الثانية، ستكون قيمة <code>i</code> مُساوِية للواحد، ولذا تُطبَع القيمة المُخزَّنة بالمُتَغيِّر <code>list[1]‎</code>. لمّا كان طول المصفوفة <code>list</code> يُساوِي ٥، فستنتهي حَلْقة التَكْرار (loop) بعد طباعة قيمة المُتَغيِّر <code>list[4]‎</code>؛ لأن قيمة <code>i</code> ستُصبِح مُساوِية للقيمة ٥، مما يَعنِي أن الشَّرْط الاستمراري (continuation condition) للحلقة <code>i &lt; list.length‎‎</code> لم يَعُدْ مُتحقِّقًا بَعْد الآن. لاحِظ أن الشيفرة بالأعلى تُعدّ مثالًا نموذجيًا لاِستخدَام حَلْقة تَكْرار بغرض معالجة مصفوفة.
</p>

<p>
	لنفْحَص عدة أمثلة اخرى، بفَرْض أن <code>A</code> هي مصفوفة أعداد حقيقية (array of double)، وكنا نُريد حِسَاب قيمة متوسط (average) جميع عناصر تلك المصفوفة. يُمكِننا ببساطة اِستخدَام حَلْقة التَكْرار <code>for</code> لحِسَاب حاصل مجموع الأعداد، ومِنْ ثَمَّ نُقسمها على طول المصفوفة، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_15" style="">
<span class="kwd">double</span><span class="pln"> total</span><span class="pun">;</span><span class="pln">    </span><span class="com">// حاصل مجموع الأعداد بالمصفوفة</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> average</span><span class="pun">;</span><span class="pln">  </span><span class="com">// قيمة متوسط الأعداد</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">  </span><span class="com">// فهرس المصفوفة</span><span class="pln">
total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> A</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫أضف قيمة العنصر برقم الموضع i إلى حاصل المجموع</span><span class="pln">
    total </span><span class="pun">=</span><span class="pln"> total </span><span class="pun">+</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">  
</span><span class="pun">}</span><span class="pln">
average </span><span class="pun">=</span><span class="pln"> total </span><span class="pun">/</span><span class="pln"> A</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫A.length هي عدد العناصر</span></pre>

<p>
	مِثال آخر هو محاولة إِيجاد أكبر عَدَد بالمصفوفة <code>A</code> من المثال السابق. سنُنشِئ مُتَغيِّر <code>max</code>، بحيث نُخزِن فيه قيمة أكبر عَدَد مرَّرنا به حتى الآن، ثم سنبدأ بالمرور على جميع عناصر المصفوفة، وأينما وَجدنا عَدَد أكبر من قيمة المُتَغيِّر <code>max</code> الحالية، فإننا سنُسنِد ذلك العَدَد إلى المُتَغيِّر <code>max</code>. بعد الانتهاء من معالجة المصفوفة بالكامل، سيَحتوِي المُتَغيِّر <code>max</code> حتمًا على أكبر عدد داخل المصفوفة ككل. ولكن يَبقى السؤال التالي، ما هي القيمة الأوَّليّة للمُتَغيِّر <code>max</code>؟ ربما ببساطة نَستخدِم قيمة أول عنصر بالمصفوفة، أي <code>A[0]</code>‎، للتهيئة المبدئية للمُتَغيِّر <code>max</code>، ومِنْ ثَمَّ نبدأ عملية البحث عن قيمة أكبر منها بباقي عناصر المصفوفة، أي بدءً من العنصر <code>A[1]‎</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_17" style="">
<span class="kwd">double</span><span class="pln"> max</span><span class="pun">;</span><span class="pln">  </span><span class="com">// اكبر عدد حتى الآن</span><span class="pln">
max </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">   </span><span class="com">// في البداية، أكبر عدد هو قيمة العنصر‫ A[0]</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> A</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> max</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       max </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// ‫بالوصول إلى تلك النقطة، يحتوي max على قيمة أكبر عدد</span></pre>

<p>
	قد تَحتاج أحيانًا إلى معالجة بعض عناصر المصفوفة (elements of the array) وليس كلها. تُستخدَم تَعْليمَة <code>if</code>، في هذه الحالة، بداخل حَلْقة التَكْرار <code>for</code> لتَحْدِيد ما إذا كُنت تُريد معالجة العنصر الحالي أم لا. دعنا نُلقِي نظرة أخرى على مسألة حِسَاب قيمة متوسط (average) عناصر مصفوفة معينة، ولكن في هذه المرة، لنفْترِض أننا نُريد حِسَاب قيمة المتوسط فقط للعناصر غَيْر الصفرية (non-zero elements)، أيّ التي لا تحتوي على القيمة صفر. في هذه الحالة، قد يكون عدد تلك العناصر أقل من طول المصفوفة (length)، ولهذا سنحتاج إلى عدّ العناصر غَيْر الصفرية، والتي أُضيفت فعليًا لحاصل المجموع بدلًا من الاعتماد على طول المصفوفة. انظر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_19" style="">
<span class="kwd">double</span><span class="pln"> total</span><span class="pun">;</span><span class="pln">    </span><span class="com">// حاصل مجموع الأعداد غير الصفرية بالمصفوفة</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">       </span><span class="com">// عدد الأعداد غير الصفرية</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> average</span><span class="pun">;</span><span class="pln">  </span><span class="com">// متوسط الأعداد غير الصفرية</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> A</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        total </span><span class="pun">=</span><span class="pln"> total </span><span class="pun">+</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">  </span><span class="com">// أضف قيمة العنصر إلى حاصل المجموع</span><span class="pln">
        count </span><span class="pun">=</span><span class="pln"> count </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">     </span><span class="com">// أزد قيمة العداد</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">count </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"There were no non-zero elements."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    average </span><span class="pun">=</span><span class="pln"> total </span><span class="pun">/</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">  </span><span class="com">// اِقسم حاصل المجموع على عدد العناصر</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"Average of %d elements is %1.5g%n"</span><span class="pun">,</span><span class="pln">
                            count</span><span class="pun">,</span><span class="pln"> average</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الجلب العشوائي (Random Access)
</h2>

<p>
	اِستخدَمت جميع أمثلة معالجة المصفوفات -التي فَحْصناها حتى الآن- الجَلْب المُتتالي (sequential access)، أي عُولَجت عناصر المصفوفة (elements of the array) بنفس ترتيب حُدُوثها بالمصفوفة واحدًا تلو الآخر. مع ذلك، يُعدّ الجَلْب العشوائي (random access) واحدًا من أهم مميزات المصفوفات، حيث تستطيع الولوج لقيمة أيّ عنصر بالمصفوفة بأيّ وقت وبنفس الكفاءة وعلى قَدَم المُساواة.
</p>

<p>
	دعنا نُلقِي نظرة على إِحدى المسائل المشهورة والمعروفة باِسم مُعْضِلة يوم الميلاد (birthday problem). بفَرْض وجود مجموعة من الأشخاص داخل حجرة، وليَكُن عَدَدهم هو <code>N</code>، فما هي احتمالية أن يكون لاثنين من هؤلاء الأشخاص نفس يوم الميلاد؟ (بمعنى أنهما قد وُلدَا بنفس اليوم، والشهر، ولكن ليس ضروريًا ولادتهما بنفس العام). يُقَلِّل غالبية الناس من شأن هذه الاحتمالية بشدة. سنَفْحَص، في الواقع، نسخة أخرى شبيهة من نفس السؤال: بفَرْض اختيارك لمجموعة أشخاص بشكل عشوائي، بحيث تَفْحَص يوم ميلادهم، فكم عَدَد الأشخاص الذين ستحتاج إلى فَحْص يوم ميلادهم قبلما تَجِد اثنين لهما نفس يوم الميلاد؟ تَعتمِد الإجابة على مِثل هذا السؤال على عدة عوامل عشوائية بالتأكيد، ولكن مع ذلك، يُمكِننا مُحاكاة هذه التجربة باِستخدَام برنامج، بحيث نُنْفِّذه عدة مرات، وهو ما سيُعْطِينا مُؤِشرًا تقريبيًا لعدد هؤلاء الأشخاص.
</p>

<p>
	لمُحاكاة هذه التجربة، سنحتاج إلى معرفة جميع أيام الميلاد التي قد وَجدناها حتى الآن. لمّا كان هناك ٣٦٥ يوم ميلاد مُحتمَل (سنتجاهل الأعوام الكبيسة [leap years])، فإننا سنُنشِئ مصفوفة قيم منطقية (array of boolean) طولها (length) يُساوِي ٣٦٥، بحيث يُناظِر كل عنصر فيها يوم ميلاد مُختلِف، ويُعْلِمنا إذا ما كُنا قد وَجدنا شخصًا بنفس يوم الميلاد المُناظِر للعنصر أم لا. اُنظر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_21" style="">
<span class="pln">boolean</span><span class="pun">[]</span><span class="pln"> used</span><span class="pun">;</span><span class="pln"> 
used </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> boolean</span><span class="pun">[</span><span class="lit">365</span><span class="pun">];</span></pre>

<p>
	بدايةً، ستُرقَّم أيام العام من ٠ إلى ٣٦٤، بحيث يُحدِّد المُتَغيِّر <code>used‎</code> -من النوع المنطقي- ما إذا سبق وأن وَجدنا شخصًا يوم ميلاده هو رقم اليوم (day number)‏ <code>i</code> أم لا، مما يَعنِي أنه سيَحمِل القيمة المنطقية <code>true</code> في تلك الحالة. مبدئيًا، ستكون جميع قيم عناصر المصفوفة <code>used</code> مُساوِية للقيمة المنطقية <code>false</code>، وهو في الواقع ما يَحدُث أتوماتيكيًا عند إِنشاء المصفوفة. عند اختيارنا لشخص ما، يوم ميلاده هو رقم اليوم <code>i</code>، فإننا سنَفْحَص أولًا قيمة المُتَغيِّر <code>used‎</code>، فإذا كانت مُساوِية للقيمة المنطقية <code>true</code>، سيَعنِي ذلك أننا قد وَجدنا الشخص الثاني بنفس يوم الميلاد، ومِنْ ثَمَّ فإننا قد انتهينا. أمّا إذا كانت قيمته مُساوِية للقيمة المنطقية <code>false</code>، فسنَضبُط قيمة المُتَغيِّر <code>used‎</code> إلى القيمة المنطقية <code>true</code>، للإشارة إلى كَوْننا قد وجدنا الشخص الأول بيوم الميلاد ذاك. بَعْد ذلك، سنستمر بتَّنْفيذ البرنامج، فنختار الشخص التالي. اُنظر البرنامج بالأسفل (لاحِظ أننا لم نُحاكِي الأشخاص، فقط أيام الميلاد):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_23" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">BirthdayProblem</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

       </span><span class="com">// لتخزين أيام الميلاد التي وجدنا أشخاص ولدوا بها</span><span class="pln">
       boolean</span><span class="pun">[]</span><span class="pln"> used</span><span class="pun">;</span><span class="pln">  

       </span><span class="com">// عدد الأشخاص الذين تم فحص أيام ميلادهم</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">       

       </span><span class="com">// ‫القيمة المبدئية لجميع العناصر هي false</span><span class="pln">
       used </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> boolean</span><span class="pun">[</span><span class="lit">365</span><span class="pun">];</span><span class="pln">  

       count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

       </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           </span><span class="com">// ‫اختر يوم ميلاد بصورة عشوائية من صفر وحتى 364</span><span class="pln">

          </span><span class="typ">int</span><span class="pln"> birthday</span><span class="pun">;</span><span class="pln">  </span><span class="com">// يوم الميلاد المختار</span><span class="pln">
          birthday </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()*</span><span class="lit">365</span><span class="pun">);</span><span class="pln">
          count</span><span class="pun">++;</span><span class="pln">

          </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"Person %d has birthday number %d%n"</span><span class="pun">,</span><span class="pln"> count</span><span class="pun">,</span><span class="pln"> birthday</span><span class="pun">);</span><span class="pln">

          </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> used</span><span class="pun">[</span><span class="pln">birthday</span><span class="pun">]</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
              </span><span class="com">// وجدنا يوم الميلاد هذا من قبل، انتهينا</span><span class="pln">
             </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">

          used</span><span class="pun">[</span><span class="pln">birthday</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

       </span><span class="pun">}</span><span class="pln"> </span><span class="com">// نهاية‫ while</span><span class="pln">

       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"A duplicate birthday was found after "</span><span class="pln"> 
                                             </span><span class="pun">+</span><span class="pln"> count </span><span class="pun">+</span><span class="pln"> </span><span class="str">" tries."</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف BirthdayProblem</span></pre>

<p>
	ينبغي عليك أن تَقضِي بعض الوقت لدراسة البرنامج بالأعلى؛ وذلك حتى تَفهَم طريقة عمله، وطريقة اِستخدَامه للمصفوفة. شَغِّله أيضًا! ستكتشف أن احتمالية تَكْرار أيام الميلاد ربما هي أكبر مما كنت تَتوقَّع.
</p>

<h2>
	المصفوفات الممتلئة جزئيًا (Partially Full)
</h2>

<p>
	لنفْترِض أن لدينا تطبيقًا، بحيث يتغَيَّر -أثناء تَّنْفيذه- عَدَد العناصر المطلوب تخزينها بمصفوفة ما. لمّا كان من غَيْر المُمكن تَغْيِير طول/حجم (length/size) المصفوفة، كان لابُدّ لنا من اِستخدَام مُتَغيِّر مُنفصل لعدّ المَواضِع المُستخدَمة فعليًا بالمصفوفة. (تَحتوِي بالطبع جميع المَواضِع بأيّ مصفوفة على قيمة ما، ولكن ما يُهِمّنا هو عَدَد المَواضِع التي تَحتوِي على عناصر صالحة ومفيدة).
</p>

<p>
	على سبيل المثال، يَقرأ برنامج ما الأعداد الصحيحة الموجبة (positive integers)، المُدْخَلة مِنْ قِبَل المُستخدِم، بحيث يَتوقَف البرنامج عن القراءة عند إِدْخَال عدد أقل من أو يُساوِي الصفر. يحتاج البرنامج لتَخْزِين الأعداد المُدْخَلة بهدف مُعالجتها لاحقًا (later processing)، ولذلك فإنه يَحتفِظ بها داخل مصفوفة من النوع <code>int[]‎</code>، هي المصفوفة <code>numbers</code>. بفَرْض أنه لن يتمّ إِدْخَال أكثر من ١٠٠ عدد، فإن حجم (length/size) تلك المصفوفة سيكون ١٠٠. نحتاج الآن إلى الإجابة على السؤال التالي: عند إضافة قيمة عنصر (member) جديد بالمصفوفة، بأيّ مَوْضِع سنضعه تحديدًا؟ للإجابة على هذا السؤال، سنحتاج إلى معرفة عَدَد الأعداد التي تمّ فعليًا قرائتها وتَخْزِينها بالمصفوفة، أيّ عَدَد المَواضِع المُستخدَمة فعليًا بالمصفوفة، ولهذا سنَستخدِم مُتَغيِّر من النوع العددي (integer)، وليَكُن المُتَغيِّر <code>count</code>. سيَعمَل هذا المُتَغيِّر كعَدَّاد (counter)، أيّ أننا سنزيد قيمة هذا المُتَغيِّر بمقدار الواحد في كل مرة نُخزِّن فيها عدد جديد بالمصفوفة. الآن، لمّا كان العدد الفعليّ للعناصر يُساوي قيمة المُتَغيِّر <code>count</code>، فلابُدّ أن تلك العناصر مُخزَّنة بالأرقام المَوْضِعية (position numbers) ٠، ١، …، وحتى <code>count - 1</code>، ولذلك فإن رقم المَوْضِع (position number) المتاح التالي هو قيمة المُتَغيِّر <code>count</code>. وعليه، فإن هذا هو المَوْضِع الذي سنُخزِّن فيه العنصر الجديد.
</p>

<p>
	مثال آخر هو برنامج يَقرأ الأعداد المُدْخَلة من قِبَل المُستخدِم، وبحيث يَتوقَف عن القراءة عند إِدْخَال عدد يُساوِي الصفر. الهدف من البرنامج هو طباعة تلك الأعداد بترتيب مُعاكِس (reverse order) للترتيب الأصلي الذي أُدْخلت به. قد يبدو هذا المثال سخيفًا نوعًا ما، ولكنه على الأقل يَتطلَّب أن تكون الأعداد مُخزَّنة بمصفوفة، بعكس أنواع آخرى كثيرة من المعالَجات، والتي يُمكِن إِجراؤها دون الحاجة إلى الاِحتفاظ بقيم الأعداد المُفردة (individual numbers) بذاتها، مثل إِيجاد حاصل مجموع عناصر المصفوفة أو قيمة متوسط تلك العناصر أو قيمة أكبر عدد بها.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_25" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ReverseInputNumbers</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> numbers</span><span class="pun">;</span><span class="pln">  </span><span class="com">// مصفوفة لتخزين القيم المدخلة</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">      </span><span class="com">// عدد الأعداد المخزنة فعليًا بالمصفوفة</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> num</span><span class="pun">;</span><span class="pln">        </span><span class="com">// أحد الأعداد المدخلة من قبل المستخدم</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">          </span><span class="com">// متغير حلقة‫ for</span><span class="pln">

        </span><span class="com">// مصفوفة أعداد صحيحة بطول 100</span><span class="pln">
        numbers </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="lit">100</span><span class="pun">];</span><span class="pln">   
        </span><span class="com">// لم يتم إدخال أي أعداد بعد</span><span class="pln">
        count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">                

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter up to 100 positive integers; enter 0 to end."</span><span class="pun">);</span><span class="pln">

        </span><span class="com">// اقرأ الأعداد وأضفها إلى المصفوفة</span><span class="pln">
        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">   
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"? "</span><span class="pun">);</span><span class="pln">
            num </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">
            </span><span class="com">// الصفر هو إشارة لانتهاء عملية الإدخال</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">num </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            numbers</span><span class="pun">[</span><span class="pln">count</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> num</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫خزن العدد برقم الموضع count</span><span class="pln">
            count</span><span class="pun">++;</span><span class="pln">  </span><span class="com">// أزد العداد بمقدار واحد</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"\nYour numbers in reverse order are:\n"</span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> count </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> numbers</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية main();</span><span class="pln">

</span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية الصنف ReverseInputNumbers</span></pre>

<p>
	مِنْ المُهم أن تُدرِك الدور المزدوج الذي يؤديه المُتَغيِّر <code>count</code>. فبالإضافة إلى كَوْنه يَحمِل عدد العناصر التي أُدْخلت فعليًا إلى المصفوفة، فإنه أيضًا يُمثِل فهرس (index) المَوْضِع التالي المُتاح بالمصفوفة.
</p>

<p>
	عندما يَحيِن موعد طباعة الأعداد الموجودة بالمصفوفة، يكون رقم المَوْضِع الأخير المُستخدَم فعليًا بالمصفوفة <code>count - 1</code>، ولذا تَطبَع حَلْقة التَكْرار <code>for</code> قيم عناصر المصفوفة بداية من رقم المَوْضِع <code>count - 1</code>، ونزولًا إلى المَوْضِع صفر. يُعدّ هذا مثالًا جيدًا لمعالجة عناصر مصفوفة ما بترتيب مُعاكِس (reverse order).
</p>

<p>
	قد تتساءل، ماذا سيَحدُث بالبرنامج إذا حاول المُستخدِم إِدْخَال أكثر من ١٠٠ عدد؟ ستكون النتيجة حُدوث خطأ (error) يَتسبَّب بانهيار (crash) البرنامج؛ فعندما يُدْخِل المُستخدِم العدد رقم ١٠١، سيُحاول البرنامج تَخْزِين ذلك العدد بعنصر مصفوفة <code>number[100]‎</code>. لكن، في الواقع، هذا العنصر غَيْر موجود؛ حيث يُوجد فقط ١٠٠ عنصر بالمصفوفة، وفهرس آخر عنصر بها هو ٩٩، ولذلك ستؤدي محاولة اِستخدَام <code>number[100]‎</code> إلى حُدوث اِعتراض (exception) من النوع <code>ArrayIndexOutOfBoundsException</code>. تُعدّ الاعتراضات من هذا النوع مصدرًا شائعًا لحُدوث أخطاء وقت التَّنْفيذ (run-time errors) بالبرامج التي تَستخدِم المصفوفات.
</p>

<h2>
	المصفوفات ثنائية البعد (Two-dimensional)
</h2>

<p>
	تُعدّ المصفوفات التي تَعامَلنا معها حتى الآن أحادية البعد (one-dimensional)، مما يَعنِي أن المصفوفة تتكون من متتالية من العناصر، والتي يُمكِن تَخَيُّلها وكأنها مَوْضوعة على خط (line). تَتوفَّر أيضًا المصفوفات ثنائية البعد (two-dimensional)، والتي تُوضَع فيها العناصر داخل شبكة مستطيلة الشكل (rectangular grid). سنمر على هذا الموضوع باختصار هنا، ونعود إليه مُجددًا بالقسم ٧.٥.
</p>

<p>
	تُرتَّب عناصر المصفوفة ثنائية البعد (2D/two-dimensional array) بصورة صفوف (rows) وأعمدة (columns). على سبيل المثال، تتكون مصفوفة الأعداد الصحيحة ثنائية البعد (2D array of int) التالية من ٥ صفوف و ٧ أعمدة:
</p>

<p style="text-align: center;">
	<img alt="002Two_Dimensional_Array.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53627" data-unique="kog6gpcz4" src="https://academy.hsoub.com/uploads/monthly_2020_11/002Two_Dimensional_Array.png.3af995d8ebf2d72b29f7c84fbba81df5.png"></p>

<p>
	تتكون الشبكة ٥*٧ بالأعلى من ٣٥ عنصر. تُرقَّم الصفوف بالمصفوفة ثنائية البعد كالتالي: ٠، ١، ٢، …، وحتى عدد الصفوف ناقص واحد. بالمثل، تُرقَّم العواميد من ٠ وحتى عدد العواميد ناقص واحد. يُمكِن الولوج لأيّ عنصر مُفرد (individual element) بالمصفوفة من خلال رقمي الصف (row number) والعمود (column number) خاصته. (لا تبدو المصفوفة بذاكرة الحاسوب كالصورة المَعروضة بالأعلى، فهي مُجرَّد توضيح للبناء المنطقي [logical structure] للمصفوفة)
</p>

<p>
	تُشبه صيغة (syntax) المصفوفات ثنائية البعد (two-dimensional arrays) بلغة الجافا نفس تلك الصيغة المُستخدَمة مع المصفوفات أحادية البعد (one-dimensional arrays)، باستثناء وجود فهرس (index) إِضافي؛ لأن الولوج لأيّ عنصر أَصبح يَتطلَّب كُلًا من رقمي الصف (row number) والعمود (column number). على سبيل المثال، إذا كانت <code>A</code> مصفوفة أعداد صحيحة (array of int) ثنائية البعد، فسيُشيِر <code>A[3][2]‎</code> إلى العنصر الموجود بالصف رقم ٣ والعمود رقم ٢، والذي يَحمِل العدد ١٧، كما هو موضح بالمصفوفة بالأعلى. كذلك، سيكون نوع مُتَغيِّر المصفوفة، في هذه الحالة، هو كلمة <code>int</code> متبوعة بزوجين من الأقواس المعقوفة (square brackets) الفارغة، أيّ <code>int[][]‎</code>.
</p>

<p>
	يمكنك كتابة التالي للتَّصْريح (declare) عن مُتَغيِّر مصفوفة (array variable)، بالإضافة إلى إِنشاء تلك المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_27" style="">
<span class="typ">int</span><span class="pun">[][]</span><span class="pln">  A</span><span class="pun">;</span><span class="pln">
A  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="lit">5</span><span class="pun">][</span><span class="lit">7</span><span class="pun">];</span></pre>

<p>
	يُنشِئ السطر الثاني مصفوفة ثنائية البعد (2D array) مُكوَّنة من ٥ صفوف و ٧ أعمدة. غالبًا ما تُستخدَم حَلْقات التَكْرار <code>for</code> المُتداخِلة (nested) لمعالجة المصفوفات ثنائية البعد. على سبيل المثال، تَطبَع الشيفرة التالية عناصر المصفوفة <code>A</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_29" style="">
<span class="typ">int</span><span class="pln"> row</span><span class="pun">,</span><span class="pln"> col</span><span class="pun">;</span><span class="pln">  </span><span class="com">// متغيرات التحكم بالحلقة احدهما للصف والآخر للعمود</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> row </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> row </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> row</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> col </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> col </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">7</span><span class="pun">;</span><span class="pln"> col</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%7d"</span><span class="pun">,</span><span class="pln">  A</span><span class="pun">[</span><span class="pln">row</span><span class="pun">][</span><span class="pln">col</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمكِن أن يكون النوع الأساسي (base type) لمصفوفة ثنائية البعد أيّ شئ، أيّ أنك تستطيع إِنشاء مصفوفات ثنائية البعد من النوع العددي <code>double</code>، أو النوع <code>String</code>، وهكذا.
</p>

<p>
	توجد عدة اِستخدَامات طبيعية للمصفوفات ثنائية البعد (2D arrays)، والتي تَكُون فيها الشبكة (grid) واضحة مرئيًا. فمثلًا، قد تُخزِن مصفوفة ثنائية البعد محتويات اللوحة (board) بألعاب مثل الشطرنج أو الدَّامَا (checkers). يُوظِّف مثال آخر، بالقسم الفرعي ٤.٧.٣، مصفوفة ثنائية البعد لحفظ ألوان شبكة (grid) مُكوَّنة من مربعات ملونة. يُمكِنك أيضًا تَوظِيف المصفوفات ثنائية البعد بمسائل لا تكون فيها الشبكة واضحة مرئيًا. فمثلًا، لنفْترِض وجود شركة تَملك ٢٥ مَخزنًا. تَحتفِظ الشركة ببيانات الأرباح التي كَسَبَها كل مَخزن شهريًا طوال عام ٢٠١٨. إذا كانت المخازن مُرقَّمة من ٠ إلى ٢٤، وكانت الشهور الاثنى عشر، أي من يناير ٢٠١٨ وحتى ديسمبر ٢٠١٨، مُرقَّمة من ٠ إلى ١١، فمِنْ ثَمَّ، يُمكِن تَخْزِين هذه البيانات بمصفوفة تَحمِل اسم <code>profit</code>، وتُنشَئ كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_31" style="">
<span class="kwd">double</span><span class="pun">[][]</span><span class="pln">  profit</span><span class="pun">;</span><span class="pln">
profit  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">double</span><span class="pun">[</span><span class="lit">25</span><span class="pun">][</span><span class="lit">12</span><span class="pun">];</span></pre>

<p>
	يُمثِل المُتَغيِّر <code>profit[3][2]‎</code> قيمة أرباح المَخزن رقم ٣ بشهر مارس. بصورة أعم، يُمثِل المُتَغيِّر <code>profit[storeNum][monthNum]‎</code> قيمة أرباح المَخزن رقم <code>storeNum</code> بالشهر رقم <code>monthNum</code> (تذكر أن الترقيم يبدأ من صفر.)
</p>

<p>
	لنفْترِض أن مصفوفة الأرباح <code>profit</code> ممتلئة بالبيانات بالفعل. وعليه، يمكن معالجة هذه البيانات بطرائق كثيرة شيقة. على سبيل المثال، يُمكِن حِسَاب الأرباح الكلية للشركة -جميع المَخازن طوال عام ٢٠١٨- بحِسَاب قيمة حاصل مجموع جميع عناصر المصفوفة، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_33" style="">
<span class="kwd">double</span><span class="pln"> totalProfit</span><span class="pun">;</span><span class="pln">  </span><span class="com">// الأرباح الكلية للشركة بعام 2018</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> store</span><span class="pun">,</span><span class="pln"> month</span><span class="pun">;</span><span class="pln">  </span><span class="com">// متغيرات حَلقتي التكرار</span><span class="pln">
totalProfit </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> store </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">25</span><span class="pun">;</span><span class="pln"> store</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> month </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> month </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln"> month</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
      totalProfit </span><span class="pun">+=</span><span class="pln"> profit</span><span class="pun">[</span><span class="pln">store</span><span class="pun">][</span><span class="pln">month</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تحتاج أحيانًا إلى معالجة صف وحيد أو عمود وحيد بالمصفوفة، وليس المصفوفة بكاملها. على سبيل المثال، تستطيع اِستخدَام حَلْقة التَكْرار التالية لحِسَاب قيمة الأرباح الكلية للشركة بشهر ديسمبر، أيّ بالشهر رقم ١١:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9202_35" style="">
<span class="kwd">double</span><span class="pln"> decemberProfit</span><span class="pun">;</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> storeNum</span><span class="pun">;</span><span class="pln">
decemberProfit </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> storeNum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> storeNum </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">25</span><span class="pun">;</span><span class="pln"> storeNum</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   decemberProfit </span><span class="pun">+=</span><span class="pln"> profit</span><span class="pun">[</span><span class="pln">storeNum</span><span class="pun">][</span><span class="lit">11</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قد تجد أن المصفوفات ثنائية البعد (two-dimensional array) مفيدة في بعض الأحيان، ولكنها عمومًا أقل شيوعًا من المصفوفات أحادية البعد (one-dimensional). وفي الواقع، تَسمَح لغة الجافا كذلك بمصفوفات ذات أبعاد أعلى (higher dimension)، ولكن يَنْدُر اِستخدَامها عمليًا.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s8.html" rel="external nofollow">Section 8: Introduction to Arrays</a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1069</guid><pubDate>Thu, 26 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x625;&#x644;&#x649; &#x627;&#x644;&#x627;&#x633;&#x62A;&#x62B;&#x646;&#x627;&#x621;&#x62A; exceptions &#x648;&#x645;&#x639;&#x627;&#x644;&#x62C;&#x62A;&#x647;&#x627; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%AB%D9%86%D8%A7%D8%A1%D8%AA-exceptions-%D9%88%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1068/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/20.png.f717e524a82bb89a769397b103edcba4.png" /></p>

<p>
	بالإضافة إلى بُنَى التحكُّم control structures المُستخدَمة لتَحْدِيد مَسار التحكُّم الطبيعي flow of control بالبرنامج، تُوفِّر لغة الجافا طريقة للتَعامُل مع الحالات الاستثناءية exceptional cases، والتي يُمكِنها تَغْيِير مَسار التحكُّم الطبيعي.
</p>

<p>
	فمثلًا، يُعدّ إنهاء terminate البرنامج وما يَتبعه من طباعة رسالة الخطأ هو مَسار التحكُّم الافتراضي في حالة حُدُوث خطأ أثناء التَّنْفيذ، مع ذلك تَسمَح لغة الجافا بالتقاط catch مثل تلك الأخطاء بصورة تَمنع اِنهيار البرنامج crashing، وبحيث يَتمكَّن المُبرمِج من الرد بصورة ملائمة على الخطأ. تُستخدَم تَعْليمَة <code>try..catch</code> لهذا الغرض، والتي سنكتفي بإلقاء نظرة مَبدئية وغَيْر مُكتملة عليها بهذا القسم؛ ففي الواقع يُعدّ موضوع مُعالجة الأخطاء error handling موضوعًا مُعقدًا نوعًا ما، ولذلك سنتناوله تفصيليًا بالقسم ٨.٣، وعندها سنَسْتَعْرِض التَعْليمَة <code>try..catch</code> بمزيد من التفصيل، ونُوضِح قواعد صياغتها syntax كاملة.
</p>

<h2>
	الاستثناءات
</h2>

<p>
	يُشير مصطلح الاستثناء exception إلى تلك النوعية من الأحَدََاث التي قد تَرغَب عادةً بمُعالجتها عن طريق تَعْليمَة <code>try..catch</code>. يُفضَّل اِستخدَام هذا المصطلح بدلًا من كلمات مثل خطأ error؛ وذلك لأن الاستثناء في بعض الحالات قد لا يُمثِل خَطأ مِنْ الأساس. ربما يُمكِنك التفكير بالاستثناء exception بعدّه اِستثناءًا بمَسار التحكُّم flow of control الطبيعي للبرنامج، أيّ أنه مُجرَّد وسيلة أخرى لتنظيم البرنامج.
</p>

<p>
	تُمثَل الاستثناءات بلغة الجافا باِستخدَام كائنات objects من الصَنْف <code>Exception</code>. تُعرَّف definition عادةً أصناف فرعية subclasses  مُشتقَّة من الصَنْف <code>Exception</code>؛ لتمثيل الاستثناءات الفعليّة، بحيث يُمثِل كل صَنْف فرعي subclass نوعًا مختلفًا من الاستثناءات. سنفْحَص بهذا القسم نوعين فقط من الاستثناءات، هما: <code>NumberFormatException</code> و <code>IllegalArgumentException</code>.
</p>

<p>
	يُمكِن أن يَحدُث الاستثناء <code>NumberFormatException</code> أثناء محاولة تَحْوِيل سِلسِلة نصية string إلى عَدَد number. تُستخدَم الدالتين <code>Integer.parseInt</code> و <code>Double.parseDouble</code> لإِجراء مثل تلك التَحْوِيلات (انُظر القسم الفرعي ٢.٥.٧). فمثلًا، تَستقبِل الدالة <code>Integer.parseInt(str)‎</code> مُعامِلًا parameter من النوع <code>String</code>، فإذا كانت قيمة المُتَغيِّر <code>str</code> -المُمرَّرة مثل قيمة لهذا المُعامِل- تُساوِي السِلسِلة النصية "٤٢"، فعندها ستتمكن الدالة من تَحْوِيلها إلى القيمة ٤٢ من النوع <code>int</code> تَحْوِيلًا صحيحًا. في المقابل، إذا كانت قيمة المُتَغيِّر <code>str</code> تُساوِي السِلسِلة النصية fred، فعندها ستَفشَل الدالة؛ لأن تلك السِلسِلة لا تُعدّ تَمثيلًا نصيًا string representation صالحًا لأيّ قيمة ممكنة من النوع العددي <code>int</code>، لذا سيَحدُث استثناء من النوع <code>NumberFormatException</code> في هذه الحالة، وسينهار crash البرنامج إذا لم يُعالَج handle هذا الاستثناء.
</p>

<p>
	يُمكِن أن يَحدُث الاستثناء <code>IllegalArgumentException</code> عندما تُمرِّر قيمة غَيْر صالحة كمُعامِل parameter إلى برنامج فرعي subroutine. على سبيل المثال، إذا مَرَّرت قيمة سالبة negative كمُعامِل إلى برنامج فرعي، وكان هذا البرنامج الفرعي يَتطلَّب أن تكون قيمة ذلك المُعامِل أكبر من أو تُساوِي الصفر، فمِنْ المُحتمَل أن يَحدُث استثناء من النوع <code>IllegalArgumentException</code>. على الرغم من شيوع حُدُوث ذلك الاستثناء في مثل تلك الحالات، فما يزال لا يُمكننا الجَزْم بحُدُوثه في كل مرة ستُمرِّر فيها قيمة غَيْر صالحة كمُعامِل لبرنامج فرعي؛ ففي الواقع تَتوقَف طريقة التَعامُل مع القيم غَيْر الصالحة على الشخص الذي كَتَب البرنامج الفرعي.
</p>

<h2>
	تعليمة <code>try..catch</code>
</h2>

<p>
	عندما يَحدُث استثناء exception، يُقَال أنه قد بُلِّغ thrown عنه. فعلى سبيل المثال، يُبلِّغ <code>Integer.parseInt(str)‎</code> عن استثناء من النوع <code>NumberFormatException</code> إذا كانت قيمة المُتَغيِّر <code>str</code> المُمرَّرة إليه غَيْر صالحة. تُستخدَم تَعْليمَة <code>try..catch</code> لالتقاط catch الاستثناءات، ومَنعها من التَسبُّب بانهيار crashing البرنامج. تُكتَب هذه التَعْليمَة بالصياغة syntax التالية في أبسط صورها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3666_7" style="">
<span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">exception</span><span class="pun">-</span><span class="kwd">class</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;</span><span class="pln">  </span><span class="pun">&lt;</span><span class="pln">variable</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قد يُشير الصَنْف <strong><exception-class-name></exception-class-name></strong> -بالأعلى- إلى الصَنْف <code>NumberFormatException</code> أو <code>IllegalArgumentException</code> أو أيّ صَنْف class آخر طالما كان من النوع <code>Exception</code>. عندما يُنفِّذ الحاسوب تَعْليمَة <code>try..catch</code>، فإنه سيبدأ بتَّنْفيذ التَعْليمَات الموجودة داخل الجزء <code>try</code> -والمُشار إليها بالتعليمة <strong><statements-1></statements-1></strong>-، فإذا لم يَحدُث استثناء أثناء تَّنْفيذها، فإنه سيتَخَطَّى الجزء <code>catch</code> ليَمضِي قُدُمًا لتَّنْفيذ بقية البرنامج. أما إذا حَدَث استثناء من النوع المُحدَّد وِفقًا للعبارة <strong><exception-class-name></exception-class-name></strong> أثناء التَّنْفيذ، فإنه سيَقفِز مُباشرةً من النقطة التي حَدَث فيها الاستثناء إلى الجزء <code>catch</code> ليُنفِّذ العبارة <strong><statements-2></statements-2></strong>، مُتَخطِّيًا بذلك أيّ تَعْليمَات مُتبقِّية ضِمْن العبارة <strong><statements-1></statements-1></strong> داخل الجزء <code>try</code>. لاحِظ أن تَعْليمَة <code>try..catch</code> بالأعلى ستَلتقِط نوعًا واحدًا فقط من الاستثناءات -النوع المُحدَّد وِفقًا للعبارة <strong><exception-class-name></exception-class-name></strong>-، أما إذا حَدَث استثناء من أي نوع آخر، فسينهار crash البرنامج كالعادة.
</p>

<p>
	تُمثِل عبارة <strong><variable-name></variable-name></strong> كائنًا من نوع الاستثناء المُلتقَط exception object، والذي يَتضمَّن معلومات عن سبب حُدُوث الاستثناء بما في ذلك رسالة الخطأ error message. تستطيع طباعة قيمة هذا الكائن object، على سبيل المثال، أثناء تَّنْفيذ العبارة <strong><statements-2></statements-2></strong>، مما سيترتب عليه طباعة رسالة الخطأ. سيَمضِي الحاسوب لتَّنْفيذ بقية البرنامج بَعْد انتهاءه من تَّنْفيذ الجزء <code>catch</code>؛ فقد اُلتقَط catching الاستثناء، وعُولَج handling، وعليه لم يَتَسبَّب بانهيار البرنامج.
</p>

<p>
	يُعدّ القوسين <code>{</code> و <code>}</code> المُستخدَمين ضِمْن تَعْليمَة <code>try..catch</code> جزءً أساسيًا من صياغة syntax التَعْليمَة، حتى في حالة اِحتوائها على تَعْليمَة واحدة، وهو ما يختلف عن بقية التَعْليمَات الآخرى التي مَررنا بها حتى الآن، والتي يكون فيها اِستخدَام الأقواس أمرًا اختياريًا في حالة التَعْليمَات المُفردة single statement.
</p>

<p>
	بفَرْض أن لدينا مُتَغيِّر <code>str</code> من النوع <code>String</code>، يُحتمَل أن تكون قيمته مُمثِلة لعَدَد حقيقي real صالح، اُنظر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3666_9" style="">
<span class="pun">(</span><span class="pln">real</span><span class="pun">)</span><span class="kwd">double</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   x </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Double</span><span class="pun">.</span><span class="pln">parseDouble</span><span class="pun">(</span><span class="pln">str</span><span class="pun">);</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> </span><span class="str">"The number is "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">NumberFormatException</span><span class="pln"> e </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Not a legal number."</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
   x </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Double</span><span class="pun">.</span><span class="typ">NaN</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا بَلَّغ استدعاء call الدالة‏ <code>Double.parseDouble(str)</code>‎ عن خطأ، فستُنفَّذ التَعْليمَات الموجودة بالجزء <code>catch</code> مع تَخَطِّي تَعْليمَة الخَرْج (output) بالجزء <code>try</code>. يُعالَج الاستثناء، في هذا المثال، بإِسْناد القيمة <code>Double.NaN</code> إلى المُتَغيِّر <code>x</code>. تُشير هذه القيمة إلى عدم حَمْل مُتَغيِّر من النوع <code>double</code> لقيمة عَدَدية.
</p>

<p>
	لا تَحتاج دائمًا إلى اِلتقاط الاستثناءات catch exceptions، والاستمرار بتَّنْفيذ البرنامج. على العكس، فقد يُؤدي ذلك أحيانًا إلى حُدُوث فوضى أكبر فيما بَعْد، ولربما يَكُون عندها من الأفضل السماح ببساطة بانهيار crash البرنامج. مع ذلك، يَكُون التَعافِي من أخطاء معينة مُمكنًا في أحيان آخرى.
</p>

<p>
	لنفْترِض مثلًا أنك تَرغَب بكتابة برنامج يَحسِب متوسط average متتالية من الأعداد الحقيقية real numbers، التي يُدْخِلها المُستخدِم، وبحيث يُمكِنه الإشارة إلى نهاية المتتالية عن طريق إِدْخَال سَطْر فارغ. في الواقع، يُشبه هذا البرنامج المثال الذي تَعرَّضنا له بالقسم ٣.٣، مع الفارق في اِستخدَام القيمة صفر للإشارة إلى انتهاء المتتالية. قد تُفكِر باِستخدَام الدالة function <code>‏TextIO.getlnInt()</code>‎ لقراءة دَخْل المُستخدِم input. ولكن لمّا كانت تلك الدالة تَتَخَطَّى الأسطر الفارغة، فإننا ببساطة لن نتَمكَّنْ من تَحْدِيد السَطْر الفارغ، ولذلك سنَستخدِم بدلًا منها الدالة <code>TextIO.getln()</code>‎، مما سيُمكِّننا من تَحْدِيد السَطْر الفارغ عند إِدْخاله. سنَستخدِم أيضًا الدالة <code>Double.parseDouble</code> لتَحْوِيل الدَخْل -إذا لم يكن سَطْرًا فارغًا- إلى عَدَد حقيقي، وسنستدعيها ضِمْن تَعْليمَة <code>try..catch</code>؛ لتَجَنُّب انهيار البرنامج في حالة إِدْخَال المُستخدِِم عددًا غَيْر صالح. اُنظر شيفرة البرنامج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3666_11" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ComputeAverage2</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">String</span><span class="pln"> str</span><span class="pun">;</span><span class="pln">     </span><span class="com">// مدخل المستخدم</span><span class="pln">
       </span><span class="kwd">double</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">  </span><span class="com">// مدخل المستخدم بعد تحويله إلى عدد</span><span class="pln">
       </span><span class="kwd">double</span><span class="pln"> total</span><span class="pun">;</span><span class="pln">   </span><span class="com">// حاصل مجموع الأعداد المدخلة</span><span class="pln">
       </span><span class="kwd">double</span><span class="pln"> avg</span><span class="pun">;</span><span class="pln">     </span><span class="com">// متوسط الأعداد المدخلة</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">      </span><span class="com">// عدد الأعداد المدخلة</span><span class="pln">
       total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter your numbers, press return to end."</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"? "</span><span class="pun">);</span><span class="pln">
          str </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">
          </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">str</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">""</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
             </span><span class="kwd">break</span><span class="pun">;</span><span class="pln"> </span><span class="com">// اخرج من الحلقة لأن المستخدم أدخل سطر فارغ</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
          </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              number </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Double</span><span class="pun">.</span><span class="pln">parseDouble</span><span class="pun">(</span><span class="pln">str</span><span class="pun">);</span><span class="pln">
              </span><span class="com">// إذا حدث خطأ، سيتم تخطي السطرين التاليين</span><span class="pln">
              total </span><span class="pun">=</span><span class="pln"> total </span><span class="pun">+</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
              count </span><span class="pun">=</span><span class="pln"> count </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
          </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="typ">NumberFormatException</span><span class="pln"> e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Not a legal number!  Try again."</span><span class="pun">);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       avg </span><span class="pun">=</span><span class="pln"> total</span><span class="pun">/</span><span class="pln">count</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"The average of %d numbers is %1.6g%n"</span><span class="pun">,</span><span class="pln"> count</span><span class="pun">,</span><span class="pln"> avg</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span></pre>

<h2>
	استثناءات الصنف <code>TextIO</code>
</h2>

<p>
	يستطيع الصَنْف <code>TextIO</code> قراءة البيانات من عدة مصادر. (انظر القسم الفرعي ٢.٤.٤). فمثلًا، عندما يُحاوِل قراءة قيمة عددية مُدْخَلة من قِبَل المُستخدِم، فإنه يتحقَّق من كون دَخْل المُستخدِم صالحًا، وذلك باِستخدَام طريقة شبيهة للمثال السابق، أيّ عن طريق اِستخدَام حَلْقة التَكْرار <code>while</code> ضِمْن تَعْليمَة <code>try..catch</code>، وبالتالي لا يُبلِّغ عن استثناء. في المقابل، عندما يُحاوِل القراءة من ملف، فلا توجد طريقة واضحة للتَعَافِي من وجود قيمة غَيْر صالحة بالدَخْل input، ولهذا فإنه يُبلِّغ عن استثناء.
</p>

<p>
	يُبلِّغ الصَنْف <code>TextIO</code> -بغرض التبسيط- عن استثناءات من النوع <code>IllegalArgumentException</code> فقط، وذلك بِغَضّ النظر عن نوع الخطأ الفعليّ الذي قد وَاجهه الصَنْف. فمثلًا، إذا حَاولت قراءة ملف تمَّت قراءة جميع محتوياته بالفعل، فسيَحدُث استثناء من الصَنْف <code>IllegalArgumentException</code>. إذا كان لديك رؤية أفضل لكيفية معالجة أخطاء الملفات غَيْر السماح للبرنامج بالانهيار crash، اِستخدِم تَعْليمَة <code>try..catch</code> لالتقاط الاستثناءات من النوع <code>IllegalArgumentException</code>.
</p>

<p>
	لنفْحَص البرنامج التالي لحِسَاب قيمة متوسط average مجموعة من الأعداد. في هذا المثال، وبفَرْض وجود ملف يَحتوِي على أعداد حقيقية real numbers فقط، فإن البرنامج سيَقرأ قيم الأعداد من ذلك الملف تباعًا، ويَحسِب كُلًا من حاصل مجموعها ومتوسطها. لمّا كان عَدَد الأعداد الموجودة بالملف غَيْر مَعلوم، فإننا بحاجة إلى معرفة إلى متى سنستمر بالقراءة. أحد الحلول هو أن نستمر حتى نَصِل إلى نهاية الملف، وعندها سيَحدُث استثناء، والذي لا يُمكِن عدّه في تلك الحالة خطأً فعليًا، وإنما هو فقط الطريقة المُتَّبَعة للإشارة إلى عدم وجود بيانات آخرى بالملف، وعليه، يُمكِننا التقاط هذا الاستثناء وإنهاء البرنامج. بعبارة آخرى، سنَقرأ البيانات داخل حَلْقة تَكْرار <code>while</code> لا نهائية، ونَخْرُج منها فقط عند حُدوث استثناء. يُوظِّف هذا المثال الاستثناءات بعدّها جزءً متوقعًا من مَسار التحكُّم flow of control بالبرنامج، وهو ما قد يُمثِل طريقة غَيْر اعتيادية نوعًا ما لاِستخدَام الاستثناءات.
</p>

<p>
	سنحتاج إلى معرفة اسم الملف حتى نَتَمكَّن من قراءته. سنَسمَح في الواقع للمُستخدِم بإِدْخَال اسم الملف، بدلًا من تَوْفِيره بالشيفرة hard-coding كقيمة ثابتة؛ وذلك بهدف تَعميم البرنامج. لكن قد يُدخِل المُستخدِم اسم ملف غَيْر موجود أساسًا. وعليه، سيُبلَّغ عن استثناء من النوع <code>IllegalArgumentException</code> عندما نَستخدِم الدالة <code>TextIO.readfile</code> لمحاولة فتح ذلك الملف. يُمكِننا أن نَلتقِط catch هذا الاستثناء، ثُمَّ نَطلُب من المُستخدِم إِدْخَال اسم ملف آخر صالح. اُنظر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_251_11" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">AverageNumbersFromFile</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

      </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
         </span><span class="typ">String</span><span class="pln"> fileName</span><span class="pun">;</span><span class="pln">  </span><span class="com">// اسم الملف المدخل من قبل المستخدم</span><span class="pln">

         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter the name of the file: "</span><span class="pun">);</span><span class="pln">
         fileName </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">
         </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">readFile</span><span class="pun">(</span><span class="pln"> fileName </span><span class="pun">);</span><span class="pln">  </span><span class="com">// حاول فتح الملف</span><span class="pln">
            </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">  </span><span class="com">// إذا نجحت عملية الفتح، أخرج من الحلقة</span><span class="pln">
         </span><span class="pun">}</span><span class="pln">
         </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">IllegalArgumentException</span><span class="pln"> e </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Can't read from the file \""</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> fileName </span><span class="pun">+</span><span class="pln"> </span><span class="str">"\"."</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Please try again.\n"</span><span class="pun">);</span><span class="pln">
         </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">

       </span><span class="com">// ‫الصنف TextIO سيقرأ الملف </span><span class="pln">

      </span><span class="kwd">double</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">  </span><span class="com">// عدد مقروء من الملف</span><span class="pln">
      </span><span class="kwd">double</span><span class="pln"> sum</span><span class="pun">;</span><span class="pln">     </span><span class="com">// حاصل مجموع الأعداد المقروءة حتى الآن</span><span class="pln">
      </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">      </span><span class="com">// عدد الأعداد المقروءة حتى الآن</span><span class="pln">

      sum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
      count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

      </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
         </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// تتوقف الحلقة عند حدوث استثناء</span><span class="pln">
             number </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getDouble</span><span class="pun">();</span><span class="pln">
             count</span><span class="pun">++;</span><span class="pln">  </span><span class="com">// يتم تخطي هذه العبارة في حالة حدوث استثناء</span><span class="pln">
             sum </span><span class="pun">+=</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
         </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">IllegalArgumentException</span><span class="pln"> e </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="com">// نتوقع حدوث استثناء عندما نفرغ من قراءة الملف</span><span class="pln">
          </span><span class="com">// تم التقاط الاستثناء فقط حتى نمنع انهيار البرنامج</span><span class="pln">
          </span><span class="com">// لكن ليس هناك ما نفعله لمعالجة الاستثناء لأنه ليس خطأ أساسا</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">

      </span><span class="com">// تمت قراءة جميع محتويات الملف عند هذه النقطة</span><span class="pln">

      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Number of data values read: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> count</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The sum of the data values: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> sum</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> count </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Can't compute an average of 0 values."</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">else</span><span class="pln">
         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The average of the values:  "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">sum</span><span class="pun">/</span><span class="pln">count</span><span class="pun">));</span><span class="pln">

   </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s7.html" rel="external nofollow">Section 7: Introduction to Exceptions and try..catch</a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1068</guid><pubDate>Sun, 22 Nov 2020 13:01:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x644;&#x64A;&#x645;&#x629; &#x627;&#x644;&#x62A;&#x628;&#x62F;&#x64A;&#x644; switch &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%A8%D8%AF%D9%8A%D9%84-switch-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1067/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/19.png.2c6b309b7d40ffba34457489c45d82de.png" /></p>

<p>
	تتوفَّر تَعْليمَتين للتَفْرِيع (branching statements) بلغة الجافا، تناولنا تَعْليمَة <code>if</code> بالقسم السابق، والآن سننتقل إلى تَعْليمَة التَفْرِيع الثانية <code>switch</code>، والتي يُعدّ اِستخدَامها أقل شيوعًا من تَعْليمَة <code>if</code>، ومع ذلك فهي تكون مفيدة أحيانًا للتعبير عن نوع معين من التَفْرِيع المُتعدِّد (multiway branches).
</p>

<h2>
	تعليمة <code>switch</code>
</h2>

<p>
	تَفحْص تَعْليمَة <code>switch</code> قيمة تعبير (expression) معين، لتَقفِز بَعْدها مباشرة إلى مكان ما بالتَعْليمَة، يَتقرَّر ذلك المكان وِفقًا للقيمة الناتجة عن التعبير. لا يُمكِنك اِستخدَام أيّ تعبير (expression) مع تَعْليمَة <code>switch</code>؛ حيث يُسمَح بأنواع معينة فقط، منها الأنواع العددية الصحيحة الأوَّليّة (primitive) مثل <code>int</code> و <code>short</code> و <code>byte</code>، في المقابل لا يُسمَح بالأنواع العددية العَشريّة مثل <code>double</code> و <code>float</code>. تستطيع كذلك اِستخدَام تعبيرات من النوع المحرفي الأوَّليّ <code>char</code> والنوع <code>String</code>. وأخيرًا، يُسمَح باِستخدَام التعدادات (enums) أيضًا. اُنظر القسم الفرعي ٢.٣.٤ لقراءة المزيد عن التعدادات (enums).
</p>

<p>
	كما ذكرنا مُسْبَّقًا، يَقفِز الحاسوب -أثناء تَّنْفيذه لتَعْليمَة <code>switch</code>- إلى مكان ما ضِمْن التَعْليمَة، لذلك كان لابُدّ من وجود طريقة لتَخْصِيص الأماكن المَسموح بالقفز (نَقْل التَحكُّم بصورة أدق) إليها. تُستخدَم عناوين الحالات (case labels) لهذا الغرض، وتُكتَب بصيغة <code>case constant:‎</code>، بحيث يكون الثابت (constant) قيمة مُجرَّدة مُصنَّفة النوع (literal)، والتي لابُدّ أن تكون من نفس نوع التعبير المُستخدَم بتَعْليمَة <code>switch</code>. يَعمَل عنوان الحالة (case label) كعلامة للإشارة إلى المكان الذي يَنبغِي للحاسوب القَفز إليه عندما تؤول قيمة التعبير إلى قيمة الثابت المُخصَّصة. يَتوفَّر أيضًا عنوان الحالة الافتراضي <code>default:</code>‎، والذي يَقفِز الحاسوب إليه إذا لم يَجِد قيمة التعبير ضِمْن قائمة عناوين الحالات (case labels) المُخصَّصة بتَعْليمَة <code>switch</code>.
</p>

<p>
	عادة ما تُستخدَم تَعْليمَة <code>switch</code> بالصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_7" style="">
<span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="str">&lt;expression&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">constant</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;:</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">constant</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;:</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">   </span><span class="com">// أضف مزيد من الحالات</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">constant</span><span class="pun">-</span><span class="pln">N</span><span class="pun">&gt;:</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-</span><span class="pln">N</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">  </span><span class="com">// حالة افتراضية</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-(</span><span class="pln">N</span><span class="pun">+</span><span class="lit">1</span><span class="pun">)&gt;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// نهاية تعليمة switch</span></pre>

<p>
	تُطابِق تَعْليمَة <code>switch</code> بالأعلى تَعْليمَة التَفْرِيع المُتعدِّد (multiway branch)‏ <code>if</code> التالية، وتؤدي نفس وظيفتها. تُعدّ تَعْليمَة <code>switch</code> مع ذلك أكثر كفاءة؛ حيث يُقَيِّم الحاسوب -أثناء تَّنْفيذها- تعبيرًا (expression) وحيدًا فقط، ويَقفِز بَعْدها مباشرةً إلى الحالة (case) المَعنيّة. في المقابل، فإنه قد يَضطر -عند مُعالجته لتَعْليمَة <code>if</code>- إلى تَقييم ما قد يَصِل إلى عدد <code>N</code> من التعبيرات، وذلك قَبْل أن يَتمكَن من تَحْدِيد أي من كُتل التَعْليمَات ينبغي له تَّنْفيذها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_9" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="str">&lt;expression&gt;</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">constant</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// but use .equals for String!!</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> 
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> expression </span><span class="pun">==</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">constant</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> 
    </span><span class="pun">.</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="str">&lt;expression&gt;</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">constant</span><span class="pun">-</span><span class="pln">N</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-</span><span class="pln">N</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> 
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">statements</span><span class="pun">-(</span><span class="pln">N</span><span class="pun">+</span><span class="lit">1</span><span class="pun">)&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في الواقع، لا تَتطلَّب صياغة (syntax) تَعْليمَة <code>switch</code> اِستخدَام تَعْليمَة <code>break</code> في نهاية كل حالة (case) كالمثال بالأعلى، ولكنك إن تَغافلت عنها -وهو ما يُعدّ سليمًا من ناحية الصياغة-، فسيَمضِي الحاسوب قُدُمًا لتَّنْفيذ التَعْليمَات الخاصة بعنوان الحالة (case label) التالي بعدما ينتهي من تَّنْفيذ تَعْليمَات الحالة الصحيحة. نادرًا ما تكون طريقة التَّنْفيذ تلك هي ما يَنتويه المبرمج، ولذلك اُعتيد اِستخدَام تَعْليمَة <code>break</code> بنهاية كل حالة؛ لإجبار الحاسوب على القفز إلى نهاية تَعْليمَة <code>switch</code>، مُتَخطِّيًا بذلك جميع الحالات الآخرى.
</p>

<p>
	ملحوظة قد لا تستطيع استيعابها حتى تَقرأ الفصل التالي: تَحلّ تَعْليمَة <code>return</code> أحيانًا مَحَلّ تَعْليمَات <code>break</code> -المُستخدَمة ضِمْن تَعْليمَة <code>switch</code>- بالبرامج الفرعية (subroutine)، ويؤدي تَّنْفيذها إلى إنهاء كُلًا من تَعْليمَة <code>switch</code> وكذلك البرنامج الفرعي.
</p>

<p>
	يُمكِنك تَرك واحدة أو أكثر من عناوين الحالات (case labels) فارغة تمامًا بدون أيّ تَعْليمَات، وحتى بدون تَعْليمَة <code>break</code>، مما سيؤدي إلى وجود متتالية من عناوين الحالات (case label) بثوابت مختلفة. في تلك الحالة، سيَقفِز الحاسوب إلى نفس المكان ويُنفِّذ نفس التَعْليمَات إذا آلت قيمة التعبير إلى أيّ واحدة من تلك الثوابت.
</p>

<p>
	ليس هناك أي قواعد لترتيب ثوابت (constants) عناوين الحالات (case label)، ولكن من الضروري ألا تُكرِّر قيمة أيّ ثابت. قد لا يكون المثال التالي مفيدًا بحدّ ذاته، ولكن على الأقل يَسهُل تَتبُّعه بغرض التعلم:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_11" style="">
<span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">   </span><span class="com">// ‫بفرض أن N متغير من النوع العددي</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 1."</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">8</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 2, 4, or 8."</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"(That's a power of 2!)"</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">6</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">9</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 3, 6, or 9."</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"(That's a multiple of 3!)"</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">5</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 5."</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 7 or is outside the range 1 to 9."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تَستعير لغة الجافا جميع بُنَى التحكُّم (control structures) التي تُدعِّمها من لغتي البرمجة الأقدم: السي <code>C</code>، والسي بلص بلص <code>C++‎</code>. تُعدّ تَعْليمَة <code>switch</code> بدائية نوعًا ما بالموازنة مع بقية بُنَى التحكُّم (control structures)؛ فمِنْ السهل أن تَقع في العديد من الأخطاء عند اِستخدَامها، ولهذا يَظُنّ الكاتب أنه كان من الضروري لمُصمِّمي لغة الجافا أن يُحسِّنوا من تَعْليمَة <code>switch</code> أثناء تَبَنّيها ضِمْن اللغة.
</p>

<h2>
	القوائم وتعليمات <code>switch</code>
</h2>

<p>
	تُعدّ معالجة القوائم (menu) واحدة من أشهر تطبيقات تَعْليمَة <code>switch</code>. ببساطة تُعرَض قائمة (menu) مُكوَّنة من مجموعة من الخيارات (options) -ومُرقَّمَة عادةً على الصورة ١، ٢، …إلخ- على المُستخدِم، والذي يختار واحدة منها، ليتَلقَّى ردًا (response) وفقًا لاختياره. يَعني ذلك أنه لابُدّ للحاسوب من الرد على كل خيار مُحتمَل بطريقة مختلفة، ولهذا يُمكِن اِستعمال رقم الخيار كثابت لعناوين الحالات (case labels) ضِمْن تَعْليمَة <code>switch</code> لتَحْدِيد الرد المناسب.
</p>

<p>
	المثال التالي عبارة عن برنامج طرفيّة (command-line program)، وهو في الواقع مُجرَّد نسخة مختلفة من مسألة "تَحْوِيل قياسات الطول" من القسم السابق، حيث يُطلَب من المُستخدِم اختيار وَحدة القياس (unit of measure) التي يَستخدِمها قياس الطول (measurement) المُدْخَل، ولهذا ستُعرَض قائمة (menu) مُرقَّمَة بوَحَدات القياس المتاحة، بحيث يُمكِن للمُستخدِم اختيار إحداها بكتابة رقمها المُناظر كمُدْخَل (input):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_13" style="">
<span class="typ">int</span><span class="pln"> optionNumber</span><span class="pun">;</span><span class="pln">   </span><span class="com">// رقم الخيار المختار من قبل المستخدم</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> measurement</span><span class="pun">;</span><span class="pln"> </span><span class="com">// قياس الطول العددي المعطى من قبل المستخدم</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> inches</span><span class="pun">;</span><span class="pln">      </span><span class="com">// نفس قياس الطول ولكن بوحدة البوصة.</span><span class="pln">

</span><span class="com">// اعرض قائمة واقرأ رقم الخيار المطلوب</span><span class="pln">

</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"What unit of measurement does your input use?"</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"         1.  inches"</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"         2.  feet"</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"         3.  yards"</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"         4.  miles"</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter the number of your choice: "</span><span class="pun">);</span><span class="pln">
optionNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">

</span><span class="com">// اقرأ قياس الطول المعطى وحوله إلى البوصة</span><span class="pln">

</span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> optionNumber </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter the number of inches: "</span><span class="pun">);</span><span class="pln">
       measurement </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">
       inches </span><span class="pun">=</span><span class="pln"> measurement</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">          
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter the number of feet: "</span><span class="pun">);</span><span class="pln">
       measurement </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">
       inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">          
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter the number of yards: "</span><span class="pun">);</span><span class="pln">
       measurement </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">
       inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">36</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">          
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter the number of miles: "</span><span class="pun">);</span><span class="pln">
       measurement </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">
       inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">5280</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Error!  Illegal option number!  I quit!"</span><span class="pun">);</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">          
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية switch</span><span class="pln">

</span><span class="com">// حول قياس الطول بالبوصة إلى وحدات القياس الأخرى</span></pre>

<p>
	يمكن أيضًا إعادة كتابة المثال السابق بحيث تَستخدَم تَعْليمَة <code>switch</code> تعبيرًا (expression) من النوع <code>String</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_15" style="">
<span class="typ">String</span><span class="pln"> units</span><span class="pun">;</span><span class="pln">       </span><span class="com">// وحدة القياس المعطاة من قبل المستخدم</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> measurement</span><span class="pun">;</span><span class="pln"> </span><span class="com">// قياس الطول العددي المعطى من قبل المستخدم</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> inches</span><span class="pun">;</span><span class="pln">      </span><span class="com">// نفس قياس الطول ولكن بوحدة البوصة</span><span class="pln">

</span><span class="com">// اقرأ وحدة القياس المعطاة</span><span class="pln">

</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"What unit of measurement does your input use?"</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Legal responses: inches, feet, yards, or miles : "</span><span class="pun">);</span><span class="pln">
units </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">().</span><span class="pln">toLowerCase</span><span class="pun">();</span><span class="pln">

</span><span class="com">// اقرأ قياس الطول المعطى وحوله إلى البوصة</span><span class="pln">

</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter the number of "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> units </span><span class="pun">+</span><span class="pln"> </span><span class="str">":  "</span><span class="pun">);</span><span class="pln">
measurement </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> units </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"inches"</span><span class="pun">:</span><span class="pln">
       inches </span><span class="pun">=</span><span class="pln"> measurement</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">          
   </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"feet"</span><span class="pun">:</span><span class="pln">
       inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">          
   </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"yards"</span><span class="pun">:</span><span class="pln">
       inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">36</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">          
   </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"miles"</span><span class="pun">:</span><span class="pln">
       inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">5280</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Wait a minute!  Illegal unit of measure!  I quit!"</span><span class="pun">);</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">          
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية switch</span></pre>

<h2>
	التعداد (Enum) كتعبير لتعليمات <code>switch</code>
</h2>

<p>
	كما ذَكَرنا مُسْبَّقًا، يُسمَح باِستخدَام التعدادات (enums) كتعبيرات (expression) لتَعْليمَة <code>switch</code>. وفي هذه الحالة، يجب أن تكون ثوابت عناوين الحالات (case labels) واحدة من القيم المتاحة بنوع التعداد المُستخدَم. فمثلًا، لنفْترِض أن لدينا تعدادًا من النوع <code>Season</code> مُعرَّف كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_17" style="">
<span class="kwd">enum</span><span class="pln"> </span><span class="typ">Season</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> SPRING</span><span class="pun">,</span><span class="pln"> SUMMER</span><span class="pun">,</span><span class="pln"> FALL</span><span class="pun">,</span><span class="pln"> WINTER </span><span class="pun">}</span></pre>

<p>
	إذا كان التعبير (expression) المُستخدَم ضِمْن تَعْليمَة <code>switch</code> من ذلك النوع، فينبغي أن تكون الثوابت المُستخدَمة بعناوين الحالات (case labels) واحدة من القيم التالية <code>Season.SPRING</code> و <code>Season.SUMMER</code> و <code>Season.FALL</code> و <code>Season.WINTER</code>. لكن لاحظ أنه عندما يُستخدَم تعداد ثابت (enum constant) ضِمْن عنوان حالة (case label)، يُستخدَم فقط الاسم دون إعادة ذِكر نوع التعداد، مثل <code>SPRING</code>، وليس الاسم كاملًا، مثل <code>Season.SPRING</code>. لمّا كان ضروريًا لثوابت عناوين الحالات (case labels) أن تكون من نفس نوع تعبير التَعْليمَة، يستطيع الحاسوب أن يَستنتج نوع تلك الثوابت اعتمادًا على نوع التعبير. فلمّا كان هذا التعبير تعدادًا، افْترَض الحاسوب أن تلك الثوابت لابُدّ وأن تَندرِج تحت قيم نفس نوع التعداد، ولهذا لا حاجة لإعادة كتابة نوع التعداد بالثابت. مع ذلك، يَظِلّ هذا شذوذًا بالصياغة (syntax). على سبيل المثال، يُوضِح المثال بالأسفل طريقة اِستخدَام التعداد <code>Season</code> ضِمْن تَعْليمَة <code>switch</code>، وبفَرْض أن المُتَغيِّر <code>currentSeason</code> من النوع <code>Season</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_19" style="">
<span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> currentSeason </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> WINTER</span><span class="pun">:</span><span class="pln">    </span><span class="com">// ‫وليس Season.WINTER</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"December, January, February"</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> SPRING</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"March, April, May"</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> SUMMER</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"June, July, August"</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> FALL</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"September, October, November"</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الإسناد المؤكد (Definite Assignment) وتعليمة <code>switch</code>
</h2>

<p>
	يُعيد التعبير <code>(int)(3*Math.random()‎)</code> واحدًا من الأعداد الصحيحة ٠ و ١ و ٢ عشوائيًا وباحتمالية مُتساوية، ولذلك تَستخدِمه تَعْليمَة <code>switch</code> -بالمثال التالي- للقيام باختيار عشوائي ضِمْن ثلاث بدائل مُحتمَلة، حيث تُسنَد إحدى القيم الثلاثة "Rock" أو "Paper" أو "Scissors" إلى المُتَغيِّر <code>computerMove</code>، وفقًا لقيمة هذا التعبير وبإحتمالية تُساوِي الثلث لكلًا من القيم الثلاثة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_21" style="">
<span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">3</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Rock"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Paper"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Scissors"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُعدّ تَعْليمَة <code>switch</code> بالأعلى سليمة تمامًا بهذه الطريقة، لكن بفَرْض قيامنا بإضافة تَعْليمَة لطباعة المُتَغيِّر <code>computerMove</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_23" style="">
<span class="typ">String</span><span class="pln"> computerMove</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">3</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Rock"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Paper"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Scissors"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The computer's move is "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> computerMove</span><span class="pun">);</span><span class="pln">  </span><span class="com">// خطأ‫!!</span></pre>

<p>
	الآن، أَصبح لدينا خطأ (error) بالسَطْر الأخير! يَرجِع سبب هذا الخطأ إلى ما يُعرَف باسم الإِسْناد المؤكد (definite assignment)، الفكرة ببساطة هي أنه من الضروري أن يَتمكَن مُصرِّف الجافا (compiler) من التأكد من أن أيّ محاولة لاِستخدَام قيمة مُتَغيِّر معين قد سَبَقها بالفعل عملية إِسْناد (assignment) قيمة لهذا المُتَغيِّر. تَعرَّضنا قبلًا لمصطلح الإِسْناد المؤكد (definite assignment) بالقسم الفرعي ٣.١.٤.
</p>

<p>
	بهذا المثال تَحْدِيدًا، تُغطِّي الحالات (cases) الثلاثة الموجودة ضِمْن تَعْليمَة <code>switch</code> جميع الاحتمالات، ومع ذلك فإن المُصرِّف (compiler) ليس ذكي كفاية لاستنتاج ذلك، فهو فقط يرى تَعْليمَة <code>switch</code> مُستخدَمة مع تعبير من النوع العددي (integer-valued expression)، وبذات الوقت، يرى أن الحالات (cases) المُخصَّصة ضِمْن التَعْليمَة لا تُغطِّي جميع الأعداد الصحيحة المُحتمَلة، وإنما فقط ثلاثة منها.
</p>

<p>
	أحد الحلول البسيطة هو استبدال الحالة الافتراضية <code>default:‎</code> بالحالة (case) الأخيرة الموجودة ضِمْن تَعْليمَة <code>switch</code>. لمّا كان تَخْصِيص الحالة الافتراضية <code>default</code> يَعني بالضرورة أن جميع القيم المُحتمَلة لتعبير التَعْليمَة <code>switch</code> سوف تُغطََّى لا محالة، استطاع المُصرِّف (compiler) التأكد من حُدوث إِسْناد مُؤكد للمُتَغيِّر <code>computerMove</code>. انظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_25" style="">
<span class="typ">String</span><span class="pln"> computerMove</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">3</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Rock"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Paper"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
      computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Scissors"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The computer's move is "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> computerMove</span><span class="pun">);</span><span class="pln">  </span><span class="com">// OK!</span></pre>

<h2>
	صياغة جديدة لتعليمة <code>switch</code>
</h2>

<p>
	أُضيفت نسخة جديدة من تَعْليمَة <code>switch</code> إلى الإصدار ١٤ من لغة الجافا. تَستخدِم النسخة الجديدة السهم (arrow)‫ <code>‎-&gt;‎‎</code>‎‎‏ بعد عنوان الحالة (case label)، بدلًا من النقطتان الرأسيتان (colon) <code>:</code>، وتَسمَح بتَعْليمَة واحدة فقط بعد السهم. إذا أردت كتابة أكثر من تَعْليمَة لنفس عنوان الحالة، يُمكِنك اِستخدَام تَعْليمَة كُتليّة (block statement) بتَضْمِين التَعْليمَات المطلوبة بين قوسين.
</p>

<p>
	لم تَعُدْ في حاجة إلى اِستخدَام تَعْليمَة <code>break</code> بنهاية كل حالة، وهو ما ساعد كثيرًا على تَجنُّب الخطأ الشائع من انتقال التَحكُّم غَيْر المقصود من الحالة (case) الصحيحة -بعد الانتهاء من تَّنْفيذها- إلى الحالة التالية بدلًا من إنهاء التَعْليمَة، وذلك في حالة عدم إضافة تَعْليمَة <code>break</code>.
</p>

<p>
	وأخيرًا، لم تَعُدْ مُضطرًا لاِستخدَام قيمة واحدة فقط لكل عنوان حالة (case label)؛ فقد أصبح بالإمكان تَخْصِيص أكثر من قيمة لنفس الحالة (case)؛ بحيث يُفصَل بينهما بفاصلة (comma). يُمكن إعادة كتابة تَعْليمَة <code>switch</code> الموجودة بأول مثال بهذا القسم بالصياغة الجديدة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_27" style="">
<span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">   </span><span class="com">// ‫بفرض أن N متغير من النوع العددي</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 1."</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 2, 4, or 8."</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"(That's a power of 2!)"</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 3, 6, or 9."</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"(That's a multiple of 3!)"</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 5."</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number is 7 or is outside the range 1 to 9."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُعدّ النسخة الجديدة من وجهة نظر الكاتب إضافة ضخمة للغة. لاحِظ أنه ما تزال الصيغة (syntax) الأصلية من تَعْليمَة <code>switch</code> مُتاحة باللغة.
</p>

<p>
	إلى جانب التحسِّينات على تَعْليمَة <code>switch</code>، أُضيف أيضًا إلى لغة الجافا تعبيرًا من النوع <code>switch</code> (‏switch expression)، والذي -وكأيّ تعبير آخر (expression)- يُمكن تَحْصِيل قيمته (evaluation) بحيث تؤول إلى قيمة مُفردة (single value). تتشابه صياغة (syntax) هذا التعبير الجديد إلى حد كبير مع تَعْليمَة <code>switch</code>، مع فارق أن كل حالة أَصبحَت تُخصِّص تعبيرًا (expression) لا تَعْليمَة (statement). اُنظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6565_29" style="">
<span class="typ">String</span><span class="pln"> computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pun">)(</span><span class="lit">3</span><span class="pun">*</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="str">"Rock"</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="str">"Paper"</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="str">"Scissors"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	لابُدّ أن يؤول التعبير من النوع <code>switch</code> (‏switch expression) إلى قيمة دائمًا، ومِنْ ثَمَّ فإنه تقريبًا دائمًا ما يَتضمَّن الحالة الافتراضية (default case).
</p>

<p>
	يُمكِن للتعبير (expression) الخاص بحالة (case) معينة أن يُستبدَل بكتلة (block) تَشتمِل على مجموعة من التَعْليمَات، وعِندها تُحسَب قيمة هذه الحالة باِستخدَام تَعْليمَة <code>yield</code>، مثل <code>yield 42;‎</code>، وليس بأي من التَعْليمَتين <code>return</code> أو <code>break</code>.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s6.html" rel="external nofollow">Section 6: The switch Statement</a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1067</guid><pubDate>Tue, 17 Nov 2020 17:56:42 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x644;&#x64A;&#x645;&#x629; &#x627;&#x644;&#x62A;&#x641;&#x631;&#x64A;&#x639; if &#x627;&#x644;&#x634;&#x631;&#x637;&#x64A;&#x629; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D9%81%D8%B1%D9%8A%D8%B9-if-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1066/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/18.png.4eb3d6c125090852e4bef17e088b2e82.png" /></p>

<p>
	تتوفَّر تَعْليمَتين للتَفْرِيع (branching statements) بلغة الجافا، وفي هذا القسم، سنتناول تَعْليمَة التَفْرِيع الأولى <code>if</code>، والتي قد سبق وتَعرَّضنا لها بالفعل بالقسم ٣.١.
</p>

<p>
	تُكتب تَعْليمَة التَفْرِيع الشَّرْطيّة <code>if</code> بالصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_7" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span></pre>

<p>
	تُسمى هذه الصياغة من <code>if</code> بتَعْليمَة التَفْرِيع الثنائي (two-way branch)، وكما هو مُتوقَّع، يُمكِن للتعليمتين <strong><statement-1></statement-1></strong> و <strong><statement-2></statement-2></strong> -بالأعلى- أن تَكونا كُتلَتي البِنْية (block statement). لاحِظ أنه من المُمكن حَذْف الجزء <code>else</code> المُكوَّن من الكلمة <code>else</code> والتعليمة <strong><statement-2></statement-2></strong>.
</p>

<h2>
	مشكلة تَّدَلِّي <code>else</code>
</h2>

<p>
	لمّا كانت تَعْليمَة <code>if</code> هي بالنهاية مُجرَّد تَعْليمَة، فإنه من المُمكن لإحدى التعليمتين <strong><statement-1></statement-1></strong> أو <strong><statement-2></statement-2></strong> أو حتى كلتيهما أن يَكونا تَعْليمَة <code>if</code> بذاتهما، ولكن قد يتَسبَّب ذلك بحُدوث مشاكل في بعض الأحيان.
</p>

<p>
	فمثلًا، إذا اِستخدَمت تَعْليمَة <code>if</code> بدون الجزء <code>else</code> محل التعليمة <strong><statement-1></statement-1></strong>، كما في الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_9" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> x </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"First case"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Second case"</span><span class="pun">);</span></pre>

<p>
	قد يُعطيك اِستخدَامك للمسافات البادئة (indentation) -ببداية كل سطر من الشيفرة- انطباعًا خاطئًا بأن الجزء <code>else</code> هو النصف الآخر من تَعْليمَة <code>if (x &gt; 0‎)‎</code>، لكن هذا غَيْر صحيح. لا يُعطِي الحاسوب في الواقع أيّ اعتبار لتلك المسافات، وإنما يَتبِّع -في هذه الحالة بالتَحْدِيد- قاعدة بسيطة، وهي ربْط الجزء <code>else</code> بأقرب تَعْليمَة <code>if</code> ليس لديها جزء <code>else</code> خاص بها، مما يَعني أنه سيَربُط الجزء <code>else</code> بتَعْليمَة <code>if (y &gt; 0)‎</code>؛ لأنها الأقرب. ولهذا يَقرأ الحاسوب التَعْليمَات بالأعلى كما لو كانت مُرَتَّبة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_11" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> x </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"First case"</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Second case"</span><span class="pun">);</span></pre>

<p>
	تستطيع مع ذلك إجبار الحاسوب على اِستخدَام التفسير الآخر بتَضْمِين تَعْليمَة <code>if</code> الداخلية داخل كُتلَة (block)، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_13" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> x </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"First case"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Second case"</span><span class="pun">);</span></pre>

<p>
	تختلف بالطبع نتائج تَعْليمَتي <code>if</code> السابقتين. فمثلًا إذا كانت قيمة المُتَغيِّر <code>x</code> أقل من أو تُساوِي الصفر، لا تَطبع التَعْليمَة الأولى شيئًا، بينما تَطبع الثانية السِلسِلة النصية "Second case".
</p>

<h2>
	التفريع المتعدد (Multiway Branching)
</h2>

<p>
	من الجهة الآخرى، تُصبِح الأمور أكثر تشويقًا عندما تَستخدِم تَعْليمَة <code>if</code> محل التعليمة <strong><statement-2></statement-2></strong>، وفي هذه الحالة، ستبدو تَعْليمَة التَفْرِيع (branching) كالتالي -ربما بدون الجزء <code>else</code> الأخير-:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_15" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
         </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln">
     </span><span class="kwd">else</span><span class="pln">
         </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">3</span><span class="pun">&gt;</span></pre>

<p>
	ولمّا كان الحاسوب لا يَهتم بطريقة تَنْسِيق الشيفرة على الصفحة، فتقريبًا دائمًا ما يُكتَب المثال السابق بالصيغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_17" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">3</span><span class="pun">&gt;</span></pre>

<p>
	تُسمى هذه الصياغة من <code>if</code> -بالأعلى- بتَعْليمَة التَفْرِيع الثلاثي (three-way branch)، وينبغي أن تُفكر بها كتَعْليمَة واحدة؛ فبالنهاية، ستُنفَّذ واحدة فقط من التعليمات الثلاثة <strong><statement-1></statement-1></strong> و <strong><statement-2></statement-2></strong> و <strong><statement-3></statement-3></strong> أثناء تَّنْفيذ تلك التَعْليمَة. تُحسَب أولًا قيمة التعبير <strong><boolean-expression-1></boolean-expression-1></strong>، فإذا كانت تؤول إلى القيمة المنطقية <code>true</code>، سيُنفِّذ الحاسوب التعليمة <strong><statement-1></statement-1></strong>، ثم سيَقفِز مباشرة إلى نهاية تَعْليمَة <code>if</code> الخارجية مُتخَطِّيًا بذلك العبارتين الآخريتين تمامًا. أما إذا آلت قيمتها إلى القيمة المنطقية <code>false</code>، فإنه سيتَخَطَّى التعليمة <strong><statement-1></statement-1></strong> فقط، وينتقل إلى تَعْليمَة <code>if</code> الثانية المُتداخِلة (nested)؛ ليَفحْص قيمة التعبير <strong><boolean-expression-2></boolean-expression-2></strong>، ويُقرِّر ما إذا كان سيُنفِّذ التعليمة <strong><statement-2></statement-2></strong> أم <strong><statement-3></statement-3></strong>.
</p>

<p>
	مثلًا، يَطبع المثال التالي واحدة من ثلاث رسائل مُحتمَلة وفقًا لقيمة المُتَغيِّر <code>temperature</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_19" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">temperature </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">50</span><span class="pun">)</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"It's cold."</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">temperature </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">80</span><span class="pun">)</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"It's nice."</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"It's hot."</span><span class="pun">);</span></pre>

<p>
	على سبيل المثال، إذا كان المُتَغيِّر <code>temperature</code> يَحمِل القيمة ٤٢، فسيَتحقَّق أول شَّرْط، ومِنْ ثَمَّ تُطبَع الرسالة "It's cold"، لينتقل بَعْدها الحاسوب إلى ما بعد التَعْليمَة مُتخَطِّيًا بقيتها، وبدون حتى محاولة اختبار الشَّرْط الثاني. أما إذا كانت قيمته تُساوِي ٧٥، فلن يتحقَّق أول شَّرْط، لذلك سينتقل الحاسوب لاختبار الشَّرْط الثاني، الذي سيتحقَّق لتتم طباعة الرسالة "It's nice"، ثم سيتَخَطَّى بقية التَعْليمَة. أخيرًا إذا كانت قيمته تُساوِي ١٧٣، لا يتحقَّق أي من الشَّرْطين، وتُطبَع الرسالة "It's hot" (لو لم تَكن دوائره الكهربية قد اِحترقَت بفِعْل الحرارة).
</p>

<p>
	يُمكنك الاستمرار بإضافة المزيد من عبارات <code>else-if</code> بأيّ عَدَد، وفي تلك الحالة، يُطلَق عليها اسم تَعْليمَة التَفْرِيع المُتعدِّد (multiway branches)، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_21" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">test</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">test</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">2</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">test</span><span class="pun">-</span><span class="lit">3</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="lit">3</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">
  </span><span class="pun">.</span><span class="pln"> </span><span class="com">// أضف المزيد</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">test</span><span class="pun">-</span><span class="pln">N</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-</span><span class="pln">N</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">statement</span><span class="pun">-(</span><span class="pln">N</span><span class="pun">+</span><span class="lit">1</span><span class="pun">)&gt;</span></pre>

<p>
	الاختبارات **<test-> **-بالأعلى- هي تعبيرات منطقية (boolean expressions)، تُحسَب قيمها واحدة تلو الآخرى، إلى أن تؤول إحداها إلى القيمة المنطقية <code>true</code>، فيُنفِّذ عندها الحاسوب التعليمة <strong><statement-></statement->‎&gt;</strong> التي تُناظِر الاختبار <strong><test-></test->‎&gt;</strong> المُتحقِّق ويتَخَطَّى البقية. أمّا إذا لم تؤول أي واحدة منها إلى القيمة المنطقية <code>true</code>، تُنفَّذ عندها التعليمة <strong><statement-></statement->(n+1)‎&gt;</strong> الموجودة ضِمْن الجزء <code>else</code>. لاحِظ أنه دائمًا ما ستُنفَّذ واحدة فقط لا غَيْر من كل هذه التعليمات <strong><statement-></statement->‎&gt;</strong>، وهذا هو سبب تسميتها باسم تَعْليمَة التَفْرِيع المُتعدِّد (multiway branch). يمُكنك أيضًا حَذْف الجزء <code>else</code> الأخير، ولكن -في تلك الحالة- إذا لم تتحقَّق أيّ من التعبيرات المنطقية، وآلت جميعا إلى القيمة المنطقية <code>false</code>، فلن تُنفَّذ أيّ عبارة نهائيًا. يُمكن بالطبع لأيّ من التعليمات <strong><statement-></statement->‎&gt;</strong> أن تكون كُتليّة البِنْية (block)، أي مُكوَّنة من أيّ عدد من التَعْليمَات طالما أُحيطَت بزوج من الأقواس. </test->‎&gt;
</p>

<p>
	قد يَنْتابك شُعور بالارتباك لوجود الكثير من قواعد الصياغة (syntax) الجديدة هنا، ولكن أَضمَن لك أنه مع قليل من الممارسة، ستعتاد عليها. يُمكنك أيضًا أن تُلقي نظرة على المُخطط التالي، والذي يُوضِح مَسار التحكُّم (flow control) أثناء تَّنْفيذ الصيغة الأعم من تَعْليمَة <code>if..else if</code> والمعروفة باسم تَعْليمَة التَفْرِيع المُتعدِّد:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="53280" data-unique="lsn4z2geu" src="https://academy.hsoub.com/uploads/monthly_2020_11/001Multiway_If_Flow_Control.png.a7bd8001119c71d4b6703bc9faba7acf.png" style="" alt="001Multiway_If_Flow_Control.png"></p>

<h2>
	أمثلة
</h2>

<p>
	لنفْترَض أن لدينا ثلاثة مُتَغيِّرات <code>x</code> و <code>y</code> و <code>z</code> من النوع العددي <code>int</code>، يَحتوِي كل منها على قيمة عددية معينة. المطلوب هو طباعة قيم المُتَغيِّرات الثلاثة بحيث تكون مُرَتَّبة ترتيبًا تصاعديًا. فمثلًا، إذا كانت قيم المُتَغيِّرات هي ٤٢ و ١٧ و ٢٠، فلابُدّ من طباعتها على الترتيب ١٧ و ٢٠ و ٤٢.
</p>

<p>
	لحل هذه المسألة، سنحاول الإجابة على السؤال التالي: "لنتخيل أن لدينا قائمة مُرَتَّبة بالفعل، فبأيّ مكان يَنبغي للمُتَغيِّر <code>x</code> أن يقع؟" ببساطة، إذا كانت قيمة المُتَغيِّر <code>x</code> أصغر من قيمة كلا المُتَغيِّرين <code>y</code> و <code>z</code>، فإنه سيأتي بأول القائمة، أما إذا كان أكبر من كليهما، فإنه سيأتي بذيل القائمة، وأخيرًا، سيأتي بوسط القائمة في أيّ حالة غَيْر تلك الحالتين. يُمكن التعبير عن الحالات الثلاثة السابقة بتَعْليمَة التَفْرِيع الثلاثي <code>if</code>، مع ذلك ما يزال أمامنا تحديًا لإيجاد طريقة نُحدِّد من خلالها ترتيب طباعة المُتَغيِّرين <code>y</code> و <code>z</code>. انظر الشيفرة الوهمية (pseudocode):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_23" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> y </span><span class="pun">&amp;&amp;</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> z</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫اطبع x متبوعة بكلا من y و z بترتيبها الصحيح</span><span class="pln">
    output x</span><span class="pun">,</span><span class="pln"> followed by y and z in their correct order
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">&gt;</span><span class="pln"> y </span><span class="pun">&amp;&amp;</span><span class="pln"> x </span><span class="pun">&gt;</span><span class="pln"> z</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫اطبع y و z بترتيبها الصحيح متبوعين بقيمة x</span><span class="pln">
   output y and z in their correct order</span><span class="pun">,</span><span class="pln"> followed by x
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫اطبع x بين y و z بترتيبها الصحيح</span><span class="pln">
    output x in between y and z in their correct order
</span><span class="pun">}</span></pre>

<p>
	يتطلب تَحْدِيد ترتيب طباعة المُتَغيِّرين <code>y</code> و <code>z</code> تَعْليمَة <code>if</code> آخرى داخلية. انظر الشيفرة التالية بلغة الجافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_25" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> y </span><span class="pun">&amp;&amp;</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> z</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">        </span><span class="com">// ‫إذا كانت x بالبداية</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> z</span><span class="pun">)</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z </span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">&gt;</span><span class="pln"> y </span><span class="pun">&amp;&amp;</span><span class="pln"> x </span><span class="pun">&gt;</span><span class="pln"> z</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">   </span><span class="com">// ‫إذا كانت x بالنهاية</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> z</span><span class="pun">)</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x </span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> z </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                       </span><span class="com">// ‫إذا كانت x في الوسط</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> z</span><span class="pun">)</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> z </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	حَاوِل اختبار ما إذا كانت الشيفرة بالأعلى ستَعمَل بشكل سليم حتى في حالة وجود أكثر من مُتَغيِّر يَحمِل نفس القيمة. عمومًا إذا كان هناك مُتَغيِّرين بنفس القيمة، فإنه لم يَعُدْ مهمًا بأيّ ترتيب سيَتِمّ طباعتهما.
</p>

<p>
	بخلاف اللغات الطبيعية التي تَسمَح بكتابة جملة مثل "إذا كان x أصغر من y و z"، لا يُمكنك أن تَفعَل الشيء نفسه -أيّ كتابة التعبير <code>if (x &lt; y &amp;&amp; z)‎</code>- بلغة الجافا. لا تَسير الأمور بهذه البساطة، فلابُدّ أن يَستقبِل العَامِل (operator) المنطقي <code>&amp;&amp;</code> مُعامِلين منطقيين (boolean)، ولهذا ستحتاج إلى إِجراء الاختبارين <code>x&lt;y</code> و <code>x&lt;z</code> بشكل منفصل، ثم تُطبِّق العَامِل المنطقي <code>&amp;&amp;</code> على نتيجتيهما.
</p>

<p>
	ربما تَتَّخذ منحى آخر لحل نفس المسألة، وذلك بمحاولة الإجابة على السؤال: "بأيّ ترتيب يَنبغي طباعة المُتَغيِّرين <code>x</code> و <code>y</code>؟". بمُجرَّد أن تتَوصَّل لإجابة، سيتبقَّى فقط أن تُحدِّد مكان المُتَغيِّر <code>z</code>. انظر الشيفرة التالية بلغة الجافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_27" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> y </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="com">// x comes before y</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> z </span><span class="pun">&lt;</span><span class="pln"> x </span><span class="pun">)</span><span class="pln">   </span><span class="com">// z comes first</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> z </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> z </span><span class="pun">&gt;</span><span class="pln"> y </span><span class="pun">)</span><span class="pln">   </span><span class="com">// z comes last</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">   </span><span class="com">// z is in the middle</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">          </span><span class="com">// y comes before x</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> z </span><span class="pun">&lt;</span><span class="pln"> y </span><span class="pun">)</span><span class="pln">   </span><span class="com">// z comes first</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> z </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> z </span><span class="pun">&gt;</span><span class="pln"> x </span><span class="pun">)</span><span class="pln">  </span><span class="com">// z comes last</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">  </span><span class="com">// z is in the middle</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتوفَّر عادةً عدة طرائق وأساليب مختلفة لحل نفس المشكلة. فمثلًا، بالمثال السابق، تَعرَّضنا لحلّين فقط ضِمْن عدة حلول مُحتمَلة آخرى كثيرة. فمثلًا، قد يقوم حل آخر ثالث بتبديل قيمة (swap) المُتَغيِّرين <code>x</code> و <code>y</code> إذا كانت قيمة <code>x</code> أكبر من قيمة <code>y</code>، ومِنْ ثَمَّ سيكون من الضروري طباعة قيمة المُتَغيِّر <code>x</code> قبل <code>y</code>.
</p>

<p>
	سنحاول أخيرًا كتابة برنامج كامل يَستخدِم تَعْليمَة <code>if</code> بطريقة مُشوِّقة. هدف البرنامج عمومًا هو تَحْوِيل قياسات الطول (measurements of length) من إحدى وَحَدات قياس الطول (units of measure) إلى آخرى، فمثلًا من المِيل (miles) إلى اليَارْدَة (yards)، أو من البُوصَة (inches) إلى القَدَم (feet). سنحتاج بالتأكيد أن نكون أكثر تحديدًا بخُصوص مُتطلَّبات البرنامج؛ فما تزال المسألة غَيْر واضحة المعالِم حتى الآن، ولهذا سنفْترَض أن البرنامج يتَعامَل فقط مع وَحَدات القياس التالية: البُوصَة، والقَدَم، واليَارْدَة، والمِيل؛ وسيكون من السهل إضافة المزيد منها فيما بَعْد. سيُدْخِل المُستخدِم قياس الطول بأي وَحدة من وَحَدات القياس المسموح بها، كأن يَكتُب "١٧ قدم" أو "٢.٧٣ ميل"، ربما بَعْدها قد تَطلُب من المُستخدِم إِدْخَال اسم وَحدة القياس المطلوب التَحْوِيل إليها، بحيث تُطبَع كخَرْج (output) للبرنامج. لكننا في الواقع سنكتفي بطباعة قياس الطول بجميع وَحَدات القياس المسموح بها؛ وذلك في محاولة لتبسيط المسألة. انظر الخوارزمية التالية المبدئية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_29" style="">
<span class="com">// اقرأ كلا من قياس الطول ووحدة القياس المستخدمة</span><span class="pln">
</span><span class="typ">Read</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s input measurement and units of measure
</span><span class="com">// حول قيمة قياس الطول المعطاة إلى وحدات القياس الأخرى</span><span class="pln">
</span><span class="typ">Express</span><span class="pln"> the measurement in inches</span><span class="pun">,</span><span class="pln"> feet</span><span class="pun">,</span><span class="pln"> yards</span><span class="pun">,</span><span class="pln"> and miles
</span><span class="com">// اطبع قياسات الطول بالوحدات الأربعة</span><span class="pln">
</span><span class="typ">Display</span><span class="pln"> the four results</span></pre>

<p>
	لابُدّ أن يَستقبِل البرنامج مُدْخَلين (input) من المُستخدِم، هما قياس الطول ذاته بالإضافة إلى وَحدة القياس المُستخدَمة (units of measure)، ولهذا تُستخدَم الدالتين <code>TextIO.getDouble()‎</code> و <code>TextIO.getlnWord()‎</code>؛ لقراءة كلًا من قياس الطول العددي واسم وَحدة القياس من نفس السَطْر على الترتيب.
</p>

<p>
	سنبدأ دائمًا بتَحْوِيل قياس الطول المُعْطى إلى إِحدى وَحَدات قياس الطول -ولتكن البُوصَة-؛ وذلك لتوحيد الخطوات التالية المسئولة عن التَحْوِيل إلى وَحَدات القياس الأخرى. يَلزَمنا الآن فقط تَحدِّيد وَحدة القياس التي أَدْخَل بها المُستخدِم قياس الطول؛ وذلك لنتمكن من تَحْوِيلها إلى وَحدة البُوصَة. بَعْد إجراء ذلك التَحْوِيل، سيكون من السهل تَحْوِيل قياس الطول بوَحدة البُوصَة إلى كلًا من القَدَم، واليَارْدَة، والمِيل. اُنظر الخوارزمية التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_31" style="">
<span class="typ">Let</span><span class="pln"> measurement </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getDouble</span><span class="pun">()</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> units </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnWord</span><span class="pun">()</span><span class="pln">
</span><span class="com">// إذا اسم وحدة القياس المعطى هو البوصة</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> the units are inches
   </span><span class="typ">Let</span><span class="pln"> inches </span><span class="pun">=</span><span class="pln"> measurement
</span><span class="com">// إذا اسم وحدة القياس المعطى هو القدم</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> the units are feet
   </span><span class="typ">Let</span><span class="pln"> inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">12</span><span class="pln">         </span><span class="com">// 12 inches per foot</span><span class="pln">
</span><span class="com">// إذا اسم وحدة القياس المعطى هو الياردة</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> the units are yards
   </span><span class="typ">Let</span><span class="pln"> inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">36</span><span class="pln">         </span><span class="com">// 36 inches per yard</span><span class="pln">
</span><span class="com">// إذا اسم وحدة القياس المعطى هو الميل</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> the units are miles
   </span><span class="typ">Let</span><span class="pln"> inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">5280</span><span class="pln">  </span><span class="com">// 5280 feet per mile</span><span class="pln">
</span><span class="com">// إذا لم يكن اسم وحدة القياس المعطى أي من القيم الأربعة السابقة</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
   </span><span class="com">// اسم وحدة القياس المعطى غير صالح</span><span class="pln">
   </span><span class="typ">The</span><span class="pln"> units are illegal</span><span class="pun">!</span><span class="pln">
   </span><span class="com">// اطبع رسالة خطأ واوقف المعالجة</span><span class="pln">
   </span><span class="typ">Print</span><span class="pln"> an error message and stop processing
</span><span class="com">// إجراء التحويلات</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> feet </span><span class="pun">=</span><span class="pln"> inches </span><span class="pun">/</span><span class="pln"> </span><span class="lit">12.0</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> yards </span><span class="pun">=</span><span class="pln"> inches </span><span class="pun">/</span><span class="pln"> </span><span class="lit">36.0</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> miles </span><span class="pun">=</span><span class="pln"> inches </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">12.0</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">5280.0</span><span class="pun">)</span><span class="pln">
</span><span class="com">// اعرض النتائج</span><span class="pln">
</span><span class="typ">Display</span><span class="pln"> the results</span></pre>

<p>
	لمّا كنا سنقرأ اسم وَحدة القياس المُعْطاة إلى المُتَغيِّر <code>units</code>، وهو من النوع <code>String</code>، فسنحتاج إلى إجراء موازنة نصية (comparison) لتَحدِّيد وَحدة القياس المُناظِرة. تُستخدَم الدالة <code>units.equals("inches")‎</code> لفَحْص ما إذا كانت قيمة المُتَغيِّر <code>units</code> تُساوِي السِلسِلة النصية "inches"، لكن لا يَنطوِي إِلزام المُستخدِم على إِدْخَال الكلمة "inches" حرفيًا على أفضل تجربة للمُستخدِم (user experience)؛ فمن الأفضل أن نَسمَح له بكتابة كلمات أخرى مثل "inch" أو "in"، ولذلك سنُجري الفَحْص على التعبير المنطقي التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_33" style="">
<span class="pln">units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"inches"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"inch"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"in"</span><span class="pun">)‎</span></pre>

<p>
	وذلك للسماح بالاحتمالات الثلاثة. يُمكننا أيضًا أن نَسمَح له بكتابة وَحدة القياس بحروف كبيرة (upper case) مثل "Inches" أو "IN" إِمّا عن طريق تَحْوِيل السِلسِلة النصية المُعْطاة <code>units</code> إلى حروف صغيرة (lower case) قبل إجراء الفَحْص، أو باِستخدَام الدالة <code>units.equalsIgnoreCase</code> للموازنة بدلًا من <code>units.equals</code>.
</p>

<p>
	تَسمَح النسخة النهائية من البرنامج للمُستخدِم بتَكْرار عمليتي الإِدْخَال والطباعة أكثر من مرة؛ حيث سيَتوقَف البرنامج فقط عند إِدْخَال القيمة صفر. كل ما تَطلبه الأمر هو إِحاطة الخوارزمية بالأعلى ضِمْن حَلْقة التَكْرار <code>while</code>، والتأكد من إِيقافها عندما يُدخِل المُستخدِم القيمة صفر. اُنظر الشيفرة بالكامل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_35" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LengthConverter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="kwd">double</span><span class="pln"> measurement</span><span class="pun">;</span><span class="pln">  </span><span class="com">// قياس الطول المعُطى</span><span class="pln">
        </span><span class="typ">String</span><span class="pln"> units</span><span class="pun">;</span><span class="pln">        </span><span class="com">// اسم وحدة قياس المعطاة</span><span class="pln">

        </span><span class="com">// قياس الطول بوحدات القياس الأربعة المتاحة</span><span class="pln">
        </span><span class="kwd">double</span><span class="pln"> inches</span><span class="pun">,</span><span class="pln"> feet</span><span class="pun">,</span><span class="pln"> yards</span><span class="pun">,</span><span class="pln"> miles</span><span class="pun">;</span><span class="pln">  

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Enter measurements in inches, feet, yards, or miles."</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"For example:  1 inch    17 feet    2.73 miles"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You can use abbreviations:   in   ft  yd   mi"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"I will convert your input into the other units"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"of measure."</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">

        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

            </span><span class="com">// اقرأ مُدخَل المستخدم </span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter your measurement, or 0 to end:  "</span><span class="pun">);</span><span class="pln">
            measurement </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getDouble</span><span class="pun">();</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">measurement </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫اِنهي حلقة while</span><span class="pln">
            units </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnWord</span><span class="pun">();</span><span class="pln">            
            units </span><span class="pun">=</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">();</span><span class="pln">  </span><span class="com">// صغر الحروف</span><span class="pln">

            </span><span class="com">// حول قياس الطول المعطى إلى وحدة البوصة</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"inch"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"inches"</span><span class="pun">)</span><span class="pln"> 
                </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"in"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                inches </span><span class="pun">=</span><span class="pln"> measurement</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"foot"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"feet"</span><span class="pun">)</span><span class="pln"> 
                     </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"ft"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"yard"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"yards"</span><span class="pun">)</span><span class="pln"> 
                     </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"yd"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">36</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"mile"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"miles"</span><span class="pun">)</span><span class="pln"> 
                     </span><span class="pun">||</span><span class="pln"> units</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="str">"mi"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                inches </span><span class="pun">=</span><span class="pln"> measurement </span><span class="pun">*</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">5280</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Sorry, but I don't understand \""</span><span class="pln"> 
                                   </span><span class="pun">+</span><span class="pln"> units </span><span class="pun">+</span><span class="pln"> </span><span class="str">"\"."</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">continue</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫عد إلى بداية حلقة while</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="com">// حوِّل قياس الطول بوحدة البوصة إلى وحدات القياس الآخرى</span><span class="pln">
            feet </span><span class="pun">=</span><span class="pln"> inches </span><span class="pun">/</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
            yards </span><span class="pun">=</span><span class="pln"> inches </span><span class="pun">/</span><span class="pln"> </span><span class="lit">36</span><span class="pun">;</span><span class="pln">
            miles </span><span class="pun">=</span><span class="pln"> inches </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">12</span><span class="pun">*</span><span class="lit">5280</span><span class="pun">);</span><span class="pln">

            </span><span class="com">// اطبع قياس الطول بوحدات القياس الأربعة</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"That's equivalent to:"</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"%14.5g inches%n"</span><span class="pun">,</span><span class="pln"> inches</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"%14.5g feet%n"</span><span class="pun">,</span><span class="pln"> feet</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"%14.5g yards%n"</span><span class="pun">,</span><span class="pln"> yards</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"%14.5g miles%n"</span><span class="pun">,</span><span class="pln"> miles</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">

        </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية تعليمة while</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"OK!  Bye for now."</span><span class="pun">);</span><span class="pln">

    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية برنامج main</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف LengthConverter</span></pre>

<p>
	لمّا كنا غَيْر مُتحكِّمين بقيم الأعداد الحقيقية (real numbers) المُدْخَلة؛ حيث تَعتمِد على المُستخدِم الذي ربما قد يَرغَب بإِدْخَال قياسات صغيرة جدًا أو ربما كبيرة جدًا، فكان لابُدّ من صياغة الخَرْج باِستخدَام مُحدِّدات الصيغة ‫(format specifiers). اُستخدِم تحديدًا مُحدِّد الصيغة <code>g</code> -بالبرنامج-، والذي يَعمَل كالتالي: إذا كان العَدَد كبيرًا جدًا أو صغيرًا جدًا، فإنه يَطبَعه ‫بصيغة أسّية (exponential form)، أمّا إن لم يَكُن كذلك، فإنه يَطبَعه بالصيغة الرقمية (decimal form) العادية. تَذَكَّر أن القيمة <code>5</code>، مثلًا، بمُحدِّد الصيغة <code>‎%14.5g‎</code> تُشير إلى العدد الكلي للأرقام المعنوية (significant digits) المَطبُوعة، وبذلك سنَحصُل دائمًا على نفس العَدَد من الأرقام المعنوية (significant digits) بالخَرْج بِغَضّ النظر عن قيمة العَدَد المُدْخَل. يَختلف ذلك عن مُحدِّد الصيغة <code>f</code>، والذي يَطبَع الخَرْج بصيغة رقمية (decimal form)، ولكن تُشير فيه القيمة <code>5</code>، مثلًا، بمُحدِّد الصيغة ‎<code>%14.5f</code> إلى عَدَد الأرقام بَعْد العلامة العَشريّة (decimal point)، أيّ إذا كان لدينا العَدَد <code>0.000000000745482</code> فإن مُحدِّد الصيغة <code>f</code> سيَطبَعه إلى <code>0.00000</code>، بدون أيّ أرقام معنوية (significant digits) على الإطلاق، أما مُحدِّد الصيغة <code>g</code> فسيَطبَعه <code>7.4549e-10</code>.
</p>

<h2>
	التعليمة الفارغة (Empty Statement)
</h2>

<p>
	تُوفِّر لغة الجافا تَعْليمَة آخرى يُطلَق عليها اسم التَعْليمَة الفارغة (empty statement)، وهي ببساطة مُجرَّد فاصلة منقوطة <code>;</code>، وتَطلُب من الحاسوب أن يَفعَل "لا شيء". اُنظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_37" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    x </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	عملية إِضافة فاصلة منقوطة (semicolon) بَعْد القوس <code>{</code>، كما بالمثال السابق، هي عملية صحيحة تمامًا وِفقًا لقواعد بناء الجملة (syntax)، لكن، في هذه الحالة، لا يعدّها الحاسوب جزءًا من تَعْليمَة <code>if</code>، وإنما يُعامِلها معاملة تَعْليمَة فارغة (empty statement) مستقلة بذاتها. عمومًا ليس هذا الغرض من تَوفَّر التَعْليمَة الفارغة بلغة الجافا، ولن تجدها مُستخدَمة بهذه الطريقة إلا نادرًا، وإنما ستَستخدِمها أحيانًا عندما تُريد أن تَطلُب من الحاسوب ألا يَفعَل شيئًا. على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_39" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> done </span><span class="pun">)</span><span class="pln">
   </span><span class="pun">;</span><span class="pln">  </span><span class="com">// تعليمة فارغة</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Not done yet."</span><span class="pun">);</span></pre>

<p>
	تَطلُب الشيفرة بالأعلى من الحاسوب ألا يَفعَل شيئًا إذا كانت قيمة المُتَغيِّر المنطقي <code>done</code> مساوية للقيمة المنطقية <code>true</code>، وأن يَطبَع السِلسِلة النصية "Not done yet" إذا كانت قيمته مُساوية للقيمة المنطقية <code>false</code>. لا يمكنك في هذه الحالة أن تَحذِف الفاصلة المنقوطة (semicolon)؛ لأن قواعد الصياغة بلغة الجافا (Java syntax) تَتَطلَّب وجود تَعْليمَة بين <code>if</code> و <code>else</code>. يُفضِّل الكاتب على الرغم من ذلك اِستخدَام كُتلَة (block) فارغة أي اِستخدَام قوسين فارغين في تلك الحالات.
</p>

<p>
	عادةً ما تَتسبَّب إضافة التَعْليمَة الفارغة <code>;</code> دون قصد بحُدوث أخطاء (errors) يَصعُب إِيجادها. انظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1736_41" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++);</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">);</span></pre>

<p>
	يَطبَع المثال بالأعلى كلمة "Hello" مرة واحدة فقط وليس عشر مرات كما قد تَظُنّ -بالأخص مع وجود المسافة البادئة (indentation) ببداية السطر الثاني-. السبب ببساطة هو وجود فاصلة منقوطة <code>;</code> بنهاية تَعْليمَة <code>for</code> بنهاية السَطْر الأول. تُعدّ هذه الفاصلة المنقوطة <code>;</code> -في هذه الحالة- تَعْليمَة بحد ذاتها، هي التَعْليمَة الفارغة (empty statement)، وهي في الواقع ما يتم تَّنْفيذه عشر مرات، أي أن حَلْقة التَكْرار <code>for</code> بالأعلى تَفعَل "لا شئ" عشر مرات. في المقابل، لا تُعدّ التَعْليمَة <code>System.out.println</code> جزءً من تَعْليمَة <code>for</code> أساسًا، ولذلك تُنفَّذ مرة واحدة فقط بعد انتهاء تَعْليمَة حَلْقة <code>for</code>.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s5.html" rel="external nofollow">Section 5: The If Statement</a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1066</guid><pubDate>Tue, 17 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x644;&#x64A;&#x645;&#x629; &#x62D;&#x644;&#x642;&#x629; &#x627;&#x644;&#x62A;&#x643;&#x631;&#x627;&#x631; for &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-for-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1065/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/17.png.a8211c0a35c6f4e19cdb14a5877baf9f.png" /></p>
<p>
	سنتناول في هذا القسم نوعًا آخر من الحَلْقات، هو تَعْليمَة الحَلْقة <code>for</code>. ينبغي أن تُدرك أنه يُمكن لأيّ حَلْقة تَكْرارية (loop) عامةً أن تُكتَب بأيّ من التَعْليمَتين <code>for</code> و <code>while</code>، وهو ما يَعني أن لغة الجافا لم تتَحَصَّل على أيّ مِيزَة وظيفية إضافية بتَدْعِيمها لتَعْليمَة <code>for</code>. لا يَعني ذلك أن تَعْليمَة <code>for</code> غَيْر مُهمة، على العكس تمامًا، ففي الواقع، قد يَتجاوز عَدَد حَلْقات <code>for</code> المُستخدَمة ببعض البرامج عَدَد حَلْقات <code>while</code>. (كما أن الكاتب على معرفة بأحد المبرمجين والذي لا يَستخدِم سوى حَلْقات <code>for</code>). الفكرة ببساطة أن تَعْليمَة <code>for</code> تكون أكثر ملائمة لبعض النوعيات من المسائل؛ حيث تُسهِل من كتابة الحَلْقات وقرائتها بالموازنة مع حَلْقة <code>while</code>.
</p>

<h2>
	حلقة التكرار <code>For</code>
</h2>

<p>
	عادةً ما تُستخدَم حَلْقة التَكْرار <code>while</code> بالصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_7" style=""><span class="str">&lt;initialization&gt;</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">continuation</span><span class="pun">-</span><span class="pln">condition</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">&lt;statements&gt;</span><span class="pln">
    </span><span class="str">&lt;update&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	مثلًا، اُنظر لهذا المثال من القسم ٣.٢:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_9" style=""><span class="pln">years </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  </span><span class="com">// هيئ المتغير</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> years </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">   </span><span class="com">// شرط حلقة التكرار</span><span class="pln">
    </span><span class="com">// نفذ التعليمات الثلاثة التالية</span><span class="pln">
    interest </span><span class="pun">=</span><span class="pln"> principal </span><span class="pun">*</span><span class="pln"> rate</span><span class="pun">;</span><span class="pln">    
    principal </span><span class="pun">+=</span><span class="pln"> interest</span><span class="pun">;</span><span class="pln">          
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">principal</span><span class="pun">);</span><span class="pln">  

    </span><span class="com">// حدث قيمة المتغير</span><span class="pln">
    years</span><span class="pun">++;</span><span class="pln">   
</span><span class="pun">}</span></pre>

<p>
	ولهذا أضيفت تَعْليمَة <code>for</code> للتسهيل من كتابة هذا النوع من الحَلْقات، حيث يُمكِن إِعادة كتابة حَلْقة التَكْرار بالأعلى باستخدام تَعْليمَة <code>for</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_13" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> years </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  years </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">  years</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    interest </span><span class="pun">=</span><span class="pln"> principal </span><span class="pun">*</span><span class="pln"> rate</span><span class="pun">;</span><span class="pln">
    principal </span><span class="pun">+=</span><span class="pln"> interest</span><span class="pun">;</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">principal</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ كيف دُمجَت كُُلًا من تعليمات التهيئة <strong><initialization></initialization></strong>، والشَّرْط الاستمراري لحَلْقة التَكْرار <strong><continuation-condition></continuation-condition></strong>، والتَحْدِيث <strong><update></update></strong> جميعًا بسَطْر واحد هو السَطْر الأول من حَلْقة التَكْرار <code>for</code>. يُسهِل ذلك من قراءة حَلْقة التَكْرار وفهمها؛ لأن جميع تَعْليمَات التحكُّم بالحَلْقة (loop control) قد ضُمِّنت بمكان واحد بشكل منفصل عن مَتْن الحَلْقة الفعليّ المطلوب تَكْرار تَّنْفيذه.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير التطبيقات باستخدام لغة Python
		</p>

		<p class="banner-subtitle">
			احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/python-application-development" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة تطوير التطبيقات باستخدام لغة Python" src="https://academy.hsoub.com/learn/assets/images/courses/python-application-development.png">
	</div>
</div>

<p>
	تُنفَّذ حَلْقة التَكْرار <code>for</code> بالأعلى بنفس الطريقة التي تُنفَّذ بها الشيفرة الأصلية، أي تُنفَّذ أولًا تعليمة التهيئة <strong><initialization></initialization></strong> مرة وحيدة قبل بدء تَّنْفيذ الحَلْقة، ثم يُفحَص الشَّرْط الاستمراري للحَلْقة <strong><continuation-condition></continuation-condition></strong> قَبْل كل تَكْرار (iteration/execution) لمَتْن الحَلْقة، بما في ذلك التَكْرار الأوَّليّ (first iteration)، بحيث تَتوقَف الحَلْقة عندما يؤول هذا الشَّرْط إلى القيمة <code>false</code>. وأخيرًا، تُنفَّذ تعليمة التَحْدِيث <strong><update></update></strong> بنهاية كل تَكْرار (iteration/execution) قَبْل العودة لفَحْص الشَّرْط من جديد.
</p>

<p>
	تُكتَب تَعْليمَة حَلْقة التَكْرار <code>for</code> بالصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_15" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="str">&lt;initialization&gt;</span><span class="pun">;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">continuation</span><span class="pun">-</span><span class="pln">condition</span><span class="pun">&gt;;</span><span class="pln"> </span><span class="str">&lt;update&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="str">&lt;statement&gt;</span></pre>

<p>
	أو كالتالي إذا كانت التعليمة <strong><statement></statement></strong> كُتليّة البِنْية (block statement):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_17" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="str">&lt;initialization&gt;</span><span class="pun">;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">continuation</span><span class="pun">-</span><span class="pln">condition</span><span class="pun">&gt;;</span><span class="pln"> </span><span class="str">&lt;update&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">&lt;statements&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمكِن لأيّ تعبير منطقي (boolean-valued expression) أن يُستخدَم محل الشَّرْط الاستمراري <strong><continuation-condition></continuation-condition></strong>. يُمكِن لأيّ تعبير (expression) -طالما كان صالحًا كتَعْليمَة برمجية- أن يُستخدَم محل تعليمة التهيئة <strong><initialization></initialization></strong>، وفي الواقع غالبًا ما تُستخدَم تَعْليمَة تَّصْريح (declaration) أو إِسْناد (assignment). يُمكِن لأي تَعْليمَة بسيطة (simple statement) أن تُستخدَم محل تعليمة التَحْدِيث <strong><update></update></strong>، وعادةً ما تكون تَعْليمَة زيادة/نقصان (increment/decrement) أو إِسْناد (assignment). وأخيرًا، يُمكِن لأي من تلك التعليمات الثلاثة بالأعلى أن تكون فارغة. لاحظ أنه إذا كان الشَّرْط الاستمراري <strong><continuation-condition></continuation-condition></strong> فارغًا، فإنه يُعامَل وكأنه يُعيد القيمة المنطقية <code>true</code>، أي يُعدّ الشَّرْط مُتحقِّقًا، مما يعني تَّنْفيذ مَتْن حَلْقة التَكْرار (loop body) بشكل لا نهائي (infinite loop) إلى أن يتم إيقافها لسبب ما، مثل اِستخدَام تَعْليمَة <code>break</code>. يُفضِّل بعض المبرمجين في الواقع تَّنْفيذ الحَلْقة اللا نهائية (infinite loop) باِستخدَام الصياغة <code>for (;;)‎</code> بدلًا من <code>while (true)‎</code>.
</p>

<p>
	يُوضح المخطط (diagram) التالي مَسار التحكُّم (flow control) أثناء تَّنْفيذ حَلْقة التَكْرار <code>for</code>:
</p>

<p style="text-align: center;">
	<img alt="001For_Loop_Flow_Control.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53279" data-unique="2gbamcym3" style="" src="https://academy.hsoub.com/uploads/monthly_2020_11/001For_Loop_Flow_Control.png.a3c9eda570a0a26df26b644b0fcf03a8.png">
</p>

<p>
	عادةً ما تُسْنِد تعليمة التهيئة <strong><initialization></initialization></strong> قيمة ما إلى مُتَغيِّر معين، ثم تُعدِّل تعليمة التَحْدِيث <strong><update></update></strong> قيمة هذا المُتَغيِّر إِمّا بواسطة تَعْليمَة إِسْناد (assignment) وإِمّا بعملية زيادة/نُقصان (increment/decrement)، وتُفْحَص تلك القيمة من خلال الشَّرْط الاستمراري لحَلْقة التَكْرار (continuation condition)، فتَتوقَف الحَلْقة عندما يؤول الشَّرْط إلى القيمة المنطقية <code>false</code>. يُطلق عادة على المُتَغيِّر المُستخدَم بهذه الطريقة اسم المُتحكِّم بالحَلْقة (loop control variable). في المثال بالأعلى، كان المُتحكِّم بالحَلْقة هو المُتَغيِّر <code>years</code>.
</p>

<p>
	تُعدّ حَلْقة العَدّ (counting loop) هي النوع الأكثر شيوعًا من حَلْقات التَكْرار <code>for</code>، والتي يأخذ فيها المُتَغيِّر المُتحكِّم بالحَلْقة (loop control variable) قيم جميع الأعداد الصحيحة (integer) الواقعة بين قيمتين إحداهما صغرى (minimum) والآخرى عظمى (maximum). تُكتَب حَلْقة العَدّ كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_19" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="str">&lt;variable&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">&lt;min&gt;</span><span class="pun">;</span><span class="pln">  </span><span class="str">&lt;variable&gt;</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="str">&lt;max&gt;</span><span class="pun">;</span><span class="pln"> </span><span class="str">&lt;variable&gt;</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">&lt;statements&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمكِن لأيّ تعبير يُعيد عددًا صحيحًا (integer-valued expressions) أن يُستخدَم محل <strong><min></min></strong> و <strong><max></max></strong>، ولكن تُستخدَم عادةً قيم ثابتة (constants). يأخذ المُتَغيِّر -المشار إليه باستخدام <strong><variable></variable></strong> بالأعلى والمعروف باسم المُتحكِّم بالحَلْقة (loop control variable)- القيم المتراوحة بين <strong><min></min></strong> و <strong><max></max></strong>، أي القيم <code>‎&lt;min&gt;+1‎‎</code> و <code>‎&lt;min&gt;+2‎‎</code> ..وحتى <strong><max></max></strong>. وغالبًا ما تُستخدَم قيمة هذا المُتَغيِّر داخل المَتْن (body). مثلًا، حَلْقة التَكْرار <code>for</code> بالأعلى هي حَلْقة عَدّ يأخذ فيها المُتَغيِّر المُتحكِّم بالحَلْقة <code>years</code> القيم ١ و ٢ و ٣ و ٤ و ٥.
</p>

<p>
	تطبع الشيفرة التالية قيم الأعداد من ١ إلى ١٠ إلى الخَرْج القياسي (standard output):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_21" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">;</span><span class="pln">  N </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">;</span><span class="pln">  N</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> N </span><span class="pun">);</span></pre>

<p>
	مع ذلك، يُفضِّل مبرمجي لغة الجافا بدء العَدّ (counting) من ٠ بدلًا من ١، كما أنهم يميلون إلى اِستخدَام العَامِل <code>&gt;</code> للموازنة بدلًا من <code>‎&lt;=‎‎</code>. تطبع الشيفرة التالية قيم الأعداد العشرة ٠، ١، ٢، …، ٩، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_23" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">;</span><span class="pln">  N </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">;</span><span class="pln">  N</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> N </span><span class="pun">);</span></pre>

<p>
	يُعدّ اِستخدَام عَامِل الموازنة <code>&gt;</code> بدلًا من <code>‎&lt;=‎‎</code> أو العكس مصدرًا شائعًا لحُدوث الأخطاء بفارق الواحد (off-by-one errors) بالبرامج. حاول دائمًا أن تأخذ وقتًا للتفكير إذا ما كنت تَرغَب بمعالجة القيمة النهائية أم لا.
</p>

<p>
	يُمكنك أيضًا إجراء العَدّ التنازلي، وهو ما قد يكون أسهل قليلًا من العَدّ التصاعدي. فمثلًا، لإجراء عَدّ تنازلي من ١٠ إلى ١. ابدأ فقط بالقيمة ١٠، ثم اِنقص المُتَغيِّر المُتحكِّم بالحَلْقة (loop control variable) بدلًا من زيادته، واستمر طالما كانت قيمة المُتَغيِّر أكبر من أو تُساوِي ١:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_25" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">;</span><span class="pln">  N </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">;</span><span class="pln">  N</span><span class="pun">--</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> N </span><span class="pun">);</span></pre>

<p>
	في الواقع، تَسمَح صيغة (syntax) تَعْليمَة <code>for</code> بأن تَشتمِل كُلًا من تعليمتي التهيئة <strong><initialization></initialization></strong> والتَحْدِيث <strong><update></update></strong> على أكثر من تعبير (expression) مربوطين بفاصلة (comma). يَعنِي ذلك أنه من الممكن الإبقاء على أكثر من عَدَّاد بنفس الوقت، فمثلًا قد يكون لدينا عَدَّاد تصاعدي من ١ إلى ١٠، وآخر تنازلي من ١٠ إلى ١، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_27" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">=</span><span class="lit">10</span><span class="pun">;</span><span class="pln">  i </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">  i</span><span class="pun">++,</span><span class="pln"> j</span><span class="pun">--</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫اطبع قيمة i بخمس خانات</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"%5d"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">);</span><span class="pln"> 
    </span><span class="com">// ‫اطبع قيمة j بخمس خانات</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"%5d"</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">);</span><span class="pln"> 
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">     
</span><span class="pun">}</span></pre>

<p>
	كمثال أخير، نريد اِستخدَام حَلْقة التَكْرار <code>for</code> لطباعة الأعداد الزوجية (even numbers) الواقعة بين العددين ٢ و ٢٠، أي بالتحديد طباعة الأعداد ٢، ٤، ٦، ٨، ١٠، ١٢، ١٤، ١٦، ١٨، ٢٠. تتوفَّر أكثر من طريقة للقيام بذلك، نسْتَعْرِض منها أربعة حلول ممكنة (ثلاث منها هي حلول نموذجية تمامًا)؛ وذلك لبيان كيف لمسألة بسيطة مثل تلك المسألة أن تُحلّ بطرائق مختلفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_29" style=""><span class="com">// (1)   </span><span class="pln">
</span><span class="com">// المتغير المتحكم بالحلقة سيأخذ القيم من واحد إلى عشرة</span><span class="pln">
</span><span class="com">// وبالتالي سنطبع القيم 2*1 و 2*2 و ... إلى 2*10</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> N </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> N</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">             
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> </span><span class="lit">2</span><span class="pun">*</span><span class="pln">N </span><span class="pun">);</span><span class="pln">         
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// (2)   </span><span class="pln">
</span><span class="com">// المتغير المتحكم بالحلقة سيأخذ القيم المطلوب طباعتها مباشرة</span><span class="pln">
</span><span class="com">// عن طريق إضافة 2 بعبارة التحديث بدلًا من واحد</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> N </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> N </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> N </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// (3)   </span><span class="pln">
</span><span class="com">// مر على جميع الأرقام من اثنين إلى عشرين </span><span class="pln">
</span><span class="com">// ولكن اطبع فقط الأعداد الزوجية</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> N </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln"> N</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">             
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="com">// is N even?     </span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> N </span><span class="pun">);</span><span class="pln">       
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">// (4)   </span><span class="pln">
</span><span class="com">// فقط اطبع الأعداد المطلوبة مباشرة</span><span class="pln">
</span><span class="com">// غالبًا سيغضب منك الأستاذ في حالة إطلاعه على مثل هذا الحل</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> N </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> N</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"2 4 6 8 10 12 14 16 18 20"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	من المهم أن نُعيد التأكيد على أنه -باستثناء تَعْليمَة التَّصْريح عن المُتَغيِّرات (variable declaration)- ليس مُمكنًا بأي حال من الأحوال تَّنْفيذ أي تَعْليمَة برمجية، بما في ذلك تَعْليمَة <code>for</code>، بشكل مستقل، وإنما ينبغي أن تُنفَّذ إما داخل البرنامج (routine) الرئيسي <code>main</code> أو داخل إحدى البرامج الفرعية (subroutine)، والمُعرَّفة ضِمْن صَنْف معين (class).
</p>

<p>
	لابُدّ أيضًا من التَّصْريح (declaration) عن أي مُتَغيِّر قبل إمكانية اِستخدَامه، بما في ذلك المُتَغيِّر المُتحكِّم بالحَلْقة (loop control variable) المُستخدَم ضِمْن حَلْقة التَكْرار <code>for</code>. صَرَّحنا عن هذا المُتَغيِّر بكونه من النوع العددي الصحيح (int) بالأمثلة التي فحصناها حتى الآن بهذا القسم. مع ذلك، فإنه ليس أمرًا حتميًا، فقد يكون من نوع آخر. فمثلًا، تَستخدِم حَلْقة التَكْرار <code>for</code> -بالمثال التالي- مُتَغيِّرًا من النوع <code>char</code>، وتعتمد على إمكانية تطبيق عَامِل الزيادة <code>++</code> على كُلًا من الحروف والأرقام:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_31" style=""><span class="kwd">char</span><span class="pln"> ch</span><span class="pun">;</span><span class="pln">  </span><span class="com">// المتغير المتحكم بالحلقة; </span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> ch </span><span class="pun">=</span><span class="pln"> </span><span class="str">'A'</span><span class="pun">;</span><span class="pln">  ch </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="str">'Z'</span><span class="pun">;</span><span class="pln">  ch</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="com">// اطبع حرف الأبجدية الحالي</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">ch</span><span class="pun">);</span><span class="pln"> 
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span></pre>

<h1>
	مسألة عد القواسم (divisors)
</h1>

<p>
	سنُلقِي الآن نظرة على مسألة أكثر جدية، والتي يُمكِن حلّها باِستخدَام حَلْقة التَكْرار <code>for</code>. بفَرْض أن لدينا عددين صحيحين موجبين (positive integers)‏ <code>N</code> و <code>D</code>. إذا كان باقي قسمة (remainder) العدد <code>N</code> على العدد <code>D</code> مُساوٍ للصفر، يُقال عندها أن الثاني قَاسِمًا (divisor) للأول أو أن الأول مُضاعَفًا (even multiple) للثاني. بالمثل، يُقال -بتعبير لغة الجافا- أن العدد <code>D</code> قَاسِمًا (divisor) للعدد <code>N</code> إذا تَحقَّق الشَّرْط <code>N % D == 0</code>، حيث <code>%</code> هو عَامِل باقي القسمة.
</p>

<p>
	يَسمَح البرنامج التالي للمُستخدِم بإِدْخَال عدد صحيح موجب (positive integer)، ثُمَّ يَحسِب عَدَد القواسم (divisors) المختلفة لذلك العَدَد. لحِساب عَدَد قواسم (divisors) عَدَد معين <code>N</code>، يُمكننا ببساطة فَحْص جميع الأَعْدَاد التي يُحتمَل أن تكون قَاسِمًا للعَدَد <code>N</code>، أيّ جميع الأَعْدَاد الواقعة بدايةً من الواحد ووصولًا للعَدَد <code>N</code> (١، ٢، ٣، … ،<code>N</code>). ثم نَعدّ منها فقط تلكم التي أَمكنها التقسيم الفعليّ للعَدَد <code>N</code> تقسيمًا مُتعادلًا (evenly). على الرغم من أن هذه الطريقة ستُؤدي إلى نتائج صحيحة، فلربما هي ليست الطريقة الأكثر كفاءة لحلّ هذه المسألة. تَسْتَعْرِض الشيفرة التالية الخوارزمية بالشيفرة الوهمية (pseudocode):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_33" style=""><span class="com">// ‫اقرأ قيمة عددية موجبة من المستخدم N</span><span class="pln">
</span><span class="typ">Get</span><span class="pln"> a positive integer</span><span class="pun">,</span><span class="pln"> N</span><span class="pun">,</span><span class="pln"> from the user
</span><span class="com">// هيئ عداد القواسم</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> divisorCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="com">// ‫لكل عدد من القيمة واحد وحتى القيمة العددية المدخلة testDivisor</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> each number</span><span class="pun">,</span><span class="pln"> testDivisor</span><span class="pun">,</span><span class="pln"> in the range from </span><span class="lit">1</span><span class="pln"> to N</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// إذا كان العدد الحالي قاسم للعدد المدخل</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> testDivisor is a divisor of N</span><span class="pun">:</span><span class="pln">
        </span><span class="com">// أزد قيمة العداد بمقدار الواحد</span><span class="pln">
        </span><span class="typ">Count</span><span class="pln"> it by adding </span><span class="lit">1</span><span class="pln"> to divisorCount
</span><span class="com">// اطبع قيمة العداد       </span><span class="pln">
</span><span class="typ">Output</span><span class="pln"> the count</span></pre>

<p>
	تَسْتَعْرِض الخوارزمية السابقة واحدة من الأنماط البرمجية (programming pattern) الشائعة، والتي تُستخدَم عندما يكون لديك مُتتالية (sequence) من العناصر، وتَرغَب بمعالجة بعضًا من تلك العناصر فقط، وليس كلها. يُمكِن تَعْمِيم هذا النمط للصيغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_35" style=""><span class="com">// لكل عنصر بالمتتالية</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> each item in the sequence</span><span class="pun">:</span><span class="pln">
   </span><span class="com">// إذا نجح العنصر الحالي بالاختبار</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> the item passes the test</span><span class="pun">:</span><span class="pln">
       </span><span class="com">// عالج العنصر الحالي</span><span class="pln">
       process it</span></pre>

<p>
	يُمكننا تَحْوِيل حَلْقة التَكْرار <code>for</code> الموجودة ضِمْن خوارزمية عَدّ القواسم بالأعلى (divisor-counting algorithm) إلى لغة الجافا كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_37" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">testDivisor </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> testDivisor </span><span class="pun">&lt;=</span><span class="pln"> N</span><span class="pun">;</span><span class="pln"> testDivisor</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">%</span><span class="pln"> testDivisor </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
      divisorCount</span><span class="pun">++;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بإمكان الحواسيب الحديثة تَّنْفيذ حَلْقة التَكْرار (loop) بالأعلى بسرعة، بل لا يَسْتَحِيل حتى تَّنْفيذها على أكبر عَدَد يُمكن أن يَحمله النوع <code>int</code>، والذي يَصِل إلى ٢١٤٧٤٨٣٦٤٧، ربما حتى قد تَستخدِم النوع <code>long</code> للسماح بأعداد أكبر، ولكن بالطبع سيستغرق تَّنْفيذ الخوارزمية وقتًا أطول مع الأعداد الكبيرة جدًا، ولذلك تَقَرَّر إِجراء تعديل على الخوارزمية بهدف طباعة نقطة (dot) -تَعمَل كمؤشر- بَعْد كل مرة ينتهي فيها الحاسوب من اختبار عشرة مليون قَاسِم (divisor) مُحتمَل جديد. سنضطر في النسخة المُعدَّلة من الخوارزمية إلى الإبقاء على عَدَّادين (counters) منفصلين: الأول منهما لعَدّ القواسم (divisors) الفعليّة التي تحصَّلَنا عليها، والآخر لعَدّ جميع الأعداد التي اُختبرت حتى الآن. عندما يَصل العَدَّاد الثاني إلى قيمة عشرة ملايين، سيَطبع البرنامج نقطة <code>.</code>، ثُمَّ يُعيد ضَبْط قيمة ذلك العَدَّاد إلى صفر؛ ليبدأ العَدّ من جديد. تُصبِح الخوارزمية باِستخدَام الشيفرة الوهمية كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_39" style=""><span class="com">// اقرأ عدد صحيح موجب من المستخدم</span><span class="pln">
</span><span class="typ">Get</span><span class="pln"> a positive integer</span><span class="pun">,</span><span class="pln"> N</span><span class="pun">,</span><span class="pln"> from the user
</span><span class="typ">Let</span><span class="pln"> divisorCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">  </span><span class="com">// عدد القواسم التي تم العثور عليها</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> numberTested </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">  </span><span class="com">// عدد القواسم المحتملة والتي تم اختبارها</span><span class="pln">

</span><span class="com">// ‫اقرأ رد المستخدم إلى المتغير str</span><span class="pln">
</span><span class="com">// ‫لكل عدد يتراوح من القيمة واحد وحتى قيمة العدد المدخل</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> each number</span><span class="pun">,</span><span class="pln"> testDivisor</span><span class="pun">,</span><span class="pln"> in the range from </span><span class="lit">1</span><span class="pln"> to N</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// إذا كان العدد الحالي قاسم للعدد المدخل </span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> testDivisor is a divisor of N</span><span class="pun">:</span><span class="pln">
        </span><span class="com">// أزد عدد القواسم التي تم العثور عليها بمقدار الواحد</span><span class="pln">
        </span><span class="typ">Count</span><span class="pln"> it by adding </span><span class="lit">1</span><span class="pln"> to divisorCount
    </span><span class="com">// أزد عدد الأعداد المحتملة التي تم اختبارها بمقدار الواحد</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to numberTested
    </span><span class="com">// إذا كان عدد الأعداد المحتملة المختبر يساوي عشرة ملايين</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> numberTested is </span><span class="lit">10000000</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// اطبع نقطة</span><span class="pln">
        print out a </span><span class="str">'.'</span><span class="pln">
    </span><span class="com">// أعد ضبط عدد الأعداد المختبرة إلى القيمة صفر</span><span class="pln">
        </span><span class="typ">Reset</span><span class="pln"> numberTested to </span><span class="lit">0</span><span class="pln">
</span><span class="com">// اطبع عدد القواسم</span><span class="pln">
</span><span class="typ">Output</span><span class="pln"> the count</span></pre>

<p>
	وأخيرًا، يُمكننا تَحْوِيل الخوارزمية إلى برنامج كامل بلغة الجافا، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_41" style=""><span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CountDivisors</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">int</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">  </span><span class="com">// القيمة العددية المدخلة من قبل المستخدم </span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> testDivisor</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫عدد يتراوح من القيمة واحد وحتى N</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> divisorCount</span><span class="pun">;</span><span class="pln"> </span><span class="com">// عدد قواسم‫ N التي عثر عليها حتى الآن</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> numberTested</span><span class="pun">;</span><span class="pln">  </span><span class="com">// عدد القواسم المحتملة التي تم اختبارها </span><span class="pln">

        </span><span class="com">// اقرأ قيمة عدد صحيح موجبة من المستخدم</span><span class="pln">
        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter a positive integer: "</span><span class="pun">);</span><span class="pln">
            N </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"That number is not positive.  Please try again."</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="com">// عِدّ القواسم واطبع نقطة بعد كل عشرة ملايين اختبار</span><span class="pln">
        divisorCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        numberTested </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">testDivisor </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> testDivisor </span><span class="pun">&lt;=</span><span class="pln"> N</span><span class="pun">;</span><span class="pln"> testDivisor</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">%</span><span class="pln"> testDivisor </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
                divisorCount</span><span class="pun">++;</span><span class="pln">
            numberTested</span><span class="pun">++;</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">numberTested </span><span class="pun">==</span><span class="pln"> </span><span class="lit">10000000</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">'.'</span><span class="pun">);</span><span class="pln">
                numberTested </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="com">// اعرض النتائج</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number of divisors of "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> N
                           </span><span class="pun">+</span><span class="pln"> </span><span class="str">" is "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> divisorCount</span><span class="pun">);</span><span class="pln">

    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية البرنامج main</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف CountDivisors</span></pre>

<h2>
	حلقات <code>for</code> المتداخلة
</h2>

<p>
	كما ذَكَرنا مُسْبَّقًا، فإن بُنَى التحكُّم (control structures) بلغة الجافا هي ببساطة تَعْليمَات مُركَّبة، أي تَتضمَّن مجموعة تَعْليمَات. في الحقيقة، يُمكن أيضًا لبِنْية تحكُّم (control structure) أن تَشتمِل على بِنْية تحكُّم أخرى أو أكثر، سواء كانت من نفس النوع أو من أيّ نوع آخر، ويُطلَق عليها في تلك الحالة اسم بُنَى التحكُّم المُتداخِلة (nested). لقد مررنا بالفعل على عدة أمثلة تَتضمَّن هذا النوع من البُنَى، فمثلًا رأينا تَعْليمَات <code>if</code> ضِمْن حَلْقات تَكْرارية (loops)، كما رأينا حَلْقة <code>while</code> داخلية (inner) مُضمَّنة بداخل حَلْقة <code>while</code> آخرى خارجية. لا يَقتصر الأمر على هذه الأمثلة؛ حيث يُسمَح عامةً بدمج بُنَى التحكُّم بأي طريقة ممكنة، وتستطيع حتى القيام بذلك على عدة مستويات من التَدَاخُل (levels of nesting)، فمثلًا يُمكن لحَلْقة <code>while</code> أن تَحتوِي على تَعْليمَة <code>if</code>، والتي بدورها قد تَحتوِي على تَعْليمَة <code>while</code> آخرى؛ فلغة الجافا <code>Java</code> لا تَضع عامةً أي قيود على عدد مستويات التَدَاخُل المسموح بها، ومع ذلك يَصعُب عمليًا فهم الشيفرة إذا اِحْتَوت على أكثر من عدد قليل من مستويات التَدَاخُل (levels of nesting).
</p>

<p>
	تَستخدِم كثير من الخوارزميات حَلْقات <code>for</code> المُتداخِلة (nested)، لذا من المهم أن تفهم طريقة عملها. دعنا نَفحْص عدة أمثلة، مثلًا، مسألة طباعة جدول الضرب (multiplication table) على الصورة التالية:
</p>

<pre class="ipsCode"> 1   2   3   4   5   6   7   8   9  10  11  12
 2   4   6   8  10  12  14  16  18  20  22  24
 3   6   9  12  15  18  21  24  27  30  33  36
 4   8  12  16  20  24  28  32  36  40  44  48
 5  10  15  20  25  30  35  40  45  50  55  60
 6  12  18  24  30  36  42  48  54  60  66  72
 7  14  21  28  35  42  49  56  63  70  77  84
 8  16  24  32  40  48  56  64  72  80  88  96
 9  18  27  36  45  54  63  72  81  90  99 108
10  20  30  40  50  60  70  80  90 100 110 120
11  22  33  44  55  66  77  88  99 110 121 132
12  24  36  48  60  72  84  96 108 120 132 144
</pre>

<p>
	نُظِّمت البيانات بالجدول إلى ١٢ صف و ١٢ عمود. اُنظر الخوارزمية التالية -بالشيفرة الوهمية (pseudocode)- لطباعة جدول مُشابه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_44" style=""><span class="kwd">for</span><span class="pln"> each rowNumber </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// اطبع بسَطر منفصل المضاعفات الاثنى عشر الأولى من قيمة المتغير </span><span class="pln">
    </span><span class="typ">Print</span><span class="pln"> the first twelve multiples of rowNumber on one line
    </span><span class="com">// اطبع محرف العودة الى بداية السطر</span><span class="pln">
    </span><span class="typ">Output</span><span class="pln"> a carriage </span><span class="kwd">return</span></pre>

<p>
	في الواقع، يُمكن للسطر الأول بمَتْن حَلْقة <code>for</code> بالأعلى "اطبع بسَطر منفصل المضاعفات الاثنى عشر الأولى من قيمة المتغير الحالية" أن يُكتَب على صورة حَلْقة <code>for</code> أخرى منفصلة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_46" style=""><span class="kwd">for</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
   </span><span class="typ">Print</span><span class="pln"> N </span><span class="pun">*</span><span class="pln"> rowNumber</span></pre>

<p>
	تحتوي الآن النسخة المُعدَّلة من خوارزمية طباعة جدول الضرب على حَلْقتي <code>for</code> مُتداخِلتين، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_48" style=""><span class="kwd">for</span><span class="pln"> each rowNumber </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
      </span><span class="typ">Print</span><span class="pln"> N </span><span class="pun">*</span><span class="pln"> rowNumber
   </span><span class="com">// اطبع محرف العودة الى بداية السطر</span><span class="pln">
   </span><span class="typ">Output</span><span class="pln"> a carriage </span><span class="kwd">return</span></pre>

<p>
	يُمكن اِستخدَام مُحدِّدات الصيغة (format specifier) عند طباعة خَرْج ما (output)؛ بهدف تخصيص صيغة هذا الخَرْج، ولهذا سنَستخدِم مُحدِّد الصيغة <code>‎%4d‎</code> عند طباعة أيّ عَدَد بالجدول؛ وذلك لجعله يَحْتلَّ أربعة خانات دائمًا دون النظر لعَدَد الخانات المطلوبة فعليًا، مما يُحسِن من شكل الجدول النهائي. بفَرْض أنه قد تم الإعلان عن المُتَغيِّرين <code>rowNumber</code> و <code>N</code> بحيث يَكُونا من النوع العددي <code>int</code>، يمكن عندها كتابة الخوارزمية بلغة الجافا، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_50" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> rowNumber </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">  rowNumber </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">  rowNumber</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">  N </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">  N</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// اطبع الرقم بأربع خانات بدون طباعة محرف العودة الى بداية السطر</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%4d"</span><span class="pun">,</span><span class="pln"> N </span><span class="pun">*</span><span class="pln"> rowNumber </span><span class="pun">);</span><span class="pln">  
    </span><span class="pun">}</span><span class="pln">
    </span><span class="com">// اطبع محرف العودة الى بداية السطر </span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">  
</span><span class="pun">}</span></pre>

<p>
	ربما قد لاحظت أن جميع الأمثلة التي تَعْرَضنا لها -خلال هذا القسم- حتى الآن تَتعامَل فقط مع الأعداد، لذلك سننتقل خلال المثال التالي إلى معالجة النصوص (text processing). لنفْترِض أن لدينا سِلسِلة نصية (string)، ونريد كتابة برنامج لتَحْدِيد الحروف الأبجدية (letters of the alphabet) الموجودة بتلك السِلسِلة. فمثلًا، إذا كان لدينا السِلسِلة النصية "أهلًا بالعالم"، فإن الحروف الموجودة بها هي الألف، والباء، والعين، واللام، والميم، والهاء. سيَستقبِل البرنامج، بالتَحْدِيد، سِلسِلة نصية من المُستخدِم، ثم يَعرِض قائمة بكل تلك الحروف المختلفة الموجودة ضمن تلك السِلسِلة، بالإضافة إلى عَدَدها. كالعادة، سنبدأ أولًا بكتابة الخوارزمية بصيغة الشيفرة الوهمية (pseudocode)، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_52" style=""><span class="com">// اطلب من المستخدم إدخال سلسلة نصية</span><span class="pln">
</span><span class="typ">Ask</span><span class="pln"> the user to input a string
</span><span class="com">// ‫اقرأ رد المستخدم إلى المتغير str</span><span class="pln">
</span><span class="typ">Read</span><span class="pln"> the response into a variable</span><span class="pun">,</span><span class="pln"> str
</span><span class="com">// هيئ عداد لعدّ الحروف المختلفة</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">  </span><span class="pun">(</span><span class="kwd">for</span><span class="pln"> counting the number of different letters</span><span class="pun">)</span><span class="pln">
</span><span class="com">// لكل حرف أبجدي</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> each letter of the alphabet</span><span class="pun">:</span><span class="pln">
   </span><span class="com">// إذا كان الحرف موجودًا بالسلسلة النصية</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> the letter occurs in str</span><span class="pun">:</span><span class="pln">
      </span><span class="com">// اطبع الحرف</span><span class="pln">
      </span><span class="typ">Print</span><span class="pln"> the letter
      </span><span class="com">// أزد قيمة العداد</span><span class="pln">
      </span><span class="typ">Add</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to count
</span><span class="com">// اطبع قيمة العداد</span><span class="pln">
</span><span class="typ">Output</span><span class="pln"> the count</span></pre>

<p>
	سنَستخدِم الدالة <code>TextIO.getln()‎</code> لقراءة السَطْر الذي أَدْخَله المُستخدِم بالكامل؛ وذلك لحاجتنا إلى معالجته على خطوة واحدة. يُمكننا تَحْوِيل سَطْر الخوارزمية "لكل حرف أبجدي" إلى حَلْقة التَكْرار <code>for</code> كالتالي <code>for (letter='A'; letter&lt;='Z'; letter++)‎</code>. في المقابل، سنحتاج إلى التفكير قليلًا بالطريقة التي سنكتب بها تَعْليمَة <code>if</code> الموجودة ضِمْن تلك الحَلْقة. نُريد تَحْدِيدًا إيجاد طريقة نتحقَّق من خلالها إذا ما كان الحرف الأبجدي الحالي بالتَكْرار (iteration)‏ <code>letter</code> موجودًا بالسِلسِلة النصية <code>str</code> أم لا. أحد الحلول هو المرور على جميع حروف السِلسِلة النصية <code>str</code> حرفًا حرفًا، لفَحْص ما إذا كان أيًا منها مُساو لقيمة الحرف الأبجدي الحالي‏ <code>letter</code>، ولهذا سنَستخدِم الدالة <code>str.charAt(i)‎</code> لجَلْب الحرف الموجود بموقع معين <code>i</code> بالسِلسِلة النصية <code>str</code>، بحيث تَتراوح قيمة <code>i</code> من الصفر وحتى عدد حروف السِلسِلة النصية، والتي يُمكن حِسَابها باِستخدَام التعبير <code>str.length() - 1</code>.
</p>

<p>
	سنواجه مشكلة أخرى، وهي إمكانية وجود الحرف الأبجدي بالسِلسِلة النصية <code>str</code> على صورتين، كحرف كبير (upper case) أو كحرف صغير (lower case). فمثلًا قد يكون الحرف <code>A</code> على الصورة <code>A</code> أو <code>a</code>، ولذلك نحن بحاجة لفَحْص كلتا الحالتين. قد نتجنب، في المقابل، هذه المشكلة بتَحْوِيل جميع حروف السِلسِلة النصية <code>str</code> إلى الحروف الكبيرة (upper case) قبل بدء المعالجة، وعندها نستطيع فَحْص الحروف الكبيرة (upper case) فقط. والآن نُعيد صياغة الخوارزمية كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_54" style=""><span class="com">// اطلب من المستخدم إدخال سلسلة نصية</span><span class="pln">
</span><span class="typ">Ask</span><span class="pln"> the user to input a string
</span><span class="com">// ‫اقرأ رد المستخدم إلى المتغير str</span><span class="pln">
</span><span class="typ">Read</span><span class="pln"> the response into a variable</span><span class="pun">,</span><span class="pln"> str
</span><span class="com">// كَبِّر حروف السلسلة النصية</span><span class="pln">
</span><span class="typ">Convert</span><span class="pln"> str to upper </span><span class="kwd">case</span><span class="pln">
</span><span class="com">// هيئ عداد لعدّ الحروف المختلفة</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> letter </span><span class="pun">=</span><span class="pln"> </span><span class="str">'A'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> </span><span class="str">'Z'</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()-</span><span class="lit">1</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> letter </span><span class="pun">==</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">):</span><span class="pln">
               </span><span class="com">// اطبع الحرف</span><span class="pln">
            </span><span class="typ">Print</span><span class="pln"> letter
            </span><span class="com">// أزد قيمة العداد</span><span class="pln">
            </span><span class="typ">Add</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to count
            </span><span class="com">// اخرج من الحلقة لتجنب إعادة عدّ الحرف أكثر من مرة</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln">  
</span><span class="typ">Output</span><span class="pln"> the count</span></pre>

<p>
	لاحظ اِستخدَامنا لتَعْليمَة <code>break</code> داخل حَلْقة تَكْرار <code>for</code> الداخلية؛ حتى نتجنب طباعة حرف الأبجدية الحالي‏ <code>letter</code> وعَدّه مجددًا إذا كان موجودًا أكثر من مرة بالسِلسِلة النصية. تُوقِف تَعْليمَة <code>break</code> حَلْقة التَكْرار <code>for</code> الداخلية فقط (inner loop)، وليس الخارجية (outer loop)، والتي ينتقل الحاسوب في الواقع إلى تَّنْفيذها بمجرد خروجه من الحَلْقة الداخلية، ولكن مع حرف الأبجدية التالي. حاول استكشاف القيمة النهائية للمُتَغيِّر <code>count</code> في حالة حَذْف تَعْليمَة <code>break</code>.
</p>

<p>
	تَسْتَعْرِض الشيفرة التالية البرنامج بالكامل بلغة الجافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6667_56" style=""><span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ListLetters</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">String</span><span class="pln"> str</span><span class="pun">;</span><span class="pln">  </span><span class="com">// السطر المدخل من قبل المستخدم</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">   </span><span class="com">// عدد الحروف المختلفة الموجودة بالسلسلة النصية</span><span class="pln">
        </span><span class="kwd">char</span><span class="pln"> letter</span><span class="pun">;</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Please type in a line of text."</span><span class="pun">);</span><span class="pln">
        str </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">

        str </span><span class="pun">=</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">toUpperCase</span><span class="pun">();</span><span class="pln">

        count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Your input contains the following letters:"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"   "</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> letter </span><span class="pun">=</span><span class="pln"> </span><span class="str">'A'</span><span class="pun">;</span><span class="pln"> letter </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="str">'Z'</span><span class="pun">;</span><span class="pln"> letter</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">  </span><span class="com">// موضع الحرف بالسِلسِلة النصية</span><span class="pln">
            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> letter </span><span class="pun">==</span><span class="pln"> str</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">letter</span><span class="pun">);</span><span class="pln">
                    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">' '</span><span class="pun">);</span><span class="pln">
                    count</span><span class="pun">++;</span><span class="pln">
                    </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"There were "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> count </span><span class="pun">+</span><span class="pln"> </span><span class="str">" different letters."</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية البرنامج main</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف ListLetters</span></pre>

<p>
	في الواقع، تتوفَّر الدالة <code>str.indexOf(letter)‎</code> المبنية مُسْبَّقًا (built-in function)، والمُستخدَمة لاختبار ما إذا كان الحرف <code>letter</code> موجودًا بالسِلسِلة النصية <code>str</code> أم لا. إذا لم يكن الحرف موجودًا بالسِلسِلة، ستُعيد الدالة القيمة <code>-1</code>، أما إذا كان موجودًا، فإنها ستُعيد قيمة أكبر من أو تُساوي الصفر. ولهذا كان يمكننا ببساطة إجراء عملية فَحْص وجود الحرف بالسِلسِلة باِستخدَام التعبير <code>if (str.indexOf(letter) &gt;= 0)‎</code>، بدلًا من اِستخدَام حَلْقة تَكْرار مُتداخِلة (nested loop). يتضح لنا من خلال هذا المثال كيف يمكننا اِستخدَام البرامج الفرعية (subroutines)؛ لتبسيط المسائل المعقدة ولكتابة شيفرة مَقْرُوءة.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s4.html" rel="external nofollow">Section 4: The for Statement</a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1065</guid><pubDate>Sun, 15 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x644;&#x64A;&#x645;&#x62A;&#x64A; &#x627;&#x644;&#x62D;&#x644;&#x642;&#x627;&#x62A; while &#x648; do..while &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%AA%D9%8A-%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-while-%D9%88-dowhile-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1064/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/16.png.4e1db060a337f4b8c69e323458a5d5cd.png" /></p>

<p>
	تُصنَّف التَعْليمات البرمجية (statements) بأي لغة برمجة -ومنها الجافا <code>Java</code>- إلى تَعْليمات بسيطة (simple) وأخرى مُركَّبة (compound). تُعدّ التَعْليمات البسيطة -مثل تَعْليمَة الإِسْناد (assignment) وتَعْليمَة اِسْتدعاء البرامج الفرعية (subroutine call)- اللَبِنة الأساسية لأيّ برنامج. في المُقابل، تتكون التَعْليمات المُركَّبة -مثل تَعْليمَة حَلْقة التَكْرار <code>while</code> وتَعْليمَة التَفْرِيع الشَّرطيّة <code>if</code>- من عدد من التَعْليمات البسيطة، وتُعرَف باسم بُنَى التحكُّم (control structures)؛ نظرًا لأنها تَتَحكَّم بترتيب تَّنْفيذ التَعْليمات.
</p>

<p>
	سنتناول بُنَى التحكُّم (control structures) المُدَعَّمة بلغة الجافا <code>Java</code> بشئٍ من التفصيل خلال الأقسام الخمسة التالية، بحيث نبدأ في هذا القسم بتَعْليمتي الحَلْقة <code>while</code> و <code>do..while</code>. سنتَعرَّض، خلال ذلك، لكثير من الأمثلة البرمجية التي تُوظِّف بُنَى التحكُّم تلك، كما أننا وبينما نقوم بذلك، سنُطبِّق التقنيات المُتَّبَعة بتصميم الخوارزميات (algorithms)، والتي قد تَعرَّضنا لها بالفصل السابق.
</p>

<h3>
	تَعْليمَة <code>while</code>
</h3>

<p>
	تُكتَب تَعْليمَة حَلْقة التَكْرار (loop)‏ <code>while</code> -والتي قد تَعرَّضت لها مُسْبقًا بالقسم ٣.١- بالصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_7" style="">
<span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="str">&lt;statement&gt;</span></pre>

<p>
	لا يُشترَط أن تتكوَّن التعليمة <strong><statement></statement></strong> -المُشار إليها بالأعلى، والمعروفة باسم مَتْن حَلْقة التَكْرار (loop body)- من تَعْليمَة واحدة فقط، فبالطبع يُمكنها أن تكون كُتليّة البِنْية (block statement)، بحيث تَتضمَّن عدة تَعْليمَات مُحَاطة بزوج من الأقواس. يَتكرَّر تَّنْفيذ مَتْن الحَلْقة (body of the loop) طالما كان التعبير <strong><boolean-expression></boolean-expression></strong> -المُشار إليه بالأعلى- مُتحقِّقًا. تتكون تلك العبارة من تَعبير منطقي (boolean expression)، وتُعرَف باسم الشَّرْط الاستمراري (continuation condition) لحَلْقة التَكْرار أو باسم اختبار حَلْقة التَكْرار.
</p>

<p>
	نحتاج الآن لإِيضاح عدة نقاط بشيء من التفصيل. أولًا، ماذا يَحدُث إذا لم يَتحقَّق شَّرْط حَلْقة التَكْرار ولو لمرة واحدة على الأقل، بمعنى أنه لم يَكُن متحقِّقًا قبل التَّنْفيذ الأوَّليّ لمَتْن الحَلْقة؟ في هذه الحالة، لا يُنفَّذ مَتْن الحَلْقة (body) نهائيًا، وهو ما يعني أن مَتْن حَلْقة <code>while</code> يُمكِن أن يُنفَّذ أيّ عدد من المرات بما في ذلك الصفر. ثانيًا، ماذا لو كان شَّرْط حَلْقة التَكْرار مُتحقِّقًا، لكن وبينما يُنفَّذ مَتْن الحَلْقة لم يَعُدْ الشَّرْط كذلك؟ هل يَتوقَف تَّنْفيذ الحَلْقة بمجرد حُدُوث ذلك؟ ببساطة لا؛ حيث يَستمِر الحاسوب بتَّنْفيذ مَتْن الحَلْقة بالكامل حتى يَصِل إلى نهايته، وعِندها فقط يَقفز عائدًا إلى بداية حَلْقة التَكْرار لفَحْص شَّرْطها (continuation condition) مُجددًا، ومِنْ ثَمَّ، يَستطيع في تلك اللحظة فقط إِيقاف الحَلْقة وليس قبل ذلك.
</p>

<p>
	لنفْحَص إِحدى المشكلات التي تُحلّ باِستخدَام حَلْقة التَكْرار <code>while</code>: حِساب قيمة متوسط (average) مجموعة من الأعداد الصحيحة الموجبة (positive integers)، والتي يَتم إِدْخالها من قِبَل المُستخدِم. تُحسَب قيمة المتوسط (average) عمومًا بحِساب حاصل مجموع الأعداد ثم قِسمته على عَدَدها. سيَطلب البرنامج من المُستخدِم إِدْخال عدد صحيح (integer) وحيد في المرة، وسيَحتفِظ دومًا بقيمة المجموع الكلي للأعداد الصحيحة المُدْخَلة حتى اللحظة الراهنة، وكذلك عَدَدها، كما سيُبقي هذه القيم مُحْدَثة مع كل عملية إِدْخال.
</p>

<p>
	هاك خوارزمية البرنامج (algorithm) مَكتوبة بأسلوب الشيفرة الوهمية (pseudocode):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_9" style="">
<span class="typ">Let</span><span class="pln"> sum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">     
</span><span class="typ">Let</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">  

</span><span class="com">// طالما لا يوجد المزيد من الأعداد الصحيحة للمعالجة</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> there are more integers to process</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// اقرأ عدد صحيح</span><span class="pln">
    </span><span class="typ">Read</span><span class="pln"> an integer 
    </span><span class="com">// ‫أضف قيمته إلى المتغير sum</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> it to the sum
    </span><span class="com">// أزد قيمة العداد</span><span class="pln">
    </span><span class="typ">Count</span><span class="pln"> it
</span><span class="com">// ‫اقسم المجموع sum على count لحساب قيمة المتوسط</span><span class="pln">
</span><span class="typ">Divide</span><span class="pln"> sum by count to get the average
</span><span class="com">// اطبع قيمة المتوسط</span><span class="pln">
</span><span class="typ">Print</span><span class="pln"> out the average</span></pre>

<p>
	لكن كيف سنتحقَّق فعليًا من شَّرْط الحَلْقة بالأعلى "طالما لا يوجد المزيد من الأعداد الصحيحة للمعالجة"؟ أحد الحلول هو إِبلاغ المُستخدِم بأن يُدخِل القيمة صفر بعد أن يَنتهِي من إِدْخال جميع البيانات الفعليَّة. ستَنجح تلك الطريقة نظرًا لأننا نَفترِض أن البيانات الفعليَّة المُدْخَلة لابُدّ وأن تَكون من الأعداد الصحيحة الموجبة، وهو ما يَعني أن الصفر يُعدّ قيمة غيْر صالحة من الأساس. لاحِظ أن الصفر هنا ليس قيمة بحدّ ذاتِها يَنبغي تَضْمِينها مع الأعداد المطلوب حِساب مُتوسطها، وإِنما هي فقط مطلوبة كعلامة للإشارة إلى نهاية البيانات الفعليَّة. يُطلق أحيانًا على قِيَم البيانات المُستخدَمة بطريقة مُشابهة اسم بَيَان البداية/النهاية (sentinel value). سنُعدِّل الآن اختبار حَلْقة التَكْرار <code>while</code> ليُصبِح "طالما العدد الصحيح المُدخل لا يساوي الصفر". ستُواجهنا مشكلة آخرى، عندما يُنفَّذ اختبار حَلْقة التَكْرار (loop) لأول مرة، أي قَبْل التَّنْفيذ الأوَّليّ لمَتْن الحَلْقة، لن يكون هناك عدد صحيح قد قُرأ بَعْد، بل ليس هناك أيّ بيانات قد قُرِأت أساسًا، مما يَعني أنه لا يوجد "عدد صحيح مُدخل". ولهذا، يُصبِح اختبار الحَلْقة "طالما العدد الصحيح المُدخل لا يساوي الصفر" -ضِمْن هذا السياق- غَيْر ذي مَعنى. لذلك يَنبغي القيام بأمر ما قَبل البدء بتَّنْفيذ حَلْقة التَكْرار <code>while</code> للتأكد من صلاحية الاختبار حتى مع أول تَّنْفيذ له. تُعرَف هذه العملية باسم التهيئة المبدئية (priming the loop) لحَلْقة التَكْرار، وفي هذه الحالة بالتحديد، يُمكننا ببساطة تهيئة الحَلْقة عن طريق قراءة أول عدد صحيح مُدْخَل قَبل بدء تَّنْفيذ حَلْقة التَكْرار. هاك الخوارزمية (algorithm) المُعدَّلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_11" style="">
<span class="typ">Let</span><span class="pln"> sum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">

</span><span class="com">// اقرأ عدد صحيح</span><span class="pln">
</span><span class="typ">Read</span><span class="pln"> an integer

</span><span class="com">// طالما العدد الصحيح المُدخل لا يساوي الصفر</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> the integer is not zero</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// ‫أضف قيمته إلى المتغير sum</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> the integer to the sum
    </span><span class="com">// أزد قيمة العداد</span><span class="pln">
    </span><span class="typ">Count</span><span class="pln"> it
    </span><span class="com">// اقرأ عدد صحيح</span><span class="pln">
    </span><span class="typ">Read</span><span class="pln"> an integer
</span><span class="com">// ‫اقسم المجموع sum على count لحساب قيمة المتوسط</span><span class="pln">
</span><span class="typ">Divide</span><span class="pln"> sum by count to get the average
</span><span class="com">// اطبع قيمة المتوسط</span><span class="pln">
</span><span class="typ">Print</span><span class="pln"> out the average</span></pre>

<p>
	لاحِظ إعادة ترتيب تَعْليمَات مَتْن حَلْقة التَكْرار (loop body)؛ لأنه لمّا أصْبَحت أول محاولة لقراءة عدد صحيح (integer) تَحدُث قَبْل بداية حَلْقة التَكْرار (loop)، كان لابُدّ لمَتْن الحَلْقة من أن يبدأ أولًا بمُعالجة ذلك العدد. ثُمَّ بنهاية المَتْن، سيُحاول الحاسوب قراءة عدد صحيح جديد، ليَقفِز بَعْدها عائدًا لبداية الحَلْقة ليَختبِر العدد الجديد المَقروء للتو. عندما يَقرأ الحاسوب قيمة بَيَان النهاية (sentinel value)، ستَتوقَف الحَلْقة، ومِنْ ثَمَّ لن تُعالَج تلك القيمة، كما أنها لن تُضاف إلى حاصل المجموع <code>sum</code>، أو هذه هى الطريقة التي ينبغي أن تَعمَل بها الخوارزمية على الأقل؛ لأن قيمة بَيَان النهاية ليست جزءً من البيانات الفعليَّة كما ذَكَرنا مُسْبَّقًا.
</p>

<p>
	لا تَعمَل الخوارزمية الأصلية طِبقًا لذلك بطريقة صحيحة -بفَرْض إِمكانية تَّنْفيذها بدون إِجراء التهيئة المبدئية (priming) بطريقة ما-؛ لأنها ستَحسِب حاصل مجموع جميع الأعداد الصحيحة وكذلك عَدَدها (count) بما يتَضمَّن قيمة بَيَان النهاية (sentinel value). لمّا كانت تلك القيمة -المُتفق عليها- تُساوي الصفر، فإن حاصل المجموع سيظِلّ لحسن الحظ صحيحًا، ولكن في المقابل سيكون عَدَدها (count) خطأ بفارق واحد. يُطلَق على الأخطاء المُشابهة اسم الأخطاء بفارق الواحد (off-by-one errors)، وهي واحدة من أكثر الأخطاء شيوعًا. اِتضح أن العَدّ أصعب مما قد يبدو عليه.
</p>

<p>
	سنُحوِّل الآن الخورازمية إلى برنامج كامل، نُلاحِظ أولًا أنه لا يُمكِن اِستخدَام التَعْليمَة <code>average = sum/count;‎</code> لحساب قيمة المتوسط (average)؛ لأنه لمّا كانت قيمة كُلًا من المُتَغيِّرين <code>sum</code> و <code>count</code> من النوع العددي الصحيح <code>int</code>، فإن حاصل قِسمة الأول على الثاني <code>sum/count</code> ستكون أيضًا من النوع العددي الصحيح <code>int</code>، في حين ينبغي للمتوسط أن يكون عددًا حقيقيًا (real number). لقد واجهنا هذه المشكلة مِن قَبْل، ويَتلخَّص حَلّها بضرورة تَحْوِيل واحد من القيمتين إلى النوع <code>double</code>؛ وذلك لإجبار الحاسوب على حِسَاب قيمة حاصل القِسمة (quotient) كعَدَد حقيقي (real number). يُمكِن القيام بذلك عن طريق إجراء عملية التَحْوِيل بين الأنواع (type-casting) على أحد المُتَغيِّرين على الأقل، بحيث يُحوَّل إلى النوع <code>double</code> عن طريق اِستخدَام <code>‎(‎‎double)sum‎</code>. ولهذا يَحسِب البرنامج قيمة المتوسط باستخدام التعبير <code>average = ((double)sum) / count;‎</code>. يَتوفَّر حلّ آخر، وهو التَّصْريح (declaration) عن المُتَغيِّر <code>sum</code> بحيث يكون أساسًا من النوع <code>double</code>.
</p>

<p>
	حُلَّت مشكلة آخرى بالبرنامج التالي، وهي أنه في حالة إِدْخال المُستخدِم القيمة صفر كأول قيمة مُدْخَل، فلن تتوفَّر أيّ بيانات للمُعالجة، ولهذا يُمكننا اختبار حُدُوث تلك الحالة بفَحْص ما إذا كانت قيمة المُتَغيِّر <code>count</code> ما تزال مُساوية للصفر حتى بَعْد انتهاء حَلْقة التَكْرار <code>while</code>. قد تبدو هذه المشكلة ثانوية، ولكن لابُدّ أن يُغطي أيّ مبرمج مُنتبِه جميع الحالات المُمكنة.
</p>

<p>
	انظر شيفرة البرنامج بالكامل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_13" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ComputeAverage</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">int</span><span class="pln"> inputNumber</span><span class="pun">;</span><span class="pln"> </span><span class="com">// إحدى القيم المدخلة من قبل المستخدم</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> sum</span><span class="pun">;</span><span class="pln"> </span><span class="com">// حاصل مجموع الأعداد الصحيحة الموجبة</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">  </span><span class="com">// عدد الأعداد الصحيحة</span><span class="pln">
        </span><span class="kwd">double</span><span class="pln"> average</span><span class="pun">;</span><span class="pln"> </span><span class="com">// قيمة متوسط الأعداد الصحيحة الموجبة</span><span class="pln">

        </span><span class="com">// هيئ قيمة كلا من متغير المجموع والعداد</span><span class="pln">
        sum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

        </span><span class="com">// اقرأ مدخل من المستخدم لمعالجته</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter your first positive integer: "</span><span class="pun">);</span><span class="pln">
        inputNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">

        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputNumber </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="com">// أضف قيمة المتغير للمجموع الحالي</span><span class="pln">
            sum </span><span class="pun">+=</span><span class="pln"> inputNumber</span><span class="pun">;</span><span class="pln">   
            </span><span class="com">// أزد قيمة العداد بمقدار الواحد</span><span class="pln">
            count</span><span class="pun">++;</span><span class="pln">              
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter your next positive integer, or 0 to end: "</span><span class="pun">);</span><span class="pln">
            inputNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="com">// اعرض النتائج </span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">count </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You didn't enter any data!"</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            average </span><span class="pun">=</span><span class="pln"> </span><span class="pun">((</span><span class="kwd">double</span><span class="pun">)</span><span class="pln">sum</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"You entered "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> count </span><span class="pun">+</span><span class="pln"> </span><span class="str">" positive integers."</span><span class="pun">);</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"Their average is %1.3f.\n"</span><span class="pun">,</span><span class="pln"> average</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية البرنامج main</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف ComputeAverage</span></pre>

<h3>
	تعليمة <code>do..while</code>
</h3>

<p>
	تَفحْص تَعْليمَة حَلْقة التَكْرار <code>while</code> الشَّرْط الاستمراري لحَلْقة التَكْرار (continuation condition) ببداية الحَلْقة، ولكن أحيانًا ما يكون من الأنسب فَحْصه بنهاية الحَلْقة لا بدايتها، وهذا في الواقع ما تُوفِّره تَعْليمَة <code>do..while</code>. تَتشابه صياغة (syntax) تَعْليمَة الحَلْقة <code>do..while</code> مع تَعْليمَة <code>while</code> تمامًا باستثناء بعض التَغْيِيرات الطفيفة، حيث تُنْقَل كلمة <code>while</code> مصحوبة مع الشَّرْط إلى نهاية الحَلْقة، في حين تُضاف كلمة <code>do</code> في بداية الحَلْقة بدلًا منها. تُكتَب تَعْليمَة حَلْقة التَكْرار <code>do..while</code> بالصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_15" style="">
<span class="kwd">do</span><span class="pln">
    </span><span class="str">&lt;statement&gt;</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	إذا كانت التعليمة <strong><statement></statement></strong> كُتلَة (block) بذاتها، تُصاغ التَعْليمَة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_17" style="">
<span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">&lt;statements&gt;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	لاحِظ وجود الفاصلة المَنقوطة (semicolon) <code>;</code> بنهاية التَعْليمَة <code>do..while</code>. تُعدّ هذه الفاصلة جزءً أساسيًا من التَعْليمَة <code>do..while</code>، مثلما تُعدّ الفاصلة بنهاية أي تَعْليمَة أخرى -كالإِسْناد (assignment) أو التَّصْريح (declaration)- جزءً أساسيًا منها. ولهذا سيؤدي حَذْف الفاصلة المنقوطة <code>;</code>، في هذه الحالة، إلى التَسبُّب بحُدوث خطأ في بناء الجملة (syntax error). ينبغي عمومًا أن تنتهي أيّ تَعْليمَة برمجية -بلغة الجافا <code>Java</code>- إِمّا بفاصلة منقوطة <code>;</code> أو بقوس مُغلِق <code>{</code>.
</p>

<p>
	عندما يُنفَّذ الحاسوب تَعْليمَة حَلْقة التَكْرار <code>do..while</code>، فإنه يبدأ أولًا بتَّنْفيذ مَتْنها (loop body)-التَعْليمَة أو مجموعة التَعْليمَات بداخل الحَلْقة-، ثم يَحسِب قيمة التعبير المنطقي (boolean expression)، فإذا كانت مُساوية للقيمة المنطقية <code>true</code>، فإنه يَقفِز عَائدًا إلى بداية الحَلْقة ويُعيد تَّنْفيذ مَتْنها، لتستمر العملية بَعْدها بنفس الطريقة. أما إذا كانت قيمة التعبير المنطقي مُساوية للقيمة المنطقية <code>false</code>، فإنه يَتوقَف عن تَّنْفيذ الحَلْقة، وينتقل إلى الجزء التالي من الشيفرة. لاحظ أنه لمّا كان شَّرْط الحَلْقة لا يُفحْص إلا بنهاية الحَلْقة، فإن مَتْن حَلْقة التَكْرار <code>do..while</code> دائمًا ما يُنفَّذ مرة واحدة على الأقل.
</p>

<p>
	على سبيل المثال، اُنظر الشيفرة الوهمية (pseudocode) التالية لبرنامج لعبة. ستجد أن استخدام تَعْليمَة الحَلْقة <code>do..while</code> أكثر مُلائمة في هذه الحالة؛ لأنها ستَضمَن أن المُستخدِم قد لعِبَ مباراة واحدة على الأقل. علاوة على ذلك، فإن شَّرْط حَلْقة التَكْرار بالأسفل لن يكون له أيّ مَعنى في حالة تَّنْفيذه في بداية الحَلْقة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_19" style="">
<span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="com">// العب مباراة</span><span class="pln">
   </span><span class="typ">Play</span><span class="pln"> a </span><span class="typ">Game</span><span class="pln">
   </span><span class="com">// اسأل المستخدم إذا ما كان يريد اللعب مرة آخرى</span><span class="pln">
   </span><span class="typ">Ask</span><span class="pln"> user </span><span class="kwd">if</span><span class="pln"> he wants to play another game
   </span><span class="com">// اقرأ رد المستخدم</span><span class="pln">
   </span><span class="typ">Read</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s response
</span><span class="com">//  أعد التكرار طالما كان رد المستخدم هو نعم</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> the user</span><span class="str">'s response is yes );</span></pre>

<p>
	سنُحوِّل الآن هذه الشيفرة الوهمية إلى لغة الجافا. بدايةً ولكي نتجنب الخَوْض في تفاصيل ليست ذا أهمية، سنفترض أن لدينا صَنْف (class) يَحمِل اسم <code>Checkers</code>. أحد أعضاء (member) هذا الصَنْف هو البرنامج الفرعي الساكن (static subroutine)‏ <code>playGame()‎</code>. يُغلِّف هذا البرنامج الفرعي التفاصيل الخاصة باللعبة، ويُمثِل استدعائه إجراء مباراة دَّامَا (checkers) واحدة مع المُستخدِم. يُمكننا الآن اِستخدَام تَعْليمَة استدعاء البرنامج الفرعي (subroutine call) الساكن <code>Checkers.playGame();‎</code> كبديل عن سَطْر الشيفرة "العب مباراة".
</p>

<p>
	سنَستخدِم الصنف <code>TextIO</code> لتَلَقِّي رد المُستخدِم على سؤال من النوع نعم أم لا؛ حيث يُوفِّر هذا النوع الدالة‏ (function) <code>‏TextIO.getlnBoolean()‎</code>، والتي تَسمَح للمُستخدِم بإِدْخال إحدى القيمتين "Yes/No" ضِمْن عدة ردود أُخرى صالحة، بحيث يؤول الرد "Yes" إلى القيمة المنطقية <code>true</code>، بينما يؤول الرد "No" إلى القيمة المنطقية <code>false</code>. سنحتاج الآن إلى مُتَغيِّر لتخزين رد المُستخدِم، والذي سيكون بطبيعة الحال من النوع المنطقي (boolean). يُمكن كتابة الخوارزمية كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_21" style="">
<span class="com">// ‫تساوي True في حالة رغب المستخدم باللعب مجددًا</span><span class="pln">
boolean wantsToContinue</span><span class="pun">;</span><span class="pln">  
</span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="typ">Checkers</span><span class="pun">.</span><span class="pln">playGame</span><span class="pun">();</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Do you want to play again? "</span><span class="pun">);</span><span class="pln">
   wantsToContinue </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnBoolean</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">wantsToContinue </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span></pre>

<p>
	وفقًا لشَّرْط حَلْقة التَكْرار بالأعلى، فإنه عندما تَتَساوى قيمة المُتَغيِّر المنطقي <code>wantsToContinue</code> مع القيمة المنطقية <code>false</code>، سيكون ذلك إشارة (signal) إلى ضرورة تَوقُف حَلْقة التَكْرار. يُطلَق عادةً على المُتَغيِّرات المنطقية (boolean variables) المُستخدَمة بهذه الطريقة اسم راية (flag) أو مُتَغيِّر راية -هي متغيرات تُضبَط (set) بمكان ما بالشيفرة لتُفحَص قيمتها بمكان آخر-.
</p>

<p>
	بالمناسبة، عادةً ما يَسخَر بعض المبرمجين -ربما قد يَصفهم البعض بالمُتَحذلِقين- من شَّرْط حَلْقة التَكْرار <code>while (wantsToContinue == true)‎</code>؛ وذلك لأنه مُكافئ تمامًا للشَّرْط <code>while (wantsToContinue)</code>‎؛ فاختبار ما إذا كان التعبير <code>wantsToContinue == true</code> يُعيد القيمة المنطقية <code>true</code> لا يَختلف نهائيًا عن اختبار ما إذا كان المُتَغيِّر <code>wantsToContinue</code> يَحمِل القيمة <code>true</code> ويُعيدها. بالمثل، -وبفَرْض أن لدينا مُتَغيِّر اسمه <code>flag</code> من النوع المنطقي (boolean variable)- يُكافئ التعبير <code>flag == false</code>، والذي يُعدّ أقل فَجاجة من التعبير السابق، تمامًا التعبير <code>‎!flag‎</code>، حيث الحرف <code>!</code> هو عَامِل النفي المنطقي (negation operator). يُفضَّل عمومًا كتابة <code>while (!flag)‎</code> بدلًا من <code>while (flag == false)‎</code>، وبالمثل، كتابة <code>if (!flag)‎</code> بدلًا من <code>if (flag == false)‎</code>.
</p>

<p>
	على الرغم من أن اِستخدَام تَعْليمَة حَلْقة التَكْرار <code>do..while</code> أحيانًا ما يكون أكثر ملائمة في بعض المسائل، فعمومًا لا يَجعل وجود نوعين مختلفين من تَعْليمَة الحَلْقة (loops) لغة البرمجة أكثر قوة؛ فبالنهاية، أي مشكلة تُحلّ بإحداهما، ستجد أنه من الممكن حلّها بالآخرى. في الواقع، بفرض أن العبارة <strong><dosomething></dosomething></strong> تُمثل أي كُتلَة شيفرة، فإن التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_23" style="">
<span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">&lt;doSomething&gt;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	يُكافئ تمامًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_25" style="">
<span class="str">&lt;doSomething&gt;</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">&lt;doSomething&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بالمثل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_27" style="">
<span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">&lt;doSomething&gt;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span></pre>

<p>
	يُكافئ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_29" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="str">&lt;doSomething&gt;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">-</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بدون أي تَغْيِير بمَقصِد البرنامج نهائيًا.
</p>

<h3>
	تعليمتي <code>break</code> و <code>continue</code>
</h3>

<p>
	تَسمَح لك صيغتي حَلْقتي التَكْرار <code>while</code> و <code>do..while</code> باختبار الشَّرْط الاستمراري (continuation condition) إِمّا ببداية الحَلْقة أو بنهايتها على الترتيب. ولكن أحيانًا سترغب في إجراء عملية اختبار شَّرْط أثناء تَّنْفيذ الحَلْقة، أيّ داخل مَتْن الحَلْقة نفسها، أو حتى قد ترغب بإجراء أكثر من عملية اختبار بأماكن مختلفة داخل نفس الحَلْقة. تُستخدَم تَعْليمَة <code>break</code> بلغة الجافا لإيقاف تَّنْفيذ أيّ حَلْقة تَكْرار (loop)، والخروج منها، وذلك بمجرد استدعائها بأيّ مكان داخل الحَلْقة. تُكتَب كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_31" style="">
<span class="kwd">break</span><span class="pun">;</span></pre>

<p>
	عندما يُنفِّذ الحاسوب تَعْليمَة <code>break</code> داخل حَلْقة (loop)، فإنه سيَقفِز مُباشرةً خارج الحَلْقة، ويُنفِّذ الشيفرة التالية بالبرنامج والموجودة أسفل الحَلْقة. انظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_33" style="">
<span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="com">// يبدو وكأنها ستنفذ بشكل لا نهائي</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter a positive number: "</span><span class="pun">);</span><span class="pln">
    N </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">
    </span><span class="com">// إما أن تكون قيمة المدخل سليمة أو اقفز خارج الحلقة</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Your answer must be &gt; 0."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// ‫اكمل هنا بعد break</span></pre>

<p>
	في المثال بالأعلى، إذا أَدْخَل المُستخدِم عدد أكبر من الصفر، سيتحقَّق الشَّرْط، وستُنفَّذ تَعْليمَة <code>break</code>، ولهذا سيَقفِز الحاسوب مباشرة خارج الحَلْقة إلى ما بَعْدها. في المقابل، إذا لم يتحقَّق الشَّرْط، ستُطبَع السِلسِلة النصية "Your answer must be &gt; 0"، ثم سيَقفِز الحاسوب عَائدًا إلى بداية الحَلْقة ليَقرأ مُدْخَل جديد.
</p>

<p>
	قد يبدو السَطْر الأول من الشيفرة بالأعلى <code>while (true)‎</code> غَيْر مألوف نوعًا ما، ولكنه في الواقع سليم تمامًا. يُسمَح عمومًا لأيّ تعبير منطقي (boolean-valued expression) بأن يكون شَّرْطًا لحَلْقة التَكْرار، أيّ لابُدّ فقط أن تؤول قيمته النهائية إلى قيمة منطقية؛ ليَفحْصها الحاسوب لمعرفة ما إذا كانت مُساوية للقيمة <code>true</code> أم للقيمة <code>false</code>. تُعدّ القيمة المُجرَّدة (literal)‏ <code>true</code> تعبيرًا منطقيًا، والذي يؤول دائمًا إلى القيمة المنطقية <code>true</code>، ولذلك يُمكِن اِستخدَامها كشَّرْط للحَلْقة. يُستخدَم الشَّرْط <code>while (true)‎</code> لكتابة حَلْقة لا نهائية (infinite loop) أو حَلْقة يُفْترَض الخروج منها باِستخدَام تَعْليمَة <code>break</code>.
</p>

<p>
	يُسمَح باِستخدَام حَلْقات التَكْرار المُتداخِلة (nested loops)، بمَعنى وجود تَعْليمَة حَلْقة تَكْرار داخل أُخرى، ولذلك لابُدّ لنا من فهم طريقة عَمَل تَعْليمَة <code>break</code> ضِمْن هذا السياق. كقاعدة عامة، تُوقِف تَعْليمَة <code>break</code> حَلْقة التَكْرار الأقرب لها فقط، بمَعنى أنها إذا اُستخدِمت بداخل الحَلْقة الداخلية (inner loop)، فإنها ستُوقِف فقط تلك الحَلْقة، لا الحَلْقة الخارجية (outer loop) التي تَشَمَلها. أما إذا أردت إيقاف تَّنْفيذ الحلقة الخارجية، يُمكِنك اِستخدَام ما يُعرَف باسم تَعْليمَة <code>break</code> المُعنوَنة ‏(labeled break).
</p>

<p>
	تَسمَح تَعْليمَة <code>break</code> المُعنوَنة بتحديد صريح للحَلْقة المطلوب الخروج منها. اِستخدَام هذه التَعْليمَة المُعنوَنة غَيْر شائع، ولذلك سنمر عليها سريعًا. تَعمَل العناوين (labels) كالتالي: يُمكِنك ببساطة عَنوَنة أيّ حَلْقة تَكْرار بوَضْع مُعرَّف (identifier) مَتبوع بنقطتان رأسيتان <code>:</code> بمقدمة الحَلْقة. فمثلًا، يمكن عَنوَنة حَلْقة تَكْرار <code>while</code> باِستخدَام <code>mainloop: while...‎</code>. تستطيع الآن اِستخدَام تَعْليمَة <code>break</code> المُعنوَنة بأيّ مكان داخل هذه الحَلْقة عن طريق اِستخدَام الصيغة <code>break mainloop;‎</code>، وذلك بهدف الخروج من هذه الحَلْقة تحديدًا.
</p>

<p>
	على سبيل المثال، تَفحْص الشيفرة بالأسفل ما إذا كانت السِلسِلتين النصيتين <code>s1</code> و <code>s2</code> تحتويان على حرف مُشتَرَك. في حالة تَحقُّق الشَّرْط، ستُسْنَد القيمة المنطقية <code>false</code> إلى مُتَغيِّر الراية <code>nothingInCommon</code>، ثُمَّ تُسْتَدعى تَعْليمَة <code>break</code> المُعنوَنة لإيقاف المعالجة عند تلك النقطة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9877_35" style="">
<span class="pln">boolean nothingInCommon</span><span class="pun">;</span><span class="pln">
</span><span class="com">// افترض أن السلسلتين لا يشتركان بأي حرف</span><span class="pln">
nothingInCommon </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">  
</span><span class="com">// متغيرات حلقتي التكرار والتي ستأخذ قيم حروف السلسلتين</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln">j</span><span class="pun">;</span><span class="pln">  

i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
bigloop</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> s1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j </span><span class="pun">&lt;</span><span class="pln"> s2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// إذا كان هناك حرفًا مشتركا</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">s1</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> s2</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">j</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
            </span><span class="com">// ‫اضبط قيمة المتغير إلى القيمة false</span><span class="pln">
            nothingInCommon </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">  
            </span><span class="com">// اخرج من الحلقتين</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln"> bigloop</span><span class="pun">;</span><span class="pln">  
        </span><span class="pun">}</span><span class="pln">
        j</span><span class="pun">++;</span><span class="pln">  </span><span class="com">// Go on to the next char in s2.</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    i</span><span class="pun">++;</span><span class="pln">  </span><span class="com">//Go on to the next char in s1.</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُعدّ تَعْليمَة <code>continue</code> مرتبطة نوعًا ما بتَعْليمَة <code>break</code>، لكنها أقل اِستخدَامًا منها. تتَخَطَّى تَعْليمَة <code>continue</code> الجزء المُتبقي من التَكْرار الحالي (current iteration) فقط، أي أنها لا تتَسبَّب بالقفز خارج الحَلْقة تمامًا إلى ما بَعْدها كتَعْليمَة <code>break</code>؛ وإنما تَقفِز عائدة إلى بداية نفس الحَلْقة لتَّنْفيذ التَكْرار التالي (next iteration) -بالطبع إذا كان الشَّرْط الاستمراري (continuation condition) لحَلْقة التَكْرار ما زال مُتحقِّقًا. عندما تُستخدَم تَعْليمَة <code>continue</code> داخل حَلْقة مُتداخِلة (nested loop)، فإنها، مثل تَعْليمَة <code>break</code>، تُجرِي هذه العملية على حَلْقة التَكْرار الأقرب لها فقط، أيّ الحَلْقة الداخلية (inner nested loop). وبالمثل، تتوفَّر تَعْليمَة <code>continue</code> المُعنوَنة ‏(labeled continue)، وذلك لتخصيص حَلْقة التَكْرار المراد إجراء عملية <code>continue</code> عليها.
</p>

<p>
	يمكن اِستخدَام تَعْليمَتي <code>break</code> و <code>continue</code> داخل جميع حَلْقات التَكْرار مثل <code>while</code>، و <code>do..while</code>، و <code>for</code>. سنتحدث عن الأخيرة تفصيليًا بالقسم التالي. يُمكن أيضًا اِستخدَام تَعْليمَة <code>break</code> للخروج من تَعْليمَة <code>switch</code>، وهو ما سنتناوله بالقسم ٣.٦. يُسمَح أيضًا باِستخدَامها داخل تَعْليمَة التَفْرِيع الشَّرْطيّة <code>if</code> إذا كانت تَعْليمَة التَفْرِيع موجودة إِمّا ضِمْن حَلْقة تَكْراريّة أو ضِمْن تَعْليمَة <code>switch</code>، ولكن عندها لا يكون المقصود هو الخروج من تَعْليمَة التَفْرِيع <code>if</code>، وإنما الخروج من التَعْليمَة التي تَشتَملها، أي من تَعْليمَة الحَلْقة أو من تَعْليمَة <code>switch</code>. بالمثل، يُمكِن اِستخدَام تَعْليمَة <code>continue</code> داخل تَعْليمَة <code>if</code> بنفس الطريقة، وتتبِّع نفس القواعد بالأعلى.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s3.html" rel="external nofollow">Section 3: The while and do..while Statements</a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1064</guid><pubDate>Thu, 12 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x637;&#x648;&#x64A;&#x631; &#x627;&#x644;&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1063/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/15.png.c1755ecfff6180d64d36f2e8d5412877.png" /></p>
<p>
	قد تَكُون البرمجة (programming) صعبة نوعًا ما، وذلك كغَيْرها من الأنشطة المُفيدة والجديرة بالاهتمام، ومع ذلك، فهي عادة ما تَكُون مُجْزيّة ومُمتعة. عند كتابة برنامج (program)، لابُدّ أن تُخبِر الحاسوب بكُل تَفصيلة صغيرة يَنبغي له تَّنْفيذها، وبصورة صحيحة تمامًا؛ وذلك لأنه سيَتَّبِع البرنامج كما هو مَكتوب تمامًا وبطريقة عمياء. إذن، كيف تُكتَب البرامج غَيْر البسيطة؟ في الواقع، إنه ليس أمرًا غامضًا، فالأمر بِرُمَّته يَعتمِد فقط على تَعَلُّم طريقة التفكير الصحيحة.
</p>

<p>
	يُعدّ البرنامج (program) تعبيرًا عن فكرة (idea)، حيث يبدأ المُبرمج بفكرة عامة عن مُهِمّة (task) معينة يُريد من الحاسوب تَّنْفيذها، وعادةً ما يكون المُبرمج على عِلم بكيفية تَّنْفيذ تلك المُهِمّة يدويًا، أو لديه تَصَوُّر عام على الأقل. تتمحور المشكلة حول طريقة تَحْوِيل هذا التَصَوُّر العام إلى إِجراء (procedure)، واضح، ومُكتمِل، ومُحدَّد الخُطوات لتََّنْفيذ تلك المُهِمّة. يُسمَى مثل هذا الإِجراء باسم "الخوارزمية (algorithm)"، والتي هي إِجراء واضح، ومُحدَّد الخُطوات، والذي لابُدّ أن ينتهي دائمًا بَعْد عَدَد مُتناهي (finite number) من الخُطوات؛ فنحن لا نُريد عدّ الإِجراءات التي قد تَستمِر للأبد. لاحِظ أن الخوارزمية (algorithm) تَختلف عن البرنامج (program)، فالبرنامج يُكتَب بلغة برمجية معينة، أما الخوارزمية، فتُكتَب بأيّ لغة بما فيها الإنجليزية، وهي أَشْبَه بالفكرة وراء البرنامج، ويُقصَد بالفكرة هنا مجموعة الخُطوات المطلوب القيام بها حتى يَتمّ تَّنْفيذ المُهِمّة، وليس مُجرَّد مُلخَّص لما ينبغي للمُهِمّة إِنجازه في النهاية. عند وصف الخوارزمية، ليس من الضروري أن تَكُون الخُطوات مُفَصَّلة، وذلك طالما كانت واضحة بما فيه الكفاية لبَيَان أن تَّنْفيذها سوف يُنجِز المُهِمّة المطلوبة، ولكن بالطبع لا يُمكِن التعبير عنها كبرنامج (program) فِعليّ بدون مَلْئ جميع تلك التفاصيل.
</p>

<p>
	من أين تأتي <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">الخوارزميات</a>؟ ينبغي عادةً تطويرها، وهو ما يَتطلَّب كثيرًا من التفكير والعمل الجاد. يُمكِن القول أن عملية تطوير الخوارزميات (algorithm development) هي مهارة تُكتسَب مع المُمارسة المستمرة، ولكن، مع ذلك، تَتَوفَّر بعض التقنيات (techniques) والقواعد الإرشادية (guidelines) التي يُمكِنها مُساعدتك. سنتناول في هذا القسم بَعضًا منها، وبالأخص ما يَتعلَّق بالبرمجة "في نطاق ضيق"، كما سنعود للحديث عن نفس هذا الموضوع أكثر من مرة بالفصول القادمة.
</p>

<h2>
	الشيفرة الوهمية والتصميم المتدرج
</h2>

<p>
	عند البرمجة "في نطاق ضيق"، فأنت مُقيَّد نوعًا ما باِستخدَام عَدَد قليل من الأوامر، وهي كالتالي: المُتَغيِّرات (variables)، وتَعْليمَات الإِسْناد (assignment statements)، والبرامج (routines) الخاصة بعَمليتي الإِدْخال (input) والإِخراج (output). قد يَتوفَّر لك أيضًا اِستخدَام بعض البرامج الفرعية (subroutines)، والكائنات (objects)، أو رُبما حتى بعض اللَبِنات الأساسية الآخرى، ولكن بشَّرْط أن تَكُون قد كُتِبَت مُسْبَّقًا إِمّا بواسطتك أو بواسطة شخص آخر (لاحِظ أن برامج الإِدْخال والإِخراج تَقع ضِمْن هذا التصنيف). والآن، تَستطِيع بناء مُتتالية مِنْ تلك التَعْليمَات البسيطة، أو ربما قد تَدمجهم دِاخل بُنَى تحكُّم (control structures) أكثر تعقيدًا، مثل تَعْليمَة حَلْقة التَكْرار (loops)‫ <code>while</code>، وتَعْليمَة التَفْرِيع الشَّرْطيّة <code>if</code>.
</p>

<p>
	لنفْترِض أننا نريد <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-r1956/" rel="">برمجة الحاسوب</a> ليُنفِّذ مُهِمّة (task) معينة، يُمكِننا البدء بكتابة تَوصِيف (description/specification) مَبدئي لتلك المُهِمّة، بحيث يُلخِّص وظيفة الخوارزمية (algorithm) المطلوب تَطْويرها، ثُمَّ نُضيف مزيدًا من الخطوات والتفاصيل إلى ذلك التَوصِيف تدريجيًا، وعبر سِلسِلة من التصميمات المُحسَّنة، إلى أن نَصِل إلى الخوارزمية الكاملة التي يُمكِن ترجمتها مباشرة إلى لغة برمجية. تُكتَب عادة تلك التَوصِيفات باِستخدَام ما يُعرَف باسم الشيفرة الوهمية (pseudocode)، وهي مجموعة من التَعْليمَات العَاميَّة، التي تُحاكِي بِنْية اللغات البرمجية، بصورة مُبسَّطة، وبدون قواعد الصيغة (syntax) الصارمة المُعتادة بالشيفرة الفعليّة. يُطلَق على هذا الأسلوب من كتابة البرامج اسم التصميم المُتدرج (stepwise refinement)، ويُصنَّف ضِمْن استراتيجيات التصميم من أعلى لأسفل (top-down design).
</p>

<p>
	لنفْحَص كيفية تَطبيق التصميم المتدرج لكتابة إحدى البرامج التي قد تَعرَّضنا لها خلال القسم السابق. يَحسِب هذا البرنامج قيمة الاستثمار خلال خمسة أعوام. يُمكِن تَوصِيف مُهِمّة البرنامج بالعبارة التالية: "اِحسب قيمة الاستثمار واطبعها لكل عام من الأعوام الخمسة التالية، بحيث تُحدَّد قيمة الاستثمار المبدئي وسعر الفائدة مِن قِبَل المُستخدِم". ربما نُفكر بكتابة الشيفرة الوهمية التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_6" style=""><span class="com">// اقرأ مدخل المستخدم</span><span class="pln">
</span><span class="typ">Get</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s input
</span><span class="com">// احسب قيمة الاستثمار بعد عام</span><span class="pln">
</span><span class="typ">Compute</span><span class="pln"> the value of the investment after </span><span class="lit">1</span><span class="pln"> year
</span><span class="com">// اطبع القيمة</span><span class="pln">
</span><span class="typ">Display</span><span class="pln"> the value
</span><span class="com">// احسب قيمة الاستثمار بعد عامين</span><span class="pln">
</span><span class="typ">Compute</span><span class="pln"> the value after </span><span class="lit">2</span><span class="pln"> years
</span><span class="com">// اطبع القيمة</span><span class="pln">
</span><span class="typ">Display</span><span class="pln"> the value
</span><span class="com">// احسب قيمة الاستثمار بعد ثلاث أعوام</span><span class="pln">
</span><span class="typ">Compute</span><span class="pln"> the value after </span><span class="lit">3</span><span class="pln"> years
</span><span class="com">// اطبع القيمة</span><span class="pln">
</span><span class="typ">Display</span><span class="pln"> the value
</span><span class="com">// احسب قيمة الاستثمار بعد أربع أعوام</span><span class="pln">
</span><span class="typ">Compute</span><span class="pln"> the value after </span><span class="lit">4</span><span class="pln"> years
</span><span class="com">// اطبع القيمة</span><span class="pln">
</span><span class="typ">Display</span><span class="pln"> the value
</span><span class="com">// احسب قيمة الاستثمار بعد خمس أعوام</span><span class="pln">
</span><span class="typ">Compute</span><span class="pln"> the value after </span><span class="lit">5</span><span class="pln"> years
</span><span class="com">// اطبع القيمة</span><span class="pln">
</span><span class="typ">Display</span><span class="pln"> the value</span></pre>

<p>
	على الرغم من أن الخوارزمية بالأعلى سليمة وستؤدي الغرض منها، لكنها مُكرَّرة، وهو ما يَعنِي ضرورة اِستخدَام حَلْقة تَكْرار (loop)؛ لأنها ستُمكِّننا من كتابة شيفرة مُعمَّمة أكثر وبعَدَد سطور أقل. يُقصَد بالتَعْميم (generalization) هنا أنه يُمكِن اِستخدَام نفس حَلْقة التَكْرار بغض النظر عن عدد الأعوام المطلوب مُعالجتها. والآن، سنُعيد كتابة مُتتالية الخطوات السابقة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_8" style=""><span class="com">// اقرأ مدخل المستخدم</span><span class="pln">
</span><span class="typ">Get</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s input
</span><span class="com">// طالما ما يزال هناك عدد من الأعوام للمعالجة</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> there are more years to process</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// احسب قيمة الاستثمار بعد العام التالي</span><span class="pln">
    </span><span class="typ">Compute</span><span class="pln"> the value after the next year
    </span><span class="com">// اطبع القيمة</span><span class="pln">
    </span><span class="typ">Display</span><span class="pln"> the value</span></pre>

<p>
	على الرغم من أن الخوارزمية (algorithm) بالأعلى سليمة، لكنها مُوجَزة، وربما مُبهَمة بشكل أكثر من اللازم. يَحتاج الحاسوب عمومًا إلى تَعْليمَات واضحة وصريحة، ولهذا سنحتاج، مثلًا، إلى شرح الخطوات: "اقرأ مُدْخَل المُستخدِم" و "احسب قيمة الاستثمار بَعْد العام التالي" و "ما يزال هناك عَدَد من الأعوام للمعالجة". فمثلًا، نستطيع إعادة تَوصِيف الخطوة "اِقْرأ مُدْخَل المُستخدِم" إلى التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_10" style=""><span class="com">// اسأل المستخدم عن قيمة الاستثمار المبدئي</span><span class="pln">
</span><span class="typ">Ask</span><span class="pln"> the user </span><span class="kwd">for</span><span class="pln"> the initial investment
</span><span class="com">// اقرأ مدخل المستخدم</span><span class="pln">
</span><span class="typ">Read</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s response
</span><span class="com">// اسأل المستخدم عن قيمة سعر الفائدة</span><span class="pln">
</span><span class="typ">Ask</span><span class="pln"> the user </span><span class="kwd">for</span><span class="pln"> the interest rate
</span><span class="com">// اقرأ مدخل المستخدم</span><span class="pln">
</span><span class="typ">Read</span><span class="pln"> the user</span><span class="str">'s response</span></pre>

<p>
	أمَا بخُصوص الخطوة "احسب قيمة الاستثمار بَعْد العام التالي"، فسنحتاج إلى معرفة طريقة حِسَابها (ينبغي أن تَطلُب في تلك الحالة مزيد من التوضيح من أستاذك أو مُديرك)، ولكن دَعْنَا الآن نفْترِض أن قيمة الاستثمار تُحسَب بإضافة قيمة فائدة معينة إلى قيمة الاستثمار السابقة، وبالتالي يُمكِننا إِعادة كتابة حَلْقة التَكْرار <code>while</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_12" style=""><span class="com">// طالما ما يزال هناك عدد من الأعوام للمعالجة</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> there are more years to process</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// احسب الفائدة</span><span class="pln">
    </span><span class="typ">Compute</span><span class="pln"> the interest
    </span><span class="com">// أضف الفائدة إلى قيمة الاستثمار</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> the interest to the value
    </span><span class="com">// اطبع القيمة</span><span class="pln">
    </span><span class="typ">Display</span><span class="pln"> the value</span></pre>

<p>
	نحتاج الآن إلى توضيح الاختبار الموجود بالخطوة "ما يزال هناك عَدَد من الأعوام للمعالجة"، وهو ما يُمكِن القيام به عن طريق عدّ الأعوام بأنفسنا، سنَستخدِم عَدَّادًا قيمته تُساوِي الصفر، ثم نُزيِد قيمة هذا العَدَّاد بمقدار الواحد بَعْد كل مرة نُعالِج فيها عامًا جديدًا، ونَتوقَف عندما تُصبِح قيمة العَدَّاد مُساوِية للعَدَد المطلوب من الأعوام. يُطلَق على ذلك عادةً اسم "حَلْقة العدّ (counting loop)"، وهي أحد الأنماط الشائعة، ولذلك تَوقَّع أن تَستخدِم شيئًا مُشابهًا بكثير من البرامج. تُصبِح الآن حَلْقة التَكْرار <code>while</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_14" style=""><span class="com">// ابدأ بعدد أعوام يساوي الصفر</span><span class="pln">
years </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="com">// طالما عدد الأعوام أقل من الخمسة</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> years </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// أزد عدد الأعوام بمقدار الواحد</span><span class="pln">
    years </span><span class="pun">=</span><span class="pln"> years </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="com">// احسب الفائدة</span><span class="pln">
    </span><span class="typ">Compute</span><span class="pln"> the interest
    </span><span class="com">// أضف الفائدة إلى تلك القيمة</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> the interest to the value
    </span><span class="com">// اطبع القيمة</span><span class="pln">
    </span><span class="typ">Display</span><span class="pln"> the value</span></pre>

<p>
	نَحتاج إلى أن نكون أكثر توضيحًا بخُصوص طريقة حِسَاب الفائدة، وسنفْترِض أنها تُساوِي حاصل ضرب سعر الفائدة بقيمة الاستثمار الحالية. نُضيِف هذا الإيضاح إلى ذلك الجزء من الخوارزمية المسئول عن قراءة مُدْخَلات المُستخدِم، وبهذا، نَحصُل على الخوارزمية الكاملة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_16" style=""><span class="com">// اسأل المستخدم عن قيمة الاستثمار المبدئي</span><span class="pln">
</span><span class="typ">Ask</span><span class="pln"> the user </span><span class="kwd">for</span><span class="pln"> the initial investment
</span><span class="com">// اقرأ مدخل المستخدم</span><span class="pln">
</span><span class="typ">Read</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s response
</span><span class="com">// اسأل المستخدم عن قيمة سعر الفائدة</span><span class="pln">
</span><span class="typ">Ask</span><span class="pln"> the user </span><span class="kwd">for</span><span class="pln"> the interest rate
</span><span class="com">// اقرأ مدخل المستخدم</span><span class="pln">
</span><span class="typ">Read</span><span class="pln"> the user</span><span class="str">'</span><span class="pln">s response
</span><span class="com">// ابدأ بعدد أعوام يساوي الصفر</span><span class="pln">
years </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="com">// طالما عدد الأعوام أقل من الخمسة</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> years </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// أزد عدد الأعوام بمقدار الواحد</span><span class="pln">
    years </span><span class="pun">=</span><span class="pln"> years </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="com">// احسب الفائدة بحيث تساوي حاصل ضرب القيمة مع سعر الفائدة</span><span class="pln">
    </span><span class="typ">Compute</span><span class="pln"> interest </span><span class="pun">=</span><span class="pln"> value </span><span class="pun">*</span><span class="pln"> interest rate
    </span><span class="com">// أضف الفائدة إلى تلك القيمة</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> the interest to the value
    </span><span class="com">// اطبع القيمة</span><span class="pln">
    </span><span class="typ">Display</span><span class="pln"> the value</span></pre>

<p>
	وَصلنا إلى النقطة التي يُمكِن معها الترجمة المُباشرة إلى لغة برمجة مناسبة، فقط نحتاج إلى اِختيار أسماء المُتَغيِّرات (variables)، وتَقْرير نص العبارات التي سنَطبَعها للمُستخدِم، وهكذا. نستطيع الآن كتابة الخوارزمية (algorithm) بلغة الجافا كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_18" style=""><span class="kwd">double</span><span class="pln"> principal</span><span class="pun">,</span><span class="pln"> rate</span><span class="pun">,</span><span class="pln"> interest</span><span class="pun">;</span><span class="pln">  </span><span class="com">// التصريح عن المتغيرات</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> years</span><span class="pun">;</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Type initial investment: "</span><span class="pun">);</span><span class="pln">
principal </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Type interest rate: "</span><span class="pun">);</span><span class="pln">
rate </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">
years </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">years </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   years </span><span class="pun">=</span><span class="pln"> years </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   interest </span><span class="pun">=</span><span class="pln"> principal </span><span class="pun">*</span><span class="pln"> rate</span><span class="pun">;</span><span class="pln">
   principal </span><span class="pun">=</span><span class="pln"> principal </span><span class="pun">+</span><span class="pln"> interest</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">principal</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ما زال أمامنا بعض التَحسِّينات الإضافية، مِن بينها تَضْمِين هذه الشيفرة داخل برنامج كامل، وإضافة التعليقات (comments)، وطِباعة المَزيد من المعلومات للمُستخدِم، ولكنه يظِلّ نفس البرنامج بالقسم السابق.
</p>

<p>
	في حين تَستخدِم خوارزمية الشيفرة الوهمية (pseudocode algorithm) المسافات البادئة (indentation) لتوضيح التَعْليمَات الواقعة ضِمْن حَلْقة التَكْرار (loop)، تُهمِل لغة الجافا هذه المسافات البادئة تمامًا، ولهذا أَضفنا قوسين معقوصين (curly brackets/braces) <code>{}</code> لتوضيح أيّ مجموعة تَعْليمَات (statements) تقع ضِمْن حَلْقة التَكْرار. إذا لم تَستخدِم هذه الأقواس بشيفرة الجافا، فإن الحاسوب سيفْترِض أن التَعْليمَة الوحيدة الواقعة ضِمْن حَلْقة التَكْرار هي <code>years = years + 1;‎</code>، أمَا بقية التَعْليمَات فسيُنفِّذها مرة واحدة فقط بَعْد انتهاء حَلْقة التَكْرار. للأسف، لا يُبلِّغ الحاسوب عن هذه النوعية من الأخطاء، بنفس الطريقة التي يُبلِّغ بها عن حُدوث خطأ في حالة عدم اِستخدَام القوسين الهلاليين (rounded brackets/parentheses) <code>()</code> حول <code>(years &lt; 5)</code>؛ وذلك لأن تلك الأقواس مطلوبة وِفقًا لصيغة (syntax) تَعْليمَة <code>while</code>، أمَا قوسيّ المعقوصين <code>{}</code>، فإنها مطلوبة فقط لأغراض دَلاليّة (semantics)، أيّ أغراض مُتعلِّقة بالمعنى. يَستطيع الحاسوب عمومًا تَمييز أخطاء بناء الجملة (syntax errors) فقط، لا الأخطاء الدَلاليّة (semantic errors).
</p>

<p>
	لاحِظ أن التَوصِيف الأصلي للمسألة التالي لم يَكُن مُكتملًا:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		"اِحسب قيمة الاستثمار واطبعها لكل عام من الأعوام الخمسة التالية، بحيث تُحدَّد قيمة الاستثمار المبدئي وسعر الفائدة مِن قِبَل المُستخدِم".
	</p>
</blockquote>

<p>
	ينبغي لك عمومًا، قَبْل بدء كتابة أيّ برنامج، أن تتأكد من أن لديك التَوصِيف الكامل لوظيفة البرنامج المطلوب كتابته، فلابُدّ أن تَعرِف المعلومات التي سيَقرأها البرنامج (input) وأيّ خَرْج (output) ينبغي أن يَطبعُه، وكذلك الحِسَابات التي ينبغي له القيام بها. ربما يُمكِننا إعادة تَوصِيف نفس البرنامج السابق بصورة أكثر معقولية كالتالي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		"اُكْتُب برنامجًا يَحسِب قيمة الاستثمار ويَطبَعها لكل عام من الأعوام الخمسة التالية، بحيث تُحدَّد قيمة الاستثمار المبدئي وسعر الفائدة مِن قِبَل المُستخدِم عند تَشْغِيل البرنامج. تُحسَب قيمة الفائدة من خلال حِسَاب حاصل ضرب قيمة الاستثمار الحالية في سعر الفائدة الثابت، وتُضَاف تلك الفائدة إلى قيمة الاستثمار كل عام".
	</p>
</blockquote>

<h2>
	مسألة متتالية "3N+1"
</h2>

<p>
	لنفْحَص مثالًا آخرًا لم نتَعرَّض له من قَبْل، السؤال هنا عبارة عن مَسألة رياضية مُجرَّدة، والتي يَعُدّها الكاتب تَحْدِيدًا واحدة مِن تمارينه البرمجية المُفضلة. سنبدأ هذه المرة، بعكس المثال السابق، بتَوصِيف كامل (specification) لمُهِمّة (task) البرنامج:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		"بفَرْض أن لديك عددًا صحيحًا موجبًا (positive integer)، وليَكُن <code>N</code>، اِحسب قيم مُتتالية الأعداد (sequence) ‫"3N+1"، والتي تبدأ من العَدَد <code>N</code>، وبحيث تُحسَب قيمة عنصر المُتتالية التالي وِفقًا للآتي: إذا كان <code>N</code> عَدَدًا زوجيًا، اِحسب حاصل قِسمته على العَدَد ٢، أمَا إذا كان فرديًا، فاِحسب حاصل ضربه في العَدَد ٣، ثُمَّ أَزِد قيمة حاصل الضرب بمقدار ١. اِستمر بحِسَاب قيم عناصر مُتتالية الأعداد بنفس الطريقة حتى تُصبِح قيمة <code>N</code> مُساوِية للعَدَد ١. على سبيل المثال، لمّا كانت قيمة <code>N</code> تُساوِي ٣، والتي هي عَدَد فردي، فإنها ضُرِبت في ٣ وأُزِيدَت نتيجة حاصل الضرب بمقدار ١، أيّ، <code>N = 3*3+1 = 10</code>. لمّا أصبحت قيمة <code>N</code> زوجية، فإنها قُسمت على ٢، أيّ، <code>N = 10/2 = 5</code>. نَستمر بحِسَاب قيم عناصر المُتتالية، ونَتوقَف عندما تُصبِح قيمة <code>N</code> مُساوِية للقيمة 1، لنَحصُل على مُتتالية الأعداد التالية: ٣، ١٠، ٥، ١٦، ٨، ٤، ٢، ١.
	</p>
</blockquote>

<p>
	اُكْتُب برنامجًا يَقرأ عَدَدًا صحيحًا موجبًا من المُستخدِم، ثُمَّ يَطبَع مُتتالية الأعداد "3N+1"، بحيث تبدأ من العَدَد المُدْخَل، كما يَنبغي للبرنامج أن يعدّ عَدَد عناصر المُتتالية ويَطبعها."
</p>

<p>
	اُنظر الخوارزمية المبدئية التالية، والتي تُوضِح فقط التَصَوُّر العام لمثل هذا البرنامج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_20" style=""><span class="com">// اقرأ عدد صحيح موجب من المستخدم</span><span class="pln">
</span><span class="typ">Get</span><span class="pln"> a positive integer N from the user</span><span class="pun">.</span><span class="pln">
</span><span class="com">// احسب قيمة كل عنصر بالمتتالية، واطبعه وعدّه</span><span class="pln">
</span><span class="typ">Compute</span><span class="pun">,</span><span class="pln"> print</span><span class="pun">,</span><span class="pln"> and count each number in the sequence</span><span class="pun">.</span><span class="pln">
</span><span class="com">// اطبع عدد عناصر المتتالية</span><span class="pln">
</span><span class="typ">Output</span><span class="pln"> the number of terms</span><span class="pun">.</span></pre>

<p>
	يَتضح لنا أن الخطوة الثانية تَحتوِي على المَضمون الفِعليّ للبرنامج، وبالطبع تحتاج إلى مزيد من الإيضاح.
</p>

<p>
	لمّا كنا نُريد الاستمرار بحِسَاب قيم عناصر المُتتالية حتى تُصبِح قيمة <code>N</code> الحالية مُساوِية للعَدَد ١، فإننا سنحتاج ببساطة إلى اِستخدَام حَلْقة تَكْرار (loop)، ولذلك دَعْنَا نُعيد صياغة نفس الجملة السابقة بحيث تَتوافق مع حَلْقة التَكْرار <code>while</code>. إننا في حاجة إلى مَعرِفة متى نَستمِر بتَّنْفيذ حَلْقة التَكْرار ومتى نُوقِّفها، في الواقع، سنستمر طالما كانت قيمة <code>N</code> الحالية لا تُساوِي ١، ولهذا يُمكِننا إعادة كتابة خوارزمية الشيفرة الوهمية (pseudocode algorithm) كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_22" style=""><span class="com">// اقرأ عدد صحيح موجب من المستخدم</span><span class="pln">
</span><span class="typ">Get</span><span class="pln"> a positive integer N from the user</span><span class="pun">;</span><span class="pln">
</span><span class="com">// ‫‫طالما كانت قيمة `N` الحالية لا تساوي 1</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> N is not </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// ‫احسب قيمة عنصر المتتالية التالي واسنده إلى N</span><span class="pln">
    </span><span class="typ">Compute</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> next term</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// ‫اطبع قيمة N</span><span class="pln">
    </span><span class="typ">Output</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// عدّ عنصر المتتالية</span><span class="pln">
    </span><span class="typ">Count</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> term</span><span class="pun">;</span><span class="pln">
</span><span class="com">// اطبع عدد عناصر المتتالية</span><span class="pln">
</span><span class="typ">Output</span><span class="pln"> the number of terms</span><span class="pun">;</span></pre>

<p>
	لمّا كان حِسَاب قيمة عنصر المُتتالية التالي يَعتمِد على ما إذا كانت قيمة <code>N</code> الحالية هي عَدَد زوجي (even) أم فردي (odd)، يَعنِي ذلك أن الحاسوب بحاجة إلى تَّنْفيذ حَدَثين مُختلفين لكل حالة، وهو ما يَعنِي أن اِستخدَام تَعْليمَة التَفْرِيع الشَّرْطيّة <code>if</code> بات ضروريًا؛ وذلك للاختيار ما بين تلك الحالتين، اُنظر الخوارزمية بَعْد التعديل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_24" style=""><span class="com">// اقرأ عدد صحيح موجب من المستخدم</span><span class="pln">
</span><span class="typ">Get</span><span class="pln"> a positive integer N from the user</span><span class="pun">;</span><span class="pln">
</span><span class="com">// ‫‫طالما كانت قيمة `N` الحالية لا تساوي 1</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> N is not </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// ‫إذا كان N عددًا زوجيًا</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> N is even</span><span class="pun">:</span><span class="pln">
        </span><span class="com">// ‫احسب قيمة العنصر التالي وأسنده إلى N</span><span class="pln">
       </span><span class="typ">Compute</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> N</span><span class="pun">/</span><span class="lit">2</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// ‫إذا كان N عددًا فرديًا</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
        </span><span class="com">// ‫احسب قيمة العنصر التالي وأسنده إلى N</span><span class="pln">
       </span><span class="typ">Compute</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> N </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// ‫اطبع قيمة N</span><span class="pln">
    </span><span class="typ">Output</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// عدّ عنصر المتتالية</span><span class="pln">
    </span><span class="typ">Count</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> term</span><span class="pun">;</span><span class="pln">
</span><span class="com">// اطبع عدد عناصر المتتالية</span><span class="pln">
</span><span class="typ">Output</span><span class="pln"> the number of terms</span><span class="pun">;</span></pre>

<p>
	انتهينا تقريبًا، يَتبقَّى فقط العدّ (counting)؛ وذلك لطباعة عَدَد عناصر المُتتالية. يَعنِي العدّ ببساطة أن تبدأ بالقيمة صفر، ثم تُضيف المقدار واحد في كل مرة يَكُون لديك فيها ما تعدّه، ولهذا نحتاج إلى مُتَغيِّر (variable) للقيام بالعدّ، يُعرَف باسم العَدَّاد (counter). يَنبغي ضَبْط قيمة ذلك المُتَغيِّر إلى القيمة صفر قَبْل بداية الحَلْقة (loop)، بحيث تَزداد (increment) تلك القيمة أثناء تَّنْفيذ الحَلْقة. (يُعدّ ذلك أحد الأنماط الشائعة [common pattern]، ولذلك تَوقَّع أن تراه بكثير من البرامج). تُصبِح الخوارزمية، بَعْد إضافة العَدَّاد (counter)، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_26" style=""><span class="com">// اقرأ عدد صحيح موجب من المستخدم</span><span class="pln">
</span><span class="typ">Get</span><span class="pln"> a positive integer N from the user</span><span class="pun">;</span><span class="pln">
</span><span class="com">// اضبط قيمة العداد إلى القيمة صفر</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">// ‫‫طالما كانت قيمة N الحالية لا تساوي 1</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> N is not </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// ‫إذا كان N عددًا زوجيًا</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> N is even</span><span class="pun">:</span><span class="pln">
        </span><span class="com">// ‫احسب قيمة العنصر التالي وأسنده إلى N</span><span class="pln">
       </span><span class="typ">Compute</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> N</span><span class="pun">/</span><span class="lit">2</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// ‫إذا كان N عددًا فرديًا</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
        </span><span class="com">// ‫احسب قيمة العنصر التالي وأسنده إلى N</span><span class="pln">
       </span><span class="typ">Compute</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> N </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// اطبع قيمة‫ N</span><span class="pln">
    </span><span class="typ">Output</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// ‫أزد قيمة العداد بمقدار 1</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to counter</span><span class="pun">;</span><span class="pln">
</span><span class="com">// اطبع عدد عناصر المتتالية</span><span class="pln">
</span><span class="typ">Output</span><span class="pln"> the counter</span><span class="pun">;</span></pre>

<p>
	ما يزال أمامنا مشكلة أخيرة بخُصوص الخطوة الأولى، وهي كيف نتأكد من أن المُستخدِم قد أَدْخَل عَدَدًا صحيحًا موجبًا؟ ففي الواقع، قد يُدْخِل المُستخدِم عَدَدًا سالبًا أو صفرًا، وعندها سيستمر تَّنْفيذ البرنامج للأبد؛ لأن القيمة المُدْخَلة <code>N</code>، في تلك الحالة، لن تُصبِح أبدًا مُساوِية للواحد. ربما قد لا يُعدّ ذلك مشكلة ضخمة في تلك الحالة تَحْدِيدًا، ولكن، مع ذلك، ينبغي عمومًا محاولة كتابة برامج غَيْر قابلة للخطأ. نستطيع حَل تلك المُشكلة عن طريق الاستمرار بقراءة الأعداد إلى أن يُدْخِل المُستخدِم عددًا صحيحًا موجبًا.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_28" style=""><span class="com">// اطلب من المستخدم إدخال عدد صحيح موجب</span><span class="pln">
</span><span class="typ">Ask</span><span class="pln"> user to input a positive number</span><span class="pun">;</span><span class="pln">
</span><span class="com">// ‫أسند القيمة المدخلة إلى N</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> N be the user</span><span class="str">'</span><span class="pln">s response</span><span class="pun">;</span><span class="pln">
</span><span class="com">// طالما‫ N ليست موجبة</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> N is not positive</span><span class="pun">:</span><span class="pln">
   </span><span class="com">// اطبع رسالة خطأ</span><span class="pln">
   </span><span class="typ">Print</span><span class="pln"> an error message</span><span class="pun">;</span><span class="pln">
   </span><span class="com">// ‫اقرأ قيمة أخرى واسندها إلى N</span><span class="pln">
   </span><span class="typ">Read</span><span class="pln"> another value </span><span class="kwd">for</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">
</span><span class="com">// اضبط قيمة العداد إلى القيمة صفر</span><span class="pln">
</span><span class="typ">Let</span><span class="pln"> counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="com">// ‫‫طالما كانت قيمة `N` الحالية لا تساوي 1</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> N is not </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
    </span><span class="com">// ‫إذا كان N عددًا زوجيًا</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> N is even</span><span class="pun">:</span><span class="pln">
       </span><span class="com">// ‫احسب قيمة العنصر التالي وأسنده إلى N</span><span class="pln">
       </span><span class="typ">Compute</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> N</span><span class="pun">/</span><span class="lit">2</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// ‫إذا كان N عددًا فرديًا</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
        </span><span class="com">// ‫احسب قيمة العنصر التالي وأسنده إلى N</span><span class="pln">
       </span><span class="typ">Compute</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> N </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// اطبع قيمة‫ N</span><span class="pln">
    </span><span class="typ">Output</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">
    </span><span class="com">// ‫أزد قيمة العداد بمقدار 1</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to counter</span><span class="pun">;</span><span class="pln">
</span><span class="com">// اطبع عدد عناصر المتتالية</span><span class="pln">
</span><span class="typ">Output</span><span class="pln"> the counter</span><span class="pun">;</span></pre>

<p>
	لاحِظ أن حَلْقة <code>while</code> الأولى ستنتهي فقط عندما تُصبِح قيمة <code>N</code> زوجية.
</p>

<p>
	عند محاولة كتابة شيفرة التَوصِيف التالي: "إذا كانت قيمة <code>N</code> غَيْر زوجية، اُطلب من المُستخدِم إِدْخَال عدد آخر"، يقع الكثير من المبرمجين، وبالأخص المبتدئين، في خطأ اِستخدَام تَعْليمَة التَفْرِيع <code>if</code> بدلًا من تَعْليمَة حَلْقة التَكْرار <code>while</code>. تَظهر المشكلة تَحْدِيدًا عندما يُدْخِل المُستخدِم عددًا غَيْر زوجي مرة آخرى. لمّا كانت تَعْليمَة التَفْرِيع <code>if</code> تُنفَّذ مرة واحدة فقط، فإنه لا يَتمّ فَحْص مُدْخَل المُستخدِم إلا مرة واحدة فقط، مما يعني أن البرنامج سينتقل إلى تَّنْفيذ التَعْليمَة التالية بغض النظر عما إذا كانت قيمة المُدْخَل الثاني للمُستخدِم زوجية أم لا، وهو ما يَتسبَّب بحُدوث حَلْقة لا نهائية (infinite loop) كما ذَكرنا آنفًا. أمَا في حالة اِستخدَام حَلْقة التَكْرار <code>while</code>، فإن الحاسوب سيَقفِز (أو سيَنقِل التَحكُّم بتعبير أدق) إلى بداية الحَلْقة بَعْد كل عملية إِدْخَال؛ لاختبار ما إذا كانت القيمة المُدْخَلة زوجية أم لا، مما يَعنِي أنه سيستمر في طلب إِدْخَال عَدَد جديد إلى أن يُدْخِل المُستخدِم قيمة مقبولة، أيّ عدد زوجي. وبالتالي، في حالة انتقال البرنامج إلى تَّنْفيذ ما بَعْد حَلْقة <code>while</code>، فإن قيمة <code>N</code> هي زوجية حتمًا.
</p>

<p>
	ها هو نفس البرنامج بشيفرة الجافا. لاحِظ اِستخدَام العَامِلين (operators)‏ <code>‎&lt;=‎</code> بمعنى "أقل من أو يُساوِي" و <code>‎!=‎</code> بمعنى "لا يُساوِي"، بالإضافة إلى اِستخدَام التعبير <code>N % 2 == 0</code>؛ لاختبار ما إذا كانت قيمة <code>N</code> زوجية. نُوقِشَت كل هذه العَوامِل في القسم ٢.٥.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_30" style=""><span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

 </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ThreeN1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

      </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                

         </span><span class="typ">int</span><span class="pln"> N</span><span class="pun">;</span><span class="pln">       </span><span class="com">// لحساب العناصر بالمتتالية</span><span class="pln">
         </span><span class="typ">int</span><span class="pln"> counter</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لعد عدد عناصر المتتالية</span><span class="pln">

         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Starting point for sequence: "</span><span class="pun">);</span><span class="pln">
         N </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">
         </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">
                   </span><span class="str">"The starting point must be positive. Please try again: "</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
            N </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">
         </span><span class="pun">}</span><span class="pln">

         </span><span class="com">// ‫نعلم أن N هي عدد صحيح موجب عند هذه النقطة</span><span class="pln">

         counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
         </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
             </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
                N </span><span class="pun">=</span><span class="pln"> N </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
             </span><span class="kwd">else</span><span class="pln">
                N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> N </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
             </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">N</span><span class="pun">);</span><span class="pln">
             counter </span><span class="pun">=</span><span class="pln"> counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
         </span><span class="pun">}</span><span class="pln">

         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"There were "</span><span class="pun">);</span><span class="pln">
         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">counter</span><span class="pun">);</span><span class="pln">
         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">" terms in the sequence."</span><span class="pun">);</span><span class="pln">

     </span><span class="pun">}</span><span class="pln">  </span><span class="com">// نهاية‫ main</span><span class="pln">

 </span><span class="pun">}</span><span class="pln">  </span><span class="com">// ‫نهاية الصنف ThreeN1</span></pre>

<p>
	مُلاحظتان أخيرتان على هذا البرنامج:
</p>

<p>
	أولًا، ربما لاحَظت أن البرنامج لم يَطبَع قيمة أول عنصر بالمُتتالية -أيّ قيمة <code>N</code> المُدْخَلة من قِبَل المُستخدِم-، وكذلك لم يعدّها. هل هذا خطأ؟ يَصعُب القول. ربما ينبغي أن نَطرح سؤالًا آخر: هل كان تَوصِيف البرنامج (specification) صريحًا بما يَكفي بخُصوص تلك النقطة؟ في الواقع، للإجابة على مثل هذا السؤال، ستَحتاج إلى طَلَب مزيد من الإيضاح من أستاذك/مديرك. يُمكِن عمومًا حل هذه المشكلة -في حال كانت- بسهولة، فقط اِستبدل السَطْرين التاليين بتَعْليمَة <code>counter = 0</code> قَبْل حَلْقة التَكْرار <code>while</code> :
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_32" style=""><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">N</span><span class="pun">);</span><span class="pln">   </span><span class="com">// print out initial term</span><span class="pln">
counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">       </span><span class="com">// and count it</span></pre>

<p>
	ثانيًا، لماذا تُعدّ هذه المسألة تَحْدِيدًا مثيرة؟ في الواقع، يَجِدْ كثير من علماء الرياضيات والحاسوب هذه المسألة مُشوقة؛ بسبب سؤال بسيط، يَخُص تلك المسألة، والذي لم يَتوصَّلوا للإجابة عليه بَعْد. السؤال هو "هل عملية حِسَاب قيم مُتتالية '3N+1' دومًا ما ستنتهي بَعْد عَدَد مُتناهي (finite) من الخطوات لجميع قيم <code>N</code> المبدئية؟" على الرغم من سهولة حِسَاب قيم المُتتاليات بشكل مُفرد، لم يُجِبْ أحد على السؤال الأعم حتى الآن، أيّ بصياغة آخرى، لا أحد يَعلم ما إذا كان من الصحيح تسمية عملية حِسَاب قيم مُتتالية "3N+1" بـ"الخوارزمية (algorithm)"؛ فبالنهاية، لابُدّ لأيّ خوارزمية أن تَنتهي بَعْد عَدَد مُتناهي من الخطوات.
</p>

<p>
	لاحظ: يَنطبق ذلك على الأعداد الصحيحة (integers) بمفهومها الرياضي، وليس القيم من النوع العددي الصحيح <code>int</code>! بمعنى أننا نفْترِض هنا أن قيمة <code>N</code> قد تَكُون أيّ عدد صحيح مُمكن مهما كَبُر، وهو ما لا يَنطبق على مُتَغيِّر من النوع <code>int</code> داخل برنامج بلغة الجافا. إذا أَصبحت قيمة <code>N</code> كبيرة جدًا ليَتمّ تَمثيلها بمُتَغيِّر من النوع <code>int</code> ‏(32 بت)، فلا يُمكِن عدّ قيم خَرْج البرنامج صحيحة رياضيًا، أيّ أن البرنامج لا يَحسِب قيم متتالية "3N+1" بشكل صحيح عندما تَكُون قيمة <code>N</code> كبيرة. اُنظر تمرين ٨.٢.
</p>

<h2>
	كتابة الشيفرة (coding) والاختبار (testing) وتنقيح الأخطاء (debugging)
</h2>

<p>
	بَعْد انتهائك من تَطوير خوارزمية البرنامج (algorithm)، سيَكُون من اللطيف لو كان بإمكانك الضغط فقط على زِر معين؛ لتَحصُل بَعْدها على برنامج قابل للتَّنْفيذ (working program) بصورة ممتازة. في الواقع، عملية تَحْوِيل الخوارزمية إلى شيفرة بلغة الجافا لا تَتمّ دومًا بمثل هذه السَلاسَة لسوء الحظ، وحتى عندما تَصِل إلى تلك المرحلة من الحُصول على برنامج قابل للتَّنْفيذ (working program)، فإنه غالبًا ما يَكُون قابلًا للتَّنْفيذ بمعنى أنه يُنفِّذ "شيء ما"، لا بالضرورة الشيء الذي تريده أن يَفعَله.
</p>

<p>
	بَعْد الانتهاء من تصميم البرنامج (program design)، يَحيِن موعد كتابة الشيفرة (coding): أيّ ترجمة التصميم إلى برنامج مكتوب بلغة الجافا أو بأيّ لغة برمجية اخرى. مَهمَا كنت حَريصًا أثناء كتابة الشيفرة، فعادةً ما ستَجِدْ بعض أخطاء بناء الجملة (syntax errors) طريقها إلى الشيفرة، ولذلك سيَرفُض مُصرِّف (compiler) الجافا البرنامج، وسيُبلِّغك عن نوع معين من رسائل الخطأ (error message). لاحِظ أنه في حين يستطيع المُصرِّف اكتشاف أخطاء بناء الجملة (syntax errors) دائمًا، فإنه لسوء الحظ ليس بنفس الكفاءة في اكتشاف مَاهية الخطأ، بل أنه قد لا يَتَمكَّن، في بعض الأحيان، من معرفة مكان حُدوث الخطأ الفِعليّ، فمثلًا، قد يَتسبَّب وجود خطأ إملائي أو نَسْيَان قوس "{" بالسطر رقم ٤٥ بتَوَقُّف المُصرِّف بالسطر ١٠٥. يَظِلّ، مع ذلك، الفهم الجيد لقواعد صياغة (syntax rules) اللغة البرمجية مع اِتباع بعض القواعد الإرشادية البرمجية البسيطة الطريقة الأفضل لتَلافِي كثير من تلك الأخطاء. لنسْتَعْرِض بعضًا من تلك القواعد، أولًا، لا تَكتُب أبدًا قوس حَاصِرة "{" بدون كتابة زوجه الآخر "}"، ثُمَّ عُد بَعْدها لكتابة التَعْليمَات بينهما؛ وذلك لأن نَسْيَان قوس أو إضافة قوس في غَيْر مَحَلّه يُعدّ من أكثر الأخطاء التي يَصعُب اكتشافها خاصة بالبرامج الضخمة. ثانيًا، اِستخدِم دائما المسافات البادئة (indentation) لتَنسيق الشيفرة، وإن عَدَّلت البرنامج، عَدِّل أيضًا المسافات البادئة بحيث تُصبِح مُتوافقة مع التَعْدِيل الجديد. ثالثًا، اِستخدِم نَمط تَسمية (naming scheme) ثابت؛ حتى لا تُعانِي بَعْد ذلك بينما تَتَذكَّر ما إذا كان اسم مُتَغيِّر ما (variable) هو "interestrate" أم "interestRate". رابعًا، عندما يُبلِّغك المُصرِّف بأكثر من رسالة خطأ (error message) واحدة، لا تُحاوِل إصلاح رسالة الخطأ الثانية حتى تَنتهي من إِصلاح الأولى؛ لأن المُصرِّف عادةً ما يَرتبك بعد إِيجاده لأول خطأ، ولذلك قد تَكُون رسائل الخطأ التالية هي مُجرَّد تَخمينات. وأخيرًا، وربما هي النصيحة الأفضل: خُذ الوقت الكافي لفِهم الخطأ قبل مُحاولة إِصلاحه؛ فالبرمجة، بالنهاية، ليست علمًا تجريبيًا (experimental science).
</p>

<p>
	إذا تمّ تَصرِيف برنامجك بنجاح، لا يَعنِي ذلك أنك قد انتهيت؛ فمن الضروري أن تَختبر (test) البرنامج لتتأكد مما إذا كان يَعمَل بشكل صحيح، وهو ما لا يَقْتصِر على مُجرَّد الحُصول على الخَرْج الصحيح (output) لعينة المُدْخَلات (inputs) التي أَعطاك إِياها الأستاذ، بل ينبغي للبرنامج أن يَعمَل بشكل سليم لجميع المُدْخَلات المقبولة، وفي حالة اِستقباله لمُدَْخَل غَيْر صالح، فينبغي أن يُوبِخ البرنامج المُستخدِم بلطف، لا أن يَنَهار (crashing) تمامًا. عمومًا، ينبغي أن تَختبِر البرنامج على نطاق واسع من المُدْخَلات. قد تُحاوِل أيضًا إِيجاد مجموعة المُدْخَلات التي بإِمكانها اِختبار جميع الوظائف التي أَدْرَجتها بالشيفرة. في حالة كتابة برامج كبيرة، حَاوِل تقسيمها إلى عدة مراحل، بحيث تَختبِر كل مرحلة قَبْل البدء بالمرحلة التالية، حتى لو اضطررت لكتابة شيفرة إِضافية تقوم بالاختبار مثل أن تَستدعِي أحد البرامج الفرعية التي قُمت بكتابتها للتو؛ فأنت حتمًا لا تُريد أن يَنتهي بك الحال بخُمسمائة سَطْر جديد من الشيفرة مَصحوبة بخطأ ما في مكان ما.
</p>

<p>
	الغرض من الاختبار (testing) هو مُحاولة العُثور على الأخطاء البرمجية (bugs)، وهي -بعكس أخطاء التَصرِيف (compilation errors)- أخطاء دَلاليّة (semantic errors)، أيّ تَكُون في صورة سُلوك غَيْر سليم. المُحزن في الأمر هو أنك غالبًا ما ستَجِدهم. تستطيع، مع ذلك، تَقْليل -لا التَفادِي التام- هذه النوعية من الأخطاء البرمجية (bugs)، من خلال الانتباه أثناء قيامك بكُلًا من التصميم (design)، وكتابة الشيفرة (coding). عندما تَكتشف خطأً برمجيًا (bug)، يَحيِن موعد تَنْقِيح الأخطاء (debugging)، بمعنى تَعَقُّب سبب الخطأ بالشيفرة بهدف التخلص منه. لاحظ أنك لن تُصبِح خبيرًا بتَنْقِيح الأخطاء إلا من خلال المُمارسة المستمرة؛ فهي مَهارة تكتسبها، مثلها مثل جميع نواحي البرمجة الآخرى، ولذلك لا تَكُن خائفا منها، وإنما تَعلَّم منها. تُعدّ القدرة على قراءة الشيفرة واحدة من أهم مهارات تَنْقِيح الأخطاء الاساسية، والمقصود بقراءة الشيفرة هنا: القدرة على تَنْحية تَصوراتك المُسْبَّقة عما ينبغي للشيفرة أن تقوم به، وبدلًا من ذلك، تَعقُّب الطريقة التي يُنفِّذها بها الحاسوب خَطوة بخَطوة؛ لتُدرِك ما تَقوم به فِعليًا. في الواقع، هذا ليس بالأمر السهل. ما يزال الكاتب يَذكُر تلك المرة التي قضى فيها عدة ساعات يَبحث عن خطأ برمجي ليَكتشِف بالنهاية أن سَطْرًا ما بالشيفرة، كان قد نَظَر إليه عشرات المرات، يَحتوِي على القيمة ١ بدلًا من الحرف i، أو تلك المرة التي كَتَب فيها برنامجًا فرعيًا (subroutine) اسمه هو WindowClosing، والذي كان سيُؤدي غرضه تمامًا لولا أن الحاسوب كان يَبحث عن البرنامج الفرعي windowClosing (بحرف w صغير). قد يُساعِدك أحيانًا الاستعانة بشخص آخر لفَحْص الشيفرة، خاصة وأنه لن يَملك نفس تَصوراتك المُسْبَّقة عنها.
</p>

<p>
	أحيانًا ما يَكُون مُجرَّد العثور على ذلك الجزء من البرنامج الذي يَكمُن فيه الخطأ مُشكلة بحد ذاته، ولهذا تُوفِّر مُعظم بيئات التطوير البرمجية (programming environments) برنامجًا يُسمَى مُنقِّح الأخطاء (debugger)؛ لمساعدتك بالعثور على الأخطاء البرمجية (bugs)، بحيث يَتمّ تَشْغِيل البرنامج (program) تحت تَحكُّم ذلك المُنقِّح، والذي يَسمَح لك بضَبْط ما يُعرَف باسم نقاط المُقاطعة (breakpoints)، وهي نقاط بالبرنامج سيَتوقَّف عندها المُنقِّح مؤقتًا (pause)؛ حتى تَتَمكَّن من فَحْص قيم مُتَغيِّرات البرنامج عند تلك النقطة، مما سيُساعدك في العُثور على المكان الذي بدأت فيه الأخطاء البرمجية بالظهور أثناء تَّنْفيذ البرنامج. بمُجرَّد تَحْدِيد ذلك الجزء من البرنامج الذي يَكمُن فيه الخطأ البرمجي (bug)، يَسمَح لك المُنقِّح أيضًا بتَّنْفيذ البرنامج سَطْرًا سَطْرًا، ومِنْ ثَمَّ، تستطيع مشاهدة ما يَحدُث تفصيليًا.
</p>

<p>
	يَعترِف الكاتب أنه لا يَستخدِم مُنقِّح الأخطاء دائمًا، وإنما يَتبِع المنهج التقليدي لتَنْقِيح الأخطاء، وذلك بإضافة تَعْليمَات تَنْقِيحيّة (debugging statements) داخل البرنامج، والتي هي مُجرَّد تَعْليمَات خَرْج تَطبَع معلومات عن حالة (state) البرنامج. عادةً ما تُكتَب أيّ تَعْليمَة تَنْقِيحيّة على الصورة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_273_34" style=""><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"At start of while loop, N = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> N</span><span class="pun">);</span></pre>

<p>
	ينبغي لنص الخَرْج أن يُساعِدك على تَحْدِيد مكان تَعْليمَة الطباعة المسئولة عن ذلك الخَرْج، وكذلك معرفة قيم المُتَغيِّرات (variables) المُهمة. ستكتشف، في بعض الأحيان، أن الحاسوب لم يَمر حتى على ذلك الجزء من البرنامج الذي كنت تَظن أنه يُنفِّذه. تَذكَّر أن الهدف هو اكتشاف أول نُقطة بالبرنامج أَصبَحت فيها حالة البرنامج (state) مُخالِفة للحالة المُتوقَّعة، فهذا هو مكان الخطأ البرمجي (bug).
</p>

<p>
	وأخيرًا، تَذكَّر القاعدة الذهبية لتَنْقِيح الأخطاء: إذا كنت مُتأكدًا تمامًا أن كُل شئ بالبرنامج سليم، ومع ذلك ما يزال لا يَعمَل بالصورة المطلوبة، فلابُدّ أن واحدًا من تلك الأشياء هو ببساطة خطأ.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s1.html" rel="external nofollow">Section 3.1 Blocks, Loops, and Branches </a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1063</guid><pubDate>Tue, 10 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x643;&#x62A;&#x644; (Blocks) &#x648;&#x627;&#x644;&#x62D;&#x644;&#x642;&#x627;&#x62A; (Loops) &#x648;&#x627;&#x644;&#x62A;&#x641;&#x631;&#x639;&#x627;&#x62A; (Branches) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D9%83%D8%AA%D9%84-blocks-%D9%88%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-loops-%D9%88%D8%A7%D9%84%D8%AA%D9%81%D8%B1%D8%B9%D8%A7%D8%AA-branches-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1062/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/14.png.c7a652457e6058b1a9842af2d6d3168c.png" /></p>

<p>
	تعتمد قدرة الحاسب على أداء مهامٍ معقدة على دمج التعليمات البسيطة ضمن بنى تحكمٍ. هناك 6 بنى تحكم كهذه في جافا، تستخدم لتحديد تدفق التحكم الطبيعي في البرنامج وتكفي ثلاث منها لكتابة برامج قادرة على أداء أيّة مهمة.بنى التحكم الستّ هي: الكتلة (block) وحلقة <code>while</code> وحلقة <code>do..while</code> وحلقة <code>for</code> وتعليمة <code>if</code> وتعليمة <code>switch</code>.
</p>

<p>
	تُعدّ كلّ واحدة من البنى السابقة "تعليمةً" مفردة، لكنها في الواقع تعليمة بنيوية قد تحتوي بداخلها تعليمة أو أكثر.
</p>

<h2>
	الكتل
</h2>

<p>
	الكتلة (Blocks) هي الشكل الأبسط للتعليمات البنيوية، وتهدف إلى تجميع سلسلة من التعليمات في تعليمة واحدة. تأخذ الكتلة الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7129_7" style="">
<span class="pun">{</span><span class="pln">     
        </span><span class="com">// ضع التعليمات هنا</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بكلمات أخرى، تتألف الكتلة من سلسلة من التعليمات المُغلّفة بين قوسين من الشكل "{ }". يمكن ألّا تحتوي الكتلة أيّة تعليمة، وتدعى عندئذٍ بالكتلة الفارغة (empty block) ومن الوارد أن تلزمك أحيانًا. تتألف الكتلة الفارغة من زوج فارغ من الأقواس فقط.
</p>

<p>
	عادةً ما ترد كتل التعليمات ضمن تعليمات أخرى وتهدف إلى تجميع عدة تعليمات معًا في وحدةٍ واحدة. يمكنك في الحقيقة استخدام كتل التعليمات أينما وردت تعليمةٌ. بيد أنّ من الواجب استخدامها في حالة البرامج الفرعية -لاحظ استخدامنا لها سابقًا في حالة البرنامج الفرعي <code>main</code> . البرنامج الفرعيّ هو كتلةٌ بالتعريف، نظرًا لكونه سلسلةً من التعليمات المغلّفة ضمن زوج من الأقواس.
</p>

<p>
	من الجدير بالذكر هنا أنّ لغة البرمجة جافا هي لغةٌ حرة التنسيق وهذا يعني عدم وجود قواعد صياغة تحدد كيفيّة ترتيب اللغة على الصفحة. يمكنك إن أردت، على سبيل المثال، كتابة كتلةٍ كاملة على سطر واحد. مع ذلك، ينبغي عليك، اتباعًا لممارسات البرمجة الفضلى، تنظيم برنامجك على نحوٍ يجعل قراءته وفهمه أسهل ما يمكن. يقتضي هذا في الحالة العامة كتابةً تعليمةٍ واحدة فقط في السطر واستخدام المسافات البادئة للإشارة إلى التعليمات المُحتواة ضمن بنى التحكم. سيُستخدم التنسيق هذا في جميع أمثلة الكتاب.إليك مثالين عن الكتل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7129_9" style="">
<span class="pun">{</span><span class="pln">
    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"الجواب هو: "</span><span class="pun">);</span><span class="pln">  
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">ans</span><span class="pun">);</span><span class="pln">

</span><span class="pun">}</span></pre>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7129_11" style="">
<span class="pun">{</span><span class="pln">  </span><span class="com">// ‫تستبدل هذه الكتلة بين قيمتي المتغيرين x و y</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">      </span><span class="com">// مُتغير مؤقت لاستخدامه ضمن هذه الكتلة</span><span class="pln">
   temp </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">      </span><span class="com">// ‫احفظ نسخةً عن x صمن temp.</span><span class="pln">
   x </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">         </span><span class="com">// انسخ قيمة‫ y إلى x.</span><span class="pln">
   y </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">      </span><span class="com">// ‫انسخ قيمة temp إلى y.</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span></pre>

<p>
	قمنا في المثال الثاني بالتصريح عن المتغيّر <code>temp</code> ضمن الكتلة. التصريح عن متغيّرٍ ضمن كتلةٍ أمرٌ جائزٌ لا بل ومستحسنٌ أيضًا لا سيما إن كان استخدام المتغير مقتصرًا على تلك الكتلة. لا يمكن الوصول للمتغير المُصرّح عنه ضمن كتلة خارجها ولا يكون مرئيًّا إلا فيها. عندما ينفّذ الحاسوب تعليمة التصريح عن متغيّر، يخصص موضعًا في الذاكرة لتخزين قيمة هذا المتغيّر (نظريًّا على الأقل). عندما تنتهي الكتلة، يتم التخلّص من موضع الذاكرة ذاك ليصبح مُتاحًا للاستخدام مجددًا. يقال أنّ هذا المتغير "محلّي" ضمن الكتلة.
</p>

<p>
	هناك مفهوم أكثر شمولًا يُصطلح على تسميته مجال المُعرّف (scope of an identifier). مجال المُعرّف هو جزء من البرنامج يكون فيه المعرّف صالحًا. يقتصر مجال المتغيّر المُعرّف ضمن كتلة على الكتلة نفسها، وعلى نحوٍ أدق، يقتصر مجال المتغيّر المعرّف ضمن كتلة على الجزء من الكتلة الذي يلي التصريح عنه.
</p>

<h2>
	حلقة while الأساسيّة
</h2>

<p>
	لا تؤثر تعليمة الكتلة بحدّ ذاتها على تدفق التحكم في البرنامج على عكس بنى التحكم الخمس المتبقية. تُصنّف هذه البنى إلى نوعين: تعليمات الحلقات وتعليمات التفريع. في الواقع، لا تحتاج لغة البرمجة عامّة الغرض سوى إلى بنية تحكم واحدة من كل نوعٍ وكل ما سواهما هو بغرض التسهيل والتبسيط ليس إلّا. سنتطرق في هذا القسم إلى حلقة <code>while</code> وتعليمة <code>if</code> ونؤجل الحديث عن بنى التحكم الثلاث المتبقية إلى أقسام لاحقة.
</p>

<p>
	تُستخدم حلقة <code>while</code> لتكرار تعليمة معيّنة مرة بعد مرة. من غير المرجّح أنّك ستحتاج تكرار العملية إلى الأبد، لكنّه أمرٌ ممكن ويدعى الحلقة اللانهائية وهو غير محبّذ في الحالة العامة. هناك قصة قديمة عن رائدة علوم الحاسوب غريس موراي هوبر التي قرأت التعليمات على علبة الشامبو وكانت تنصّ على: " ارغي، اشطفي، كرري العمليّة." اتبعت غريس التعليمات حسب قولها وانتهى بها الأمر بعلبة شامبو فارغة. روت غريس القصة كمزحة حول اتباع الحواسيب للتعليمات بدون تفكير.
</p>

<p>
	توخيًّا للدقة، نقول أنّ حلقة <code>while</code> تُكرر التعليمة مرةً بعد مرة طالما أنّ قيمة شرطٍ محدّدٍ هي <code>true</code>. تأخذ حلقة <code>while</code> الشكل الآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7129_13" style="">
<span class="kwd">while</span><span class="pln"> </span><span class="pun">(تعبير</span><span class="pln"> </span><span class="pun">منطقي)</span><span class="pln">
   </span><span class="com">//ضع تعليماتك هنا</span></pre>

<p>
	نظرًا لأنّه من الممكن والمرّجح أن التعليمة هي كتلة تعليمات، تأخذ معظم حلقات <code>while</code> الشكل الآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7129_15" style="">
<span class="kwd">while</span><span class="pln"> </span><span class="pun">(تعبير</span><span class="pln"> </span><span class="pun">منطقي)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">//ضع تعليماتك هنا</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يظّن بعض المبرمجين أنّ من الواجب تضمين الأقواس دائمًا لضرورات تنسيقية حتى لو كانت ستُغلّف تعليمةً واحدة فحسب، لكننا لن نتبع هذه النصيحة في الكتاب.
</p>

<p>
	أمّا دلالة تعليمة <code>while</code> فهي كما يلي: عندما يصادف الحاسوب تعليمة <code>while</code>، يقوم بتقييم التعبير المنطقي لينتج عن ذلك قيمة إما <code>ture</code> أو <code>false</code>. إذا كانت القيمة <code>false</code>، يتجاوز الحاسوب بقيّة حلقة <code>while</code> ويتابع تنفيذ الأمر الذي يليها في البرنامج. أمّا إذا كانت قيمة التعبير <code>ture</code>، ينفّذ الحاسوب التعليمة أو كتلة التعليمات الواردة ضمن الحلقة. بعدئذٍ، يعود الحاسوب إلى بداية حلقة <code>while</code> ويكرر العملية (أي يعاود تقييم التعبير المنطقي، يُنهي التنفيذ إذا كانت قيمته <code>false</code>، ويستمر إذا ما كانت <code>ture</code>). تتكرر العملية مرةً بعد مرةٍ بعد مرة حتى تصبح قيمة التعبير <code>false</code> عند قيام الحاسوب بتقييمه. إن لم نصل لهذه النتيجة، فستستمر الحلقة إلى الأبد.إليك مثالًا عن حلقة <code>while</code> بسيطة تطبع الأرقام 1، 2، 3، 4، 5:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7129_17" style="">
<span class="typ">int</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫العدد المراد طباعته.</span><span class="pln">
number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫ابدأ من الرقم 1.</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> number </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫تابع طالما أن العدد أصغر من 6.</span><span class="pln">
  </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">number</span><span class="pun">);</span><span class="pln">
  number </span><span class="pun">=</span><span class="pln"> number </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‫انتقل للعدد التالي.</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"انتهى التنفيذ"</span><span class="pun">);</span></pre>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c3/s2.html" rel="external nofollow">Section 2: Algorithm Development</a> من فصل Chapter 3: Programming in the Small II: Control من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1062</guid><pubDate>Sun, 08 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x628;&#x64A;&#x626;&#x627;&#x62A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; (programming environment) &#x641;&#x64A;  &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%A8%D9%8A%D8%A6%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-programming-environment-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1020/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/13.png.efe5225f4cf06e265270d3bda7039fe4.png" /></p>

<p>
	تُعدّ لغة الجافا لغة قياسية ومعيارية إلى حد بعيد، ومع ذلك، تختلف الإجراءات اللازمة لإنشاء برامج الجافا وتَصْرِيفها وتَعْدِيلها من بيئة برمجة (programming environment) إلى آخرى اختلافًا كبيرًا. تَتَوفَّر طريقتان في العموم هما: بيئة سطر الأوامر (command line environment) حيث يَكْتُب المُستخدِم أوامرًا (commands) يَرُد عليها الحاسوب، والآخرى هي بيئة تَطْوِير مُتكاملة (integrated development environment - IDE) والتي يَعتمِد فيها المُستخدِم على كُلًا من الفأرة ولوحة المفاتيح للتَفاعُل مع واجهة مُستخدِم رُسومية (graphical user interface). في حين تَتَوفَّر بيئة سطر أوامر واحدة للغة الجافا، فهنالك الكثير من بيئات التَطْوِير المُتكاملة منها Eclipse و NetBeans و IntelliJ IDEA و BlueJ. سنتناول خلال هذا القسم المعلومات الضرورية لكي تَتَمكَّن من تَصْرِيف (compile) الأمثلة وتَشْغِيلها باِستخدَام كُلًا من سطر الأوامر وبيئتي Eclipse و BlueJ. اِحرِص دائمًا على قراءة الأمثلة وتَصْريِفها وتَشْغِيلها. ستَجِد الشيفرة المصدرية لكُلًا من البرامج التوضيحية وحلول تمارين كل فصل <a href="http://math.hws.edu/javanotes" rel="external nofollow">بموقع الكتاب الالكتروني</a>.
</p>

<p>
	يُعدّ الإصدار ١٤ هو الإصدار الحالي من الجافا، ولكن سيَعتمِد الكتاب على الإصدار ٨. في الحقيقة، لقد حَدَثَت الكثير من التَعْدِيلات على لغة الجافا وكذلك سياسة شركة أوراكل (Oracle) منذ الإصدار ٨. أدت تلك التَغْيِيرات إلى جَعْل مُهِمّة تَثْبِيت الجافا وتَجهِيزها للعمل أكثر صعوبة، ولذلك سنُحاوِل شرح المعلومات الضرورية لتَثْبِيتها بهذا القسم.
</p>

<p>
	أصبحت الإصدارات الجديدة من الجافا تُصدَر بصورة أسرع مما كانت عليه في الماضي. يُعدّ بعضها إصدارات مُدعَّمة طويلة الأمد (long-term support - LTS) أي تَستمِر بتَلَقِّي التحديثات الأمنية (security updates) وتحديثات إصلاح الأخطاء البرمجية (bug fixes) لفترة أطول من الزمن. يُعدّ الإصدارين ٨ و ١١ من الجافا من الإصدارات المُدعَّمة طويلة الأمد أما الإصدارات ٩ و ١٠ و ١٢ و ١٣ و ١٤ فليست كذلك. في الواقع، الإصدارات ٨ و ١١ و ١٤ هي إصدارات مُدعَّمة رسميًا إلى الآن.
</p>

<h2>
	عدة تطوير جافا <code>JDK</code> و <code>JavaFX</code>
</h2>

<p>
	يُعرَف نظام التطوير بلغة الجافا باسم "عُدة تطوير جافا (Java Development Kit - JDK)". تَعتمِد الأمثلة بهذا الكتاب على الإصدار ٨ من الجافا أو الإصدارات الأحدث، لذا ينبغي أن تُثبته على حاسوبك. تَتَوفَّر الجافا بنسختين: عُدة تَطوِير (JDK) وبيئة تّنْفيذ (Java Runtime Environment - JRE). تُستخدَم نسخة بيئة التّنفيذ (JRE) لتَشغِيل البرامج، لكن ليس بإمكانها تَصْرِيفها (compile). في المقابل، يُمكِنك اِستخدَام نسخة عُدة التطوير (JDK) لتَصرِيف البرامج كما أنها تَتَضمَّن بيئة تّنْفيذ (JRE). لقد أصبح من الصعب إيجاد ملف بيئة تّنْفيذ مُنفصِل منذ الإصدار ١١ من الجافا ولكن ما يزال ذلك المُصطلح مُستخدَمًا على أية حال. تَتَضمَّن عُدة تطوير جافا (JDK) بيئة لسطر الأوامر (command line environment) ستحتاج إليها للعمل مع الجافا. لاحظ أنه لابُدّ من أن تُحمِّل عدة تطوير جافا (JDK) حتى لو كنت تنوي اِستخدَام بيئة تطوير متكاملة (IDE).
</p>

<p>
	طُوِّرت لغة الجافا بواسطة شركة صن ميكروسيستمز (Sun Microsystems) ثم اِستحوَذت عليها مؤسسة أوراكل (Oracle). يُمكِنك أن تُحمِّل نسخة أوراكل من عُدة تَطوِير جافا (JDK) من موقعها الإلكتروني مباشرةً، ولكنها أصبحت منذ الإصدار الحادي عشر تَستهدِف الأغراض التجارية لذا ربما قد تُفضِّل الاعتماد على نسخة OpenJDK فيما يتعلق بالأغراض الشخصية والتعليمية، فهي تمتلك نفس وظائف نسخة أوراكل كما أنها مُوزعة برخصة مجانية ومفتوحة المصدر (open-source). يَفترِض ما يلي اِستخدَامك لنسخة OpenJDK، فإذا كنت قد حمَّلت نسخة أوراكل، ستَجِد تَعْليمَات التثبيت بموقعها الإلكتروني.
</p>

<p>
	يُمكِنك أن تُحمِّل نسخة OpenJDK من موقع <a href="https://jdk.java.net" ipsnoembed="false" rel="external nofollow">https://jdk.java.net</a> التابع لأوراكل ولكنه يُوفِّر خيارات محدودة، لذا قد تُفضِّل تَحْمِيله من موقع <a href="https://adoptopenjdk.net/" rel="external nofollow">AdoptOpenJDK</a> حيث يُوفِّر نُسخًا لنطاق أوسع من المنصات كما أنه يُوفِّر أداة تثبيت للجافا لنظامي ماك (Mac) وويندوز (Windows) مما يُسهِل من عملية التثبيت على تلك المنصات لذا فقد يَكُون ذلك هو خيارك الأفضل لتثبيت JDK. أما بالنسبة لنظام لينكس (Linux)، فعادةً ما تستطيع تثبيت JDK من مستودع برمجيات (software repositories) النظام. لاحِظ أنه على الرغم من أن كُلًا من البرامج التوضيحية والتمارين التي سنتناولها هنا مُتناسبة مع الإصدارات الأقدم من JDK حتى الإصدار الثامن، لكن يُنصَح عمومًا بالاعتماد على أحدث إصدار منه أو على إصدار مُدعم على المدى البعيد. منذ مايو ٢٠٢٠، يُعدّ الإصدار الحالي للجافا هو ١٤.
</p>

<p>
	تَعتمِد تطبيقات واجهة المُستخدِم الرسومية (GUI programs) على مكتبة برمجية تُعرَف باسم <code>JavaFX</code>. إذا كنت تَستخدِم أداة OpenJDK، فينبغي عليك أن تُحمِّل تلك المكتبة بصورة مُنفصلة عن الأداة. أما بالنسبة لنُسخ أوراكل من أداة JDK، فلقد كانت مكتبة <code>JavaFX</code> مُضْمَّنة بها حتى الإصدار الحادي عشر من الجافا أي إذا كنت تَستخدِم إصدارًا أحدث، سينبغي عليك تَحْمِيلها أيضًا بصورة مُنفصِلة. تستطيع عمومًا تَحْمِيل مكتبة <code>JavaFX</code> من <a href="https://gluonhq.com/products/javafx/" rel="external nofollow">هنا</a>.
</p>

<p>
	ملحوظة: ينبغي أن تَكُون عُدة تطوير جافا إف إكس (JavaFX SDK) مُتناسبة مع نظام التَشغِيل الخاص بك (لينكس، وماك، وويندوز) كما ينبغي أن تَكُون مُتوافقة مع إصدار أداة OpenJDK الذي تَستخدِمه.
</p>

<p>
	إذا كنت قد حَمَّلت أداة تثبيت JDK لنظام ويندوز (Windows) أو ماك (Mac) من موقع أوراكل (Oracle) أو موقع AdoptOpenJDK، فتستطيع ببساطة أن تَنقُر نقرة مزدوجة على ملف أداة التثبيت إذا لم يَكُن قد شُغِّل أتوماتيكيًا بالفعل لبدء عملية التثبيت أما إذا كنت قد حَمَّلت ملفات OpenJDK و JavaFX، فستَجِد كُلًا منهما بهيئة ملف أرشيفي (archive file) مَضغُوط ينبغي أن تَستخرِج محتوياته أولًا. يُمكِنك أن تَنقُر على أيقونة الملف الأرشيفي نقرة مُزدوجة مما سيُؤدي إلى اِستخرَاج محتوياته أو فَتْح برنامج يُساعِدك على اِستخرَاج محتوياته. ستَجِد بَعْدها مُجلدًا يحمل اسم مشابه لـ"jdk-11.0.7" أو "javafx-sdk-11.0.2"، والذي تستطيع وَضْعُه بأي مكان بالحاسوب ولكن ينبغي أن تَعرِف مساره.
</p>

<p>
	إذا كنت تَستخدِم نظام لينكس (Linux)، فعادةً ما يُوفِّر مستودع برمجيات (software repositories) لينكس إصدارًا حديثًا من كُلًا من OpenJDK و JavaFX مما سيُمكِّنك من تثبيتهما باِستخدَام أداة تثبيت البرمجيات (Linux software installer). يعَتمِد ذلك على إصدار لينكس المُستخدَم لكن في العموم يُمكِنك البحث عن أي حزم (packages) تَحتوِي أسمائها على كلمات مثل "openjdk" و "openjfx" كما أنك ستحتاج أيضًا إلى مَعرِفة مكان مجلد عدة تطوير JavaFX الذي يَقَع عادةً بالمسار "‎/usr/share/openjfx".
</p>

<p>
	إذا كُنت تَستخدِم نظام ماك (Mac) وحَمَّلت OpenJDK كملف أرشيفي، فينبغي أن تَستخرِج محتوياته، وستَجِد عندها مُجلدًا اسمه هو "jdk-11.0.7.jdk". يُنصَح بنَقْل مجلد JDK إلى المسار "‎/Library/Java/JavaVirtualMachines" وهو ما يَتَطلَّب بعض الصلاحيات الإدارية. يَعتمِد نظام ماك (Mac) بشكل تلقائي على أحدث إصدار من JDK بالمسار "‎Library/Java/JavaVirtualMachines/".
</p>

<p>
	أما إذا كنت تَستخدِم نظام ويندوز (Windows)، فعادةً ما تُثبَّت عُدة تطوير جافا (JDK) بالمسار "C:\Program Files\Java" لذلك يُمكِنك نَقْل مجلد OpenJDK إلى نفس ذلك المسار.
</p>

<h2>
	بيئة سطر الأوامر
</h2>

<p>
	تَختلِف بيئة سطر الأوامر (command line environment) عن واجهات المُستخدِم الرُسومية (graphical user interfaces) إلى حد كبير. في حين أن غالبية مُستخدمِي الحواسيب العصرية مُعتادون على الواجهات الرُسومية حيث يَجِدُون بيئة سطر الأوامر غَيْر بديهية، ولكن يُمكِنك بقليلٍ من المُمارسة أن تَتَعلَّم أساسيات بيئة سطر الأوامر وستَجِدها أكثر إنتاجية بالموازنة مع نظيرتها من الواجهات الرُسومية. في العموم، يُعدّ تَعلُّم كيفية اِستخدَام سطر الأوامر (command line) أمرًا مهمًا بالأخص لطلبة علوم الحاسوب (computer science)، ولكن يُمكِنك تَخطِّيه إن كُنت تَنوِي الاِعتمَاد بالكامل على واحدة من بيئات التطوير المتكاملة (IDE).
</p>

<p>
	ينبغي أن تَفتَح نافذة كتابة الأوامر أولًا لكي تَتَمكَّن من اِستخدَام بيئة سطر الأوامر (command line environment). إذا كنت تَستخدِم نظام ويندوز (Windows)، فيُمكِنك فَتْح تلك النافذة عن طريق تَشْغِيل برنامج اسمه "cmd" أما إذا كنت تَستخدِم نظام ماك (Mac)، فيُمكِنك تَشْغِيل برنامج الطرفية (terminal) والذي ستَجِده بمُجلد الأدوات (Utilities) داخل مُجلد التطبيقات (applications) أما إذا كنت تَستخدِم نظام لينكس (Linux)، فهنالك أكثر من طريقة، فيُمكِنك مثلًا أن تَستخدِم برنامجًا اسمه "xterm" لكن حَاوِل البحث عن برنامج الطرفية (terminal) بقائمة التطبيقات (applications) أولًا.
</p>

<p>
	عند فَتْح نافذة الأوامر (command window) بأي حاسوب، سيَظهَر محث (prompt) حيث تستطيع أن تَكْتُب أمرًا (command) ثم تَضغَط على مفتاح العودة الى بداية السطر. سيُنفِّذ الحاسوب عندها ذلك الأمر ثم سيَعرِض الخرج (output) الناتج عن الأمر بنفس النافذة. سيَظهَر بَعْدها المحث مرة آخرى لكي يُمكِّنك من كتابة أمر جديد. يُعدّ "المجلد الحالي (current directory)" أو "مجلد العمل (working directory)" واحدًا من المفاهيم الأساسية ببيئة سطر الأوامر (command line environment)، وعادةً ما يَكُون اسم المجلد الحالي جزءًا من اسم محث الأوامر (command prompt). (لاحِظ أن الكلمتين "directory" أو "folder" يحملان نفس المعنى). يَحتوِي المجلد الحالي (current directory) على ملفات تُستخدَم مِن قِبَل الأوامر المُدْخَلة. إذا كنت تَستخدِم نظام ويندوز، يُمكِنك اِستخدَام الأمر <code>dir</code> لتَحصُل على قائمة بالملفات الموجودة بالمجلد الحالي أما إذا كنت تَستخدِم نظام لينكس أو ماك، فيُمكِنك اِستخدِم الأمر <code>ls</code> لنفس الغرض. عند فَتْح النافذة للمرة الأولى، ستَجِد أن المُجلد الحالي يُشير إلى المجلد الرئيسي للمُستخدِم (home directory) أي حيث ملفاته الشخصية مُخزَّنة. يُمكِنك أن تُغيِّر المجلد الحالي باِستخدَام الأمر <code>cd</code> متبوعًا باسم المُجلد الذي تود أن تَستخدِمه. فمثلًا إذا كان المجلد الحالي يُشير إلى مجلدك الرئيسي (home directory)، يُمكِنك أن تَكْتُب الأمر <code>cd Desktop</code> لكي تُغيِّره إلى مُجلد سطح المكتب (Desktop directory) الخاص بك وبالطبع ينبغي أن تَضغَط على مفتاح العودة إلى بداية السطر لكي يُنفَّذ الأمر.
</p>

<p>
	يُمكِنك أن تُنشِئ مجلدًا (directory/folder) بمُجلدك الرئيسي (home directory) لتَخْزِين برامج الجافا الخاصة بك، وليَكُن اسم المجلد هو "javawork". تستطيع بالطبع أن تُنشِئه باِستخدَام الواجهة الرسومية، ولكننا سنُنشِئه هنا باِستخدَام سطر الأوامر (command line). اِتبع الخطوات التالية ببساطة: أولًا، اِفتح نافذة الأوامر (command window). إذا كُنت تريد أن تُنشِئه بمجلد آخر غَيْر مُجلدك الرئيسي (home directory)، فينبغي أن تَستخدِم الأمر <code>cd</code> -كما أوضحنا مُسبَقًا- للانتقال إلى ذلك المجلد. بَعد ذلك، يُمكِنك أن تَكْتُب الأمر <code>mkdir javawork</code> لكي تُنشِئ المجلد الجديد. وقتما تريد العمل على أحد برامج الجافا الخاصة بك ضِمْن ذلك المجلد، تستطيع فَتْح نافذة الأوامر (command window) وكتابة الأمر <code>cd</code> للانتقال إلى المجلد "javawork".
</p>

<p>
	يُعدّ الأمرين <code>javac</code> و <code>java</code> من أبسط الأوامر لاِستخدَام الجافا من خلال سطر الأوامر. يُستخدَم الأمر <code>javac</code> لتَصرِيف (compile) الشيفرة المصدرية المَكْتُوبة بلغة الجافا بينما يُستخدَم الأمر <code>java</code> لتَشْغِيل البرامج. تَقَع تلك الأوامر بمجلد اسمه "bin" داخل مجلد عُدة تطوير جافا (JDK). إذا ثَبَّت كل شيء بصورة سليمة، فينبغي أن يتعرَّف الحاسوب على هذه الأوامر عند كتابتها بسطر الأوامر (command line). حَاوِل مثلًا أن تَكْتُب كُلًا من الأمرين <code>java -version</code> و <code>javac -version</code> بسطر الأوامر. إذا كان كل شيء مُثبَّتًا على نحو سليم، فستَعرِض تلك الأوامر إصدار الجافا المُثبَّت أما إذا كان هنالك مشكلة ما، فستَحصُل على رسالة مثل "الأمر غَيْر موجود".
</p>

<p>
	بالنسبة لنظام لينكس، إذا كنت قد ثَبَّت الجافا من مستودع برمجيات النظام (software repositories)، فينبغي أن يَكون كل شيء مَضبُوطًا على نحوٍ سليم. يَنطبِق الأمر نفسه على نظام ماك إذا كنت قد اِستخدَمت أداة التثبيت من موقع AdoptOpenJDK أو إذا كنت قد نَقْلَت مجلد OpenJDK إلى المسار "/Library/Java/JavaVirtualMachines/". يَعتمِد الأمرين <code>javac</code> و <code>java</code> بنظام ماك على أحدث إصدار من عدة تطوير جافا (JDK) ضِمْن ذلك المجلد. بالنسبة لنظام ويندوز، إذا كنت قد اِستخدَمت أداة تثبيت AdoptOpenJDK، فينبغي أن يَكُون كل شيء مضبوطًا بصورة افتراضية. في المقابل، إذا كنت قد اِستخدَمت نُسخة أوراكل من عُدة تطوير جافا (Oracle JDK) أو ملف JDK مضغُوط، فلابُدّ أن تُضيف مسار مجلد "bin" الموجود بمجلد عُدة تطوير جافا (JDK) يدويًا إلى مسار النظام (system path). تُوضِح تَعْليمَات تثبيت نسخة أوراكل بنظام ويندوز طريقة القيام بذلك. اُنظر تحديدًا قسم "<a href="https://docs.oracle.com/en/java/javase/15/install/installation-jdk-microsoft-windows-platforms.html" rel="external nofollow">ضَبْط مُتْغيِّر البيئة PATH</a>" بتَعْليمَات تثبيت JDK بنظام ويندوز.
</p>

<p>
	سنُجرِّب الآن الأمر <code>javac</code>، يُمكِنك أن تَضَع مثلًا نُسخة من الملف <code>HelloWorld.java</code> بمجلد العمل (working directory). إذا كنت قد حمَّلت نسخة الكتاب المُتاحة عبر الإنترنت، ستَجِد ذلك الملف بالمجلد "source". تستطيع أن تَستخدِم الواجهة الرسومية لنَسْخ ذلك الملف ولصقه إلى مجلد العمل. أو على نحوٍ بديل، يُمكِنك فَتْح ذلك الملف بالموقع الإلكتروني للكتاب واِستخدَام أمر المُتصفح "Save As" لحِفظ نسخة منه بمُجلد العمل الخاص بك. اُكْتب الآن الأمر التالي:
</p>

<pre class="ipsCode">
javac  HelloWorld.java
</pre>

<p>
	سيُصرِّف ذلك الأمر الملف <code>HelloWorld.java</code> وسيُنشِئ ملف بايتكود اسمه <code>HelloWorld.class</code> بنفس المجلد. إذا نجح الأمر في عملية التصريف، لن تَحصُل على أي خَرْج، وسيَظهَر محث الأوامر (command prompt) مرة آخرى ليُخبرك بكَوْنه جاهزًا لاستقبال أي أمر آخر. يُمكِنك عندها كتابة الأمر <code>java</code> لتَشْغِيل البرنامج كالتالي:
</p>

<pre class="ipsCode">
java  HelloWorld
</pre>

<p>
	ينبغي أن يَعرِض الحاسوب الرسالة "Hello World!‎". على الرغم من أن البرنامج مُخزَّن بالملف <code>HelloWorld.class</code>، يَستخدِم الأمر <code>java</code> اسم الصَنْف (class) -أي <code>HelloWorld</code>- لا اسم الملف.
</p>

<p>
	تَستخدِم الكثير من البرامج التوضيحية التي سنتعرض لها الصنف <code>TextIO</code> لقراءة مدخلات المُستخدِم (اُنظر القسم الفرعي ٢.٤.٣). ولأن الصنف <code>TextIO</code> ليس جزءًا قياسيًا من لغة الجافا، لابُدّ إذًا من أن تتيحه لأي برنامج يَستخدِمه. يَعنِي ذلك أن مجلد العمل (working directory) الخاص بك ينبغي أن يحتوي على مجلد اسمه "textio" بداخله ملف اسمه <code>TextIO.java</code>، والذي يُمكِنك نسخه من المجلد "source" أو تحميله من الموقع الالكتروني، ولكن تَأكَّد من وَضْعه داخل مجلد اسمه "textio" بنفس مجلد البرنامج الذي يَستخدِم الصَنْف <code>TextIO</code>.
</p>

<p>
	يُمكِنك الآن أن تُشغِّل البرنامج التوضيحي <code>Interest2.java</code> لتختبر مُدْخَلات البرنامج. اِستخدِم الأمر التالي أولًا لتَصرِيف (compile) البرنامج:
</p>

<pre class="ipsCode">
javac  Interest2.java
</pre>

<p>
	إذا نجح الأمر السابق، فإنه سيُنشِئ ملفًا مُصرَّفًا (compiled) اسمه <code>Interest2.class</code>، وكذلك سيُنشِئ ملفًا اسمه <code>TextIO.class</code> بالمجلد "textio" إذا لم يَكُن موجودًا. في العموم، لا يُصرِّف الأمر <code>javac</code> الملف المُخصَّص فقط وإنما يُصرِّف أيضًا أية ملفات جافا آخرى مطلوبة. تستطيع الآن تَشْغِيل البرنامج بكتابة الأمر التالي:
</p>

<pre class="ipsCode">
java  Interest2
</pre>

<p>
	سيَطلُب البرنامج منك أن تُدْخِل بعض المعلومات لذا ينبغي أن تَكْتُب إجاباتك بنافذة الأوامر (command window) مع الضَغْط على محرف العودة بنهاية كل سطر. عندما ينتهي البرنامج، سيَظهَر محث الأوامر (command prompt) مرة آخرى مما يَعنِي إمكانية كتابة أمر جديد. لأن الصَنْف <code>TextIO</code> لا يُعرِّف البرنامج <code>main()‎</code>، لا يُمكِن تّنْفيذه كبرنامج أي لا يَكُون للأمر <code>java TextIO</code> أي معنى.
</p>

<p>
	يُمكِنك تَشْغِيل جميع البرامج التي سنَتعرَّض لها هنا بنفس الطريقة باستثناء تلك التي تَستخدِم مكتبة JavaFX والتي سنُوضِح طريقة تَشْغِيلها بالقسم الفرعي التالي.
</p>

<p>
	ستحتاج إلى مُحرر نصي (text editor) لتُنشِئ برامجك الخاصة. سيَسمَح لك أي مُحرر نصي في العموم بكتابة مستندات (documents) تَحتوِي على نص مُجرّد (plain text) ومن ثَمَّ حِفظها. لابُدّ أن تَحفظ تلك المُستندات كنص مُجرّد بدون أي ترميز (encoding) أو تنسيق خاص. في المقابل، لا يُمكِنك أن تَستخدِم مُعالجات النصوص (Word processor) إلا إذا ضَبْطتها لكي تحفظ المستندات بهيئة نص مُجرّد (plain text). سيُمكِّنك أي محرر نصي جيد من البرمجة على نحو أفضل. يأتي نظام لينكس مثلًا مع مجموعة من محررات النصوص (text editors). أما بالنسبة لنظام ويندوز، فيُمكِنك أن تَستخدِم برنامج notepad أو قد تبحث عن شيء أفضل قليلًا. بالنسبة لنظام ماك، يُمكِنك أن تُحمِّل تطبيق <a href="https://www.barebones.com/products/bbedit/" rel="external nofollow">BBEdit</a> مجانًا. بالإضافة إلى تلك البرامج، قد تُفضِّل استخدام برامج متعددة المنصات (cross-platform) مثل المحرر النصي <a href="http://www.jedit.org/" rel="external nofollow">jedit</a> أو مُحرر البرمجة الشائع <a href="https://atom.io" rel="external nofollow">Atom</a>.
</p>

<p>
	يُمكِنك الآن أن تَكْتُب برنامجًا خاصًا بك باتباع الخطوات التالية: اِفتح نافذة سطر الأوامر (command line window) ثم استخدِم الأمر <code>cd</code> لكي تنتقل إلى مجلد العمل (working directory) حيث تُخزِّن ملفات الشيفرة المصدرية (source code). اُنقُر نقرة مزدوجة على أيقونة برنامج مُحرر النصوص (text editor) أو اختره من قائمة "ابدأ (Start)" لتَشْغِيله ثم اُكْتُب شيفرة البرنامج بنافذة المُحرر أو قد تُعدِّل على ملف شيفرة مصدرية موجود مُسْبَقًا، وأخيرًا اِحفظ الملف. يَحمِل أي ملف شيفرة مصدرية بلغة الجافا اسمًا يَتطابَق مع اسم الصَنْف (class) المُعرَّف بالملف وينتهي بالامتداد <code>‎.java</code>. بَعْد حِفظ الملف بمجلد العمل (working directory)، اِستخدِم الأمر <code>javac</code> لتَصْرِيف (compile) الملف كما ذَكَرنا مُسْبَقًا. إذا كان هنالك أية أخطاء بقواعد بناء الجملة (syntax errors) بشيفرة البرنامج، ستَظهَر رسائل خطأ بنافذة الأوامر (command window). ستُخبرك كل رسالة منها برقم سطر ضِمْن ملف حيث عَثَر الحاسوب على الخطأ. ينبغي إذًا أن تعود مرة آخرى إلى المُحرر لتَصْليح ذلك الخطأ، وبعدها ينبغي أن تَحفظ تلك التَغْيِيرات وتُجرِّب الأمر <code>javac</code> مُجددًا. يُفضل دومًا أن تُحاول إصلاح أول مجموعة صغيرة من رسائل الأخطاء، فعادةً ما يؤدي تَصْلِيحها إلى اختفاء بعض الأخطاء الآخرى. عندنا ينجح الأمر <code>javac</code> بعملية التَصرِيف، لن تَحصُل على أية رسائل نهائيًا أو قد تَحصُل على بعض "التحذيرات (warnings)" التي لا تَمنَع تَشْغِيل البرنامج. يُمكِنك الآن أن تَستخدِم الأمر <code>java</code> لتَشْغِيل البرنامج كما ذَكَرنا مُسْبَقًا. بمُجرّد تَصرِيف البرنامج، يُمكِنك أن تُشغِّله وقتما تُريد وبأي عدد من المرات دون الحاجة لإعادة تَصرِيفه (compile).
</p>

<p>
	ها هو مُلخَّص كل شيء تقريبًا: ابقي كُلًا من نافذة المحرر ونافذة سطر الأوامر مفتوحة. عَدِّل محتويات الملف ثم اِحفظه وأخيرًا حَاوِل تَصْرِيفه (compile) إلى أن تَختفِي جميع أخطاء بناء الجملة (syntax errors). ينبغي دومًا أن تَحفظ التَغْيِيرات التي أَجْرَيتها على الملف قَبْل أن تُحاوِل إعادة تَصْرِيفه حيث يرى المُصرِّف (compiler) آخر نُسخة محفوظة من الملف وليس النُسخة المَعرُوضة بنافذة المُحرر. بَعْدما تُشغِّل البرنامج، قد تَعثُر على بعض الأخطاء الدلالية (semantic errors)، وعندها يَنبغِي أن تعود إلى حَلْقة "عَدِّل واِحفظ وصَرِّف" في محاولة للعُثور على المشكلة وإصلاحها.
</p>

<h2>
	استخدام <code>JavaFX</code> بسطر الأوامر
</h2>

<p>
	تَتَكوَّن مكتبة <code>JavaFX</code> من مجموعة من الأصناف (classes) المَكْتُوبة بلغة الجافا، والتي يُمكِنها أن تُستخدَم لإنشاء برامج واجهة مُستخدِم رُسومية (GUI). سنَتَعرَّض لتلك المكتبة بالقسم ٣.٩ للمرة الأولى، وسنتناولها تفصيليًا بكُلًا من الفصلين ٦ و ١٣. بالإضافة إلى ذلك، ستَجِدها مُستخدَمة ضِمْن الأمثلة التوضيحية بعدة فصول آخرى.
</p>

<p>
	لقد كانت مكتبة <code>JavaFX</code> جزءًا قياسيًا من نسخة أوراكل من عُدة تطوير جافا (JDK) الإصدار ٨. إذا كنت قد ثَبَّت ذلك الإصدار، فأنت لست بحاجة للقيام بأي شيء آخر لاِستخدَامها. في المقابل، إذا كنت قد ثَبَّت OpenJDK أو JDK للإصدار ١١ أو أحدث، فينبغي عليك أن تُجْرِي عدة أشياء لأن مكتبة <code>JavaFX</code> أصبحت تُوزَّع منذ ذلك الإصدار كمجموعة من الوحدات (modules) بشكل مُستقِل. تُخزَّن الوحدات (modules) -كما سنُوضِح بالقسم الفرعي ٤.٦.٤- بهيئة ملفات <code>‎.jar</code> بالمجلد الفرعي "lib" بمجلد عُدة تطوير جافا إف إكس (Java SDK). عندما تَستخدِم أي من الأمرين <code>java</code> أو <code>javac</code> مع برنامج يَعتمِد على مكتبة <code>JavaFX</code>، ينبغي أن تُمرِّر مسار وحدات مكتبة <code>JavaFX</code> إلى ذلك الأمر. سنُوضِح بهذا القسم كيفية اِستخدَام <code>JavaFX</code> بسطر الأوامر بالإصدار ١١ أو أحدث.
</p>

<p>
	يُستخدَم الخياران <code>‎--module-path</code> و <code>‎--add-modules</code> لتَخْصِيص وحدات (modules) مكتبة <code>JavaFX</code>. يُخصِّص الخيار الأول المُجلد الذي يحتوي على ملفات <code>‎.jar</code> أما الثاني فيُخصِّص الوحدات (modules) المُستخدَمة ضِمْن البرنامج بشكل فعليّ. يُمكِنك ضَبْط قيمة الخيار <code>‎--add-modules</code> إلى القيمة "ALL-MODULE-PATH" مما سيُؤدي إلى إتاحة مكتبة <code>JavaFX</code> بالكامل أما الخيار <code>‎--module-path</code>، فينبغي أن تَضبُطه إلى مسار المجلد "lib" الذي يَحتوِي على ملفات <code>‎.jar</code>. لنَفترِض مثلًا أن اسم مجلد <code>JavaFX</code> هو "openjfx-sdk-11"، وبأنه موجود بالمجلد الرئيسي "‎/home/eck"، سيَكُون مسار المجلد "lib" هو "‎/home/eck/openjfx-sdk-11/lib" أي يُمكِننا عندها كتابة أمر <code>javac</code> التالي لتَصرِيف برامج <code>JavaFX</code>:
</p>

<pre class="ipsCode">
javac --module-path=/home/eck/openjfx-sdk-11/lib --add-modules=ALL-MODULE-PATH
</pre>

<p>
	ينبغي أن تُضيف إليه أسماء ملفات <code>‎.java</code> التي تُريد أن تُصرِّفها. يَتَطلَّب الأمر <code>java</code> نفس تلك الخيارات ليُشغِّل برامج <code>JavaFX</code>. يُمكِنك أن تَستخدِم الاختصار <code>‎-p</code> بدلًا من <code>‎--module-path</code> كالتالي:
</p>

<pre class="ipsCode">
javac -p /home/eck/openjfx-sdk-11/lib --add-modules=ALL-MODULE-PATH
</pre>

<p>
	إذا لم تَستطِع مَعرِفة مسار عُدة تطوير جافا إف إكس (JavaFX SDK)، اِفتح نافذة الأوامر (command window) واستخدِم الأمر <code>cd</code> لكي تنتقل إلى مجلد "lib" الخاص بعُدة تطوير جافا إف إكس. إذا كنت تَستخدِم نظام ماك أو لينكس، فيُمكِنك أن تَكْتُب الأمر <code>pwd</code> لكي تَطبَع مسار مجلد العمل (working directory) أما إذا كنت تَستخدِم نظام ويندوز، اِستخدِم الأمر <code>cd</code> بدون تَخْصِيص أي مجلد لكي تَطبَع المسار. أخيرًا، اِستخدِم خَرْج ما سبَق كقيمة للخيار <code>‎--module-path</code>. قد يبدو أمر <code>java</code> عند اِستخدَامه مع <code>javafx</code> كما يلي:
</p>

<pre class="ipsCode">
java -p C:\Users\eck\openjfx-sdk-11\lib --add-modules=ALL-MODULE-PATH
</pre>

<p>
	إذا اِحتوَى المسار على مسافة أو أي محارف خاصة آخرى، فلابُدّ أن تُحيطه بعلامتي اقتباس.
</p>

<p>
	لأن الأمر بالأعلى طويلًا نوعًا ما، سيَكُون من الأفضل بالتأكيد لو أمَكْنَنا تَجنُّب إعادة كتابته بكل مرة نُنفِّذه فيها. إذا كنت تَستخدِم نظام لينكس أو ماك، يُمكِنك أن تُعرِّف اسمًا مستعارًا (alias) يَعمَل كاختصار لأمر معين. على سبيل المثال، يُمكِنك أن تُعرِّف الاسم المستعار <code>jfxc</code> كاختصار لأمر تَصرِيف البرامج المُستخدِمة لمكتبة <code>JavaFX</code>. لاحِظ أنه من الضروري اِستخدَام المسار الكامل لكُلًا من الأمر <code>javac</code> ومجلد "lib" الخاص بمكتبة <code>JavaFX</code> أثناء تعريف الاسم المستعار. سيبدو تَعرِيفه مشابهًا لما يلي (لابُدّ من كتابته ضِمْن سطر واحد):
</p>

<pre class="ipsCode">
alias jfxc='/home/eck/jdk-11.0.7/bin/javac 
                  --module-path=/home/eck/javafx-sdk-11/lib 
                  --add-modules=ALL-MODULE-PATH'
</pre>

<p>
	بالمثل، يُمكِنك أن تُعرِّف الاسم المستعار <code>jfx</code> كاختصار لأمر تَشْغِيل البرامج المُستخدِمة لمكتبة <code>JavaFX</code>:
</p>

<pre class="ipsCode">
alias jfx='/home/eck/jdk-11.0.7/bin/java 
                  --module-path=/home/eck/javafx-sdk-11/lib 
                  --add-modules=ALL-MODULE_PATH'
</pre>

<p>
	لابُدّ أن تُضيِف تَعرِيفات الأسماء المستعارة (aliases) بالأعلى إلى ملف <code>‎.bashrc</code> بنظام لينكس وملف <code>‎.bash_profile</code> بنظام ماك بمُجلد المُستخدِم الرئيسي (home directory) لكي تَحتفِظ بها بصورة دائمة. عادةً ما يَكون ذلك الملف موجودًا، وإذا لم تَجِده، فيُمكِنك أن تُنشئه ببساطة. يُنفَّذ ذلك الملف بكل مرة تُفْتَح فيها نافذة طرفية (terminal) أيّ لن تُفعَّل أية تَعْدِيلات تُجرِيها عليه حتى تَفتَح طرفية جديدة. يبدأ اسم الملف بنقطة (period) مما يَعنِي كَوْنه ملف مَخفِي (hidden file) لا يُعرَض افتراضيًا بمُتصفِح الملفات. إذا كنت تَستخدِم نظام لينكس، يُمكِنك أن تُظهِر أية ملفات مخفية بمُتصفِح الملفات من خلال إِعدادات الضَبْط. (ألقي نظرة على قائمة "View"). ليس الأمر بنفس السهولة إذا كُنت تَستخدِم نظام ماك. في العموم، تستطيع دومًا أن تَستخدِم الأمر <code>ls -a</code> بنافذة سطر الأوامر (command line) لكي تَعرِض قائمة بأسماء الملفات الموجودة بمجلد معين بما في ذلك أية ملفات مخفية. إذا واجهتك مشكلة مع أي ملف مَخفِي (hidden file)، أَعِد تسميته ليُصبِح ملفًا عاديًا ثم عدِّله كما تشاء وأخيرًا أَعِد تسميته مرة آخرى. يُستخدَم الأمر <code>mv</code> لإعادة تسمية الملفات مثل <code>mv .bash_profile temp</code> و <code>mv temp .bash_profile</code>.
</p>

<p>
	في المقابل، لا يُوفِّر نظام ويندوز ملفًا لنافذة الأوامر <code>cmd</code> كالملفات <code>‎.bashrc</code> أو <code>‎.bash_profile</code>. كحل بديل، قد تُنشِئ ملف نص برمجي (script file) يُنفِّذ أمرًا. فمثلًا لتَصْرِيف برامج <code>JavaFX</code>، انشِئ ملفًا اسمه <code>jfxc.bat</code> يَحتوِي على سطر مُماثِل لما يلي:
</p>

<pre class="ipsCode">
javac -p C:\Users\eck\openjfx-sdk-11\lib --add-modules=ALL-MODULES-PATH $*
</pre>

<p>
	لكن بالطبع باِستخدَام مسار <code>JavaFX</code> الخاص بحاسوبك. تُمثِل <code>‎‎$*‎</code> مُدْخَلات الأمر <code>javac</code>. قد يَكُون الملف المُدْخَل موجودًا بالمجلد الحالي (current directory) أو بأي مكان آخر بمسار النظام (system path) مثل مجلد "bin" الخاص بعُدة تطوير جافا (JDK). تستطيع الآن أن تَستخدِم <code>jfxc</code> كأمر لتَصرِيف (compiling) البرامج المُستخدِمة لمكتبة <code>JavaFX</code> كالتالي:
</p>

<pre class="ipsCode">
jfxc MyJavaFXProgram.java
</pre>

<p>
	يُمكِنك أن تُطبِّق الشيء نفسه مع الأمر <code>java</code>.
</p>

<h2>
	بيئة تطوير إكلبس المتكاملة (Eclipse)
</h2>

<p>
	تَتَضمَّن بيئات التطوير المُتكاملة (Integrated Development Environment - IDE) كل شيء قد تحتاج إليه لإنشاء البرامج وتَصْرِيفها وتشْغِيلها ضِمن حزمة واحدة مُدعَّمة بواجهة مُستخدِم رُسومية (graphical user interface) مألوفة لغالبية مُستخدِمي الحاسوب. تَتَوفَّر مجموعة من بيئات التطوير المتكاملة لبرامج الجافا تتراوح من مجرد برامج بسيطة تعمل كغلاف لعُدة تطوير جافا (JDK) إلى تطبيقات معقدة تتميز بالعديد من الخاصيات. نظرًا لصعوبة تَعلُّم كُلًا من بيئات التطوير المتكاملة (IDE) ومفاهيم البرمجة نفسها في نفس الوقت، لا يُحبَّذ في العموم اِستخدَامها من قِبَل المُبرمجين المُبتدئين. سنتناول هنا بيئة تطوير إكلبس المُتكاملة (Eclipse IDE) بشيء من التفصيل وكذلك البديل الأكثر بساطة BlueJ على نحوٍ مختصر نوعًا ما. تتميز بيئات التطوير المُتكاملة (IDEs) بالكثير من السمات المفيدة حتى للمبرمج المبتدئ ولكنه عادةً ما سيتَجاهلها خاصة بالبداية.
</p>

<p>
	إذا لم تَكُن تَستخدِم نُسخة أوراكل من عُدة تطوير جافا (JDK) إصدار ٨ أو ٩ أو ١٠، فينبغي أن تَضْبُط بعض الإعدادت الآخرى لكي تَتَمكَّن من اِستخدَام إكلبس (Eclipse) مع البرامج المُستخدِمة لمكتبة <code>JavaFX</code>، وهو ما سنتناوله بالقسم الفرعي التالي. خلال هذا القسم، سنُناقش كيف يُمكِننا أن نَستخدِم إكلبس لكي نُنشِئ برامجًا تَعتمِد فقط على أصناف جافا القياسية (standard classes).
</p>

<p>
	يُمكِنك أن تُحمِّل بيئة تطوير إكلبس المُتكاملة (Eclipse IDE) من <a href="https://www.eclipse.org" rel="external nofollow">موقع إكلبس</a>. حمِّل <a href="https://www.eclipse.org/downloads/packages" rel="external nofollow">حزمة بيئة إكلبس لمطوري الجافا (Eclipse IDE for Java Developers)</a>
</p>

<p>
	إذا كنت تَستخدِم نظام ويندوز أو لينكس، سيَكُون الملف المُحمَّل بهيئة ملف أرشيفي مَضغُوط. اِستخرِج مُحتوياته إلى مجلد بأي مكان ثم اُنقُر نقرة مزدوجة على أيقونة تطبيق إكلبس (Eclipse) التي ستَجِدها بذلك المجلد لتَشْغِيل البرنامج. إذا كنت تَستخدِم نظام ماك، فسيَكُون امتداد الملف المُحمَّل هو <code>‎.dmg</code>، يُمكِنك فتحه وسحبه إلى أي مكان تُفضِّله (ربما مُجلد التطبيقات).
</p>

<p>
	إكلبس (Eclipse) هو برنامج مجاني مَكْتُوب بلغة الجافا، ويَتَطلَّب عُدة تطوير جافا (JDK) إصدار ٨ أو أحدث لذا لابُدّ أن تُثبِّت عُدة تطوير جافا (JDK) قَبْل أن تُحاوِل تَشْغِيله. ملحوظة لمُستخدمِي ماك: منذ يونيو ٢٠١٩، تَسبَّب خطأ برمجي (bug) بإكلبس (Eclipse) بمنع تَشْغِيله مع عدة تطوير جافا (JDK) إصدار ١٢، لذا إذا كنت تُريد اِستخدَام إكلبس (Eclipse)، يُفضَّل أن تَعتمِد على الإصدار ١١ من JDK إلى أن يُصلَّح ذلك الخطأ.
</p>

<p>
	سيَطلُب منك برنامج إكلبس عند تَشْغِيله لأول مرة تَخْصِيص مساحة عمل (workspace) عبارة عن مجلد لتَخْزِين الملفات التي ستَعمَل عليها. يُمكِنك أن توافق على الاسم الافتراضي أو قد تُخصِّص أي اسم آخر. في الواقع، يُمكِنك أن تَستخدِم أكثر من مساحة عمل واحدة (workspaces) ثم تختار واحدة منها عند تَشْغِيله. عند فَتْح مساحة عمل (workspace) لأول مرة، ستَظهَر شاشة ترحيب كبيرة تَتَضمَّن روابط إلى عدة دروس إلى جانب التوثيق (documentation). اِضغَط على زر "X" الموجود إلى جوار كلمة "Welcome" لإغلاق الشاشة. يُمكِنك فَتْحها لاحقًا باختيار "Welcome" من قائمة "Help".
</p>

<p>
	تَتَكوَّن واجهة برنامج إكلبس (Eclipse) الرُسومية من نافذة كبيرة مُجزَّئة إلى عدة أقسام (section) يَتَكوَّن كُلًا منها من عَرْض (view) واحد أو أكثر. يُوضِح كل عَرْض (view) نوعًا مُختلفًا من المعلومات، فيُمكِن أن يَكُون بهيئة مُحرر نصي (text editor) أو مساحة لعمليات الخَرْج والدَخْل (I/O) أو قائمة بالمشروعات الخاصة بك. إذا كان هناك أكثر من عَرْض (view) ضِمْن قسم (section) واحد، فسيَظهَر شريط نوافذ (tabs) بالجزء العلوي من ذلك القسم يَسمَح لك باختيار العَرْض (view) الذي تَرغَب بإظهاره. يُطلَق اسم "منظور (perspective)" على مجموعة عُروض (views). يَستخدِم إكلبس (Eclipse) منظورات (perspectives) مختلفة لمجموعات مختلفة من العُروض (views) تَخُص أنواعًا مختلفة من المعلومات. ستحتاج عمومًا إلى ما يُعرَف باسم "منظور الجافا (java perspective)" لتَصْرِيف البرامج وتَشْغِيلها، وهو في الواقع المنظور الافتراضي. عندما تُصبِح أكثر خبرة، ستَستخدِم على الأغلب "منظور تَنْقِيح الأخطاء (debug perspective)" للعُثور على الأخطاء الدلالية (semantic errors) بالبرامج. توجد أزرار صغيرة بشريط أدوات إكلبس (Eclipse) للتَبْدِيل بين المنظورات (perspectives) المختلفة.
</p>

<p>
	يَتَكوَّن "منظور الجافا (java perspective)" من مساحة كبيرة بمنتصف النافذة تَحتوِي على عَرْض (view) واحد أو أكثر بهيئة مُحرر نصي (text editor). في الواقع، ستُنشِي البرامج وتُعدِّلها بتلك المساحة. على الجانب الأيسر منها، ستَجِد عَرْض بهيئة مُستكْشِف حزم (package explorer) يَعرِض قائمة بمشروعات الجافا وبملفات الشيفرة المصدرية (source code). على الجانب الأيمن منها، ستَجِد عدة عروض (views) آخرى غَيْر مُهِمّة لذلك يُمكِنك أن تُغلِقها بالنَقْر على "X" الموجود بجانب اسم كُلًا منها. بالإضافة إلى ذلك، ستَجِد عدة عروض (views) آخرى مفيدة أسفل مساحة التَعْدِيل. إذا أغلقت عَرْضًا (views) مُهِمًّا عن طريق الخطأ كمُستكِشف الحزم (package explorer)، يُمكِنك أن تُظهِره مُجددًا عن طريق اختياره من القائمة الفرعية "Show View" من قائمة "Window". يُمكِنك إعادة ضَبْط النافذة بالكامل إلى محتوياتها الافتراضية عن طريق اختيار "Reset Perspective" من قائمة "Window".
</p>

<p>
	لبدء العمل على إكلبس (Eclipse)، ينبغي أولًا أن تُنشِئ مشروعًا (project): اِختر الأمر "Java Project" من القائمة الفرعية "New" بقائمة "File". ستَظهَر نافذة أمامك، املأ حقل "اسم المشروع (Project Name)" بأي شيء تريده ثم اِضغَط على زر "Finish". قد يسألك إكلبس عما إذا كنت تُريد أن تُنشِئ ملف <code>module-info.java</code>، ولأننا لن نَستخدِم أية وحدات (modules) بأي برنامج نهائيًا، اُنقر دومًا على "Don't Create". اُنظر القسم الفرعي ٤.٦.٤ لمزيد من المعلومات عن الوحدات (modules). لابُدّ أن يَظهَر المشروع الآن بعَرْض (view) "مُستكِشف الحزم (package explorer)". اُنقُر على علامة المربع أو المثلث الصغيرة الموجودة إلى جانب اسم المشروع لترى مُحتوياته. إذا كنت تَستخدِم الإعدادات الافتراضية، ينبغي أن تَجِد مُجلد اسمه "src" مُخصَّص لملفات الشيفرة المصدرية لذلك المشروع، وستَجِد أيضًا "مكتبات بيئة تّنْفيذ الجافا (JRE System Library)" مُكوَّنة من مجموعة من الأصناف القياسية المَبنية مُسْبَقًا (standard built-in classes).
</p>

<p>
	لتَشْغيِل أي من برامج الجافا المَعرُوضة هنا، ينبغي أن تَنسَخ ملف الشيفرة المصدرية (source code) للبرنامج إلى مشروع الجافا بتطبيق إكلبس (Eclipse). إذا كُنت قد حمَّلت ذلك الملف إلى حاسوبك، تستطيع ببساطة أن تَنسخُه وتُلصقه إلى نافذة إكلبس كما يلي: اُنقُر بزر الفأرة الأيمن على أيقونة الملف ثُمَّ اِختَر "اِنسَخ (Copy)" من القائمة ثُمَّ اُنقُر بزر الفأرة الأيمن على مُجلد "src" بالمشروع بنافذة إكلبس واِختَر "اِلصِق (Paste)". تَأكَّد من لَصْقُه بمُجلد "src" لا مجلد المشروع نفسه، فالملفات الموجودة خارج مُجلد "src" لا تُعامَل كملفات شيفرة مصدرية. بدلًا من ذلك، يُمكِنك أن تَسحَب أيقونة الملف من نافذة مُتصفِح الملفات إلى مجلد "src" بنافذة إكلبس.
</p>

<p>
	لكَوْن الأمثلة هنا مُعتمِدة على الصَنْف <code>TextIO</code> غَيْر القياسي، ينبغي إذًا أن تُضيِف الملف <code>TextIO.java</code> إلى المشروع بحيث يَقَع ضِمْن حزمة اسمها <code>textio</code>. إذا كُنت قد حمَّلت ذلك الملف إلى حاسوبك بمُجلد اسمه "textio" كما أَوضَحنا مُسْبَقًا، يُمكِنك نَسخُه ولَصقُه إلى مجلد المشروع "src". بدلًا من ذلك، يُمكِنك أن تُنشِئ الحزمة <code>textio</code> باختيار الأمر "New/Package" من قائمة "File". سيُنشِئ ذلك مجلدًا جديدًا اسمه "textio" بالمشروع، وعليه، تستطيع نَسْخ الملف <code>TextIO.java</code> بداخله. أيًا كانت الطريقة المُستخدَمة، لابُدّ أن يَحتوِي مجلد المشروع "src" على الملف <code>TextIO.java</code> داخل مجلد ثانوي اسمه هو <code>textio</code>. إذا وَضعَت ملفًا بمكان غَيْر صحيح عن طريق الخطأ، يُمكِنك سَحْبه من مكانه إلى أي مكان آخر بـ"مستكشف الحزم (package explorer)".
</p>

<p>
	بَعْدما تُضيِف برنامج الجافا إلى مشروعك، اُنقُر نقرة مزدوجة على اسم الملف الموجود بعَرْض "مُستكِشف الحزم (package explorer)" لفَتْح البرنامج ثم اُنقُر بزر الفأرة الأيمن على نافذة المُحرّر أو على اسم الملف بمُستكِشف الحزم واِختَر "Java Application" من القائمة الفرعية "Run As" لتّنْفيذ البرنامج. إذا كان البرنامج مُصمَّمًا ليَكْتُب إلى الخَرْج القياسي (standard output)، فسيَظهَر الخَرْج بالعَرْض "Console" بالقسم الواقع أسفل المُحرّر بنافذة إكلبس. إذا كان البرنامج يَستخدِم أي من الصَنْفين <code>TextIO</code> أو <code>Scanner</code> لقراءة أية مُدْخَلات (input)، ستَضطّر إلى كتابة المُدْخَلات المطلوبة بالعَرْض "Console". لاحِظ أنك ستحتاج للضَغْط على ذلك العَرْض قبل البدء بالكتابة لكي تتأكَّد من إرسال المحارف التي ستَكْتُبها إلى القسم الصحيح من نافذة إكلبس. تَتَوفَّر طريقة أسهل لتَشْغيل البرنامج: اِضغَط على زر "شَغِّل (Run)" بشريط أدوات إكلبس. وفقًا للسياق، سيؤدي ذلك إلى تَشْغِيل البرنامج المَعرُوض بنافذة المُحرّر أو البرنامج المُختار بمُستكِشف الحزم (package explorer) أو أحدث برنامج كان مُشغَّلًا للتو. ملحوظة: عندما تُشغِّل برنامجًا بإكلبس، فليس هناك خُطوة مُنفصِلة لعملية التَصرِيف (compilation) حيث تُصرَّف ملفات البرنامج أتوماتيكيًا.
</p>

<p>
	يُمكِنك أن تُضيِف أكثر من برنامج إلى نفس المشروع أو قد تُنشِئ مشروعات إضافية لتَنْظِيم العمل على نحو أفضل. تَذكَّر دومًا أن تُضيِف نُسخة من الصَنْف <code>TextIO.java</code> بمجلد اسمه <code>textio</code> بأي مشروع يَستخدِمه.
</p>

<p>
	إذا كنت تريد أن تُنشِئ برنامج جافا جديد بإكلبس، لابُدّ إذًا من أن تُنشِئ صنفًا (class) جديدًا: اُنقُر بزر الفأرة الأيمن على اسم المشروع بمُستكِشف المشروع (Project Explorer) ثم اُنقُر على القائمة الفرعية "New" ثم اِختَر "Class". بدلًا من ذلك، تستطيع أن تَنقُر على واحدة من الأيقونات الصغيرة بصندوق الأدوات أعلى نافذة إكلبس. بالنافذة المفتوحة، اُكْتُب اسم الصنف (class) -وليس اسم ملف الشيفرة المصدرية- الذي تريد أن تُنشئه بشَّرط أن يَكُون عبارة عن اسم مُعرف هوية (identifier) صالح. تَتَضمَّن النافذة صندوق إدخال آخر بعنوان "حزمة (Package)" حيث يُمكِنك أن تُخصِّص اسم الحزمة (package) المطلوب إضافة الصَنْف إليها. تَستخدِم غالبية الأمثلة بهذا الكتاب "الحزمة الافتراضية (default package)". اُترك صندوق الإدخال فارغًا لكي تَستخدِم الحزمة الافتراضية، ولكن يُمكِنك أيضًا أن تُخصِّص اسم حزمة إذا أردت. أخيرًا، اضغط على زر "Finish" لإنشاء الصنف، والذي ينبغي أن يَظهَر بالمجلد "src" داخل مجلد فرعي مُناظِر للحزمة (package) المُخصَّصة كما سيُفتَح الملف الجديد أتوماتيكيًا بمساحة التعديل (editing area) لكي تََتَمكَّن من البدء بالكتابة.
</p>

<p>
	يُوفِّر إكلبس خاصيات مُتعدّدة ستُساعدك حتمًا أثناء كتابة الشيفرة. على سبيل المثال، يَظهَر خط أحمر خشن أسفل أي خطأ في بناء الجملة (syntax error)، وفي بعض الحالات، تَظهَر علامة خطأ إلى الجانب الأيسر من نافذة المُحرر، والتي تَعرِض وصفًا للخطأ إذا حومت (hover) مؤشر الفأرة عليها أو على الخطأ نفسه. لا ينبغي أن تُحاوِل التَخلُّص من كل خطأ يَظهَر أثناء كتابة الشيفرة خاصة وأن بعضها يَختفِي تلقائيًا بَعْدما تُكمِل كتابة البرنامج. إذا كانت علامة الخطأ بهيئة مصباح كهربي، يَعنِي ذلك أن إكلبس يَعرِض محاولة لإصلاح الخطأ أتوماتيكيًا. اِضغَط على علامة المصباح أو حوم (hover) مؤشر الفأرة على الخطأ الفعليّ للحصول على قائمة بالحلول المُحتمَلة. يُمكِنك الضَغْط على أي منها لتطبيق الحل. على سبيل المثال، إذا اِستخدَمت مُتْغيِّرًا (variable) بدون أن تُصرِّح عنه، سيَعرِض إكلبس إمكانية التَصْرِيح (declare) عنه أتوماتيكيًا مما يعني السماح لإكلبس بكتابة أنواع محددة من الشيفرة. ملحوظة: لن تَفهَم جميع الحلول التي يقترحها إكلبس حتى تَتَعلَّم المزيد عن لغة الجافا لذا لا تُحاوِل تطبيق أي حل لا تفهمه فعادةً ما سيَجعَل ذلك الأمور اسوأ في النهاية.
</p>

<p>
	يَعثُر إكلبس (Eclipse) أيضًا على أخطاء التهجئة بالتعليقات (comments) ويَضَع خطًا أحمرًا خشنًا أسفلها. حوم مؤشر الفأرة على واحدًا من تلك الأخطاء لتَجِد قائمة بالحلول الصحيحة المُحتمَلة.
</p>

<p>
	يتميز إكلبس بخاصية أخرى أساسية هي مُساعد المُحتوى (content assist) المُستخدَمة لعَرْض التكميلات المُحتمَلة لما تَكْتبه بتلك اللحظة. يُمكِنك استدعاء المساعد بالضَغْط على زري "Control-Space". على سبيل المثال، إذا كُنت تَكْتب جُزءًا من مُعرِّف هوية (identifier) ثم ضَغْطت على زري "Control-Space"، ستَظهَر قائمة بكل مُعرِّفات الهوية المتاحة البادئة بالمحارف التي كُنت قد كَتْبَتها. اِستخدِم مفتاحي الأسهم (arrow keys) "لأعلى" و "لأسفل" لاختيار أي عنصر بالقائمة ثم اضغط "Enter". يُمكِنك أيضًا أن تَنقُر على أي عنصر باِستخدَام الفأرة لاختياره أو قد تَضغَط على "Escape" لإخفاء القائمة. إذا ضَغطَت على "Control-Space" وكان هنالك احتمالًا تَكْميليًا واحدًا، فسيُكتَب أتوماتيكيًا. يظهر مساعد المحتوى (content assist) تلقائيًا بصورة افتراضية عند كتابة نقطة أو عدة محارف آخرى، فمثلًا، إذا كَتَبَت "TextIO.‎" ثم اِنتظرت لجزء من الثانية، ستَظهَر قائمة بجميع البرامج الفرعية (subroutines) المُعرََّفة بالصَنْف <code>TextIO</code>. يُمكِنك إلغاء التَفْعِيل التلقائي لتلك الخاصية من خلال إعدادات إكلبس (جافا &gt; المحرر &gt; مساعد المحتوى). ما يزال بإمكانك استدعائه يدويًا باستخدام زري "Control-Space".
</p>

<p>
	بمُجرد أن يُصبِح برنامجك خالٍ من الأخطاء، يُمكِنك أن تُشغِّله كما أوضحنا بالأعلى. إذا وجدت مشكلة عند تَشْغِيله، عُد إلى المُحرّر لتجُرِي التعديلات المطلوبة ثُمَّ جَرِّب تَشْغِيله مرة آخرى.
</p>

<h2>
	استخدام <code>JavaFX</code> ببيئة تطوير إكلبس (Eclipse)
</h2>

<p>
	إذا كنت تَستخدِم إصدارً من عُدة تطوير جافا (JDK) لا يَحتوِي على مكتبة JavaFX، فلابُد من أن تَضبُط مشروعات إكلبس لكي تَتَمكَّن من اِستخدَام تلك المكتبة. تَتَوفَّر في الواقع الكثير من الطرائق للقيام بذلك. سنَعرِض واحدة منها هنا والتي ليست بالضرورة أصحها أو أفضلها، فنحن فقط نحتاج إلى تَطْوِير بعض البرامج البسيطة المُعتمِدة على JavaFX. سنَضبُط إحدى إعدادات مساحة العمل (workspace) بإكلبس (Eclipse). تَعمَل هذه الطريقة مع كُلًا من الإصدار ١١ من الجافا وبيئة إكلبس (Eclipse) حتى إصدار يونيو ٢٠١٩. قد لا تتوافق هذه الطريقة مع الإصدارات الأحدث من كُلًا منهما.
</p>

<p>
	اِختَر الأمر "Preferences" من قائمة "Windows" بنظامي لينكس وويندوز أو من قائمة "Eclipse" بنظام ماك لفَتْح نافذة الإِعدادات المُفضَّلة. اُنقُر على علامة المربع أو المثلث الصغيرة الموجودة إلى جانب كلمة "Java" بالقائمة على يسار النافذة لفَتْح قسم "Java" ثم اُنقُر على "بيئات تّنْفيذ جافا المُثبَّتة (Installed JREs)". ستَظهَر قائمة ببيئات الجافا (Java environments) التي تَعرَّف عليها إكلبس بالفعل. يُمكِنك القيام بأمر من اثنين: اِضغَط على الزر "Add" لإضافة بيئة تّنْفيذ جافا (JRE) جديدة أو اِختَر واحدة من تلك الموجودة بالقائمة واِضغَط على "Edit". إذا اِختَرت إضافة بيئة تّنْفيذ جديدة، سيَظهَر صندوق يسألك عن نوع بيئة التّنْفيذ (JRE Type)، اِختَر "Standard VM" ثم اِضغَط على "Next". سيَظهَر صندوق مُشابه للصورة بالأسفل. في المقابل، إذا اِختَرت التَعْدِيل على بيئة تّنْفيذ (JRE) موجودة، فإن الحقلين "مسار بيئة التّنْفيذ (JRE Home)" و "اسم بيئة التنفيذ (JRE name)" سيَكُونا مملوئين بالفعل أما حقل "مكتبات بيئة تّنْفيذ الجافا (JRE system libraries)" فسيَكُون فارغًا.
</p>

<p style="text-align: center;">
	<img alt="001Eclipse_fx.png" class="ipsImage ipsImage_thumbnailed" data-fileid="51795" data-unique="1qajjk164" src="https://academy.hsoub.com/uploads/monthly_2020_10/001Eclipse_fx.png.c9383d671027024d58c4fbde3d6ec075.png"></p>

<p>
	إذا اِختَرت إضافة بيئة تّنْفيذ جافا (JRE) جديدة، ستَحتاج إلى تَخْصِيص "مسار بيئة التّنْفيذ (JRE Home)". لابُدّ أن يَحتوِي المجلد الذي يُشير إليه ذلك المسار على مجلد "bin" بعُدة تطوير جافا. اِضغَط على زر "Directory" لفَتْح مُتصفِح الملفات ثم اِختَر المجلد. يُمكِنك اختيار عُدة تطوير جافا (JDK) مُثبَّتة على الحاسوب أو لا. بالمثال المُوضَّح بالصورة، كانت عُدة تَطوِير جافا (JDK) مُثبَّتة على نظام لينكس. إذا كنت تَستخدِم ويندوز أو لينكس، اِختَر مجلد JDK الرئيسي أما إذا كنت تَستخدِم نظام ماك، فاِختَر مجلد "Home" الموجود بمجلد "Content" الموجود بمجلد JDK الرئيسي أي لابُدّ أن يَنتهِي المسار بـ"‎/Content/Home". إذا أَدْخَلت مُجلد عُدة تطوير (JDK) صالح، فسيَملأ إكلبس كُلًا من "اسم بيئة التّنْفيذ (JRE name)" و"مكتبات النظام (system library)" تلقائيًا.
</p>

<p>
	لابُدّ أن تَكون مكتبة <code>JavaFX</code> مُتاحة للبرنامج خلال زمني التَصْرِيف (compile time) والتَشْغِيل (run time). بالنسبة لزمن التصريف (compile time)، يُمكِنك أن تُضيِف ملفات المكتبة <code>‎.jar</code> إلى مكتبات النظام (system libraries): اِضغَط على زر "Add External JARs" ثم اِنتقِل إلى مجلد "lib" الموجود بمجلد عُدة تطوير جافا إف إكس (JavaFX SDK) المُحمَّلة أو المُثبَّتة. ستَجِد سبعة ملفات مُنتهيّة بالامتداد <code>‎.jar</code>، اِخترها جميعًا ثم اُنقُر على "OK". ينبغي أن تَظهَر جميعًا بقائمة "مكتبات بيئة تّنْفيذ الجافا (JRE system libraries)".
</p>

<p>
	بالنسبة لزمن التَشْغِيل (run time)، ينبغي أن تُضيِف عدة وسائط (arguments) إلى صندوق "Default VM arguments" يدويًا. يَتَضمَّن ذلك الصندوق عدة خيارات ستُضَاف إلى الأمر <code>java</code> عندما تُشغِّل برنامجًا باِستخدَام تلك النُسخة من عُدة التطوير (JDK). ينبغي أن تَكْتُب نفس الخيارات التي كنت تَستخدِمها مع سطر الأوامر (command line) كما ناقشنا بالأعلى، فمثلًا، قيمة الخيار <code>‎-p</code> أو <code>‎--module-path</code> هي مسار المجلد "lib" الخاص بمكتبة <code>JavaFX</code> أما قيمة الخيار <code>‎--add-modules</code> فيُمكِن أن تَكُون "ALL-MODULE-PATH".
</p>

<p>
	عندما تَنتهِي من ضَبْط كل شيء، اُنقُر على "Finish" ثم اُنقُر على "Apply and Close" بنافذة "الإعدادات المُفضَّلة (Preferences)" الرئيسية. عندما تُنشِئ مشروع جافا جديد بمساحة العمل (workspace)، اِختَر بيئة التّنْفيذ (JRE) التي أَضفتها أو عدَّلتها للتو بنافذة إِنشاء المشروع. ينبغي الآن أن تَكُون قادرًا على اِستخدَام مكتبة <code>JavaFX</code> ضِمْن ذلك المشروع. إذا واجهتك مشكلة، اِفحَص إعدادات بيئة تّنْفيذ الجافا (JRE).
</p>

<p>
	ملحوظة: ليس هنالك أي ضرر من اِستخدَام بيئة تّنفيذ (JRE) مُدعِّمة لمكتبة <code>JavaFX</code> مع البرامج العادية التي لا تَستخدِم تلك المكتبة. بتعبير آخر، يُمكِنك أن تَستخدِم نفس الإعدادات السابقة مع كل البرامج التي سنتناولها لاحقًا.
</p>

<h2>
	بيئة التطوير BlueJ
</h2>

<p>
	تُعدّ بيئة التطوير BlueJ مُوجَّهة للمبتدئين الراغبين بتَعلُّم البرمجة. هي في العموم أقل تعقيدًا بكثير من بيئة إكلبس (Eclipse) ولكنها مع ذلك تُوفِّر مجموعة من الخاصيات المفيدة للأغراض التعليمية. يُمكِنك أن تُحمِّل بيئة BlueJ من <a href="https://bluej.org" rel="external nofollow">موقعها الرسمي</a>. يتوافق إصدارها الحالي مع الإصدار ١١ من كُلًا من الجافا و جافا إف إكس (JavaFX) كما يَتَوفَّر إصدار سابق متوافق مع الإصدار ٨ من الجافا. عندما تُشغِّل BlueJ لأول مرة، سيَطلُب منك إدخال مسار كُلًا من JDK و JavaFX. تستطيع الآن أن تُصرِّف البرامج المُستخدِمة لمكتبة <code>JavaFX</code> وتُشغِّلها باستخدام بيئة BlueJ.
</p>

<p>
	يُمكِنك أن تُنشِئ مشروعًا جديدًا باختيار الأمر "New Project" من قائمة "Project". لاحِظ أن المشروع ببيئة BlueJ عبارة عن مجلد. عندما تُنشِئ أي مشروع جديد، سيتعيَّن عليك اختيار اسم ذلك المجلد. ستُنشِئ بيئة BlueJ المجلد وستَفتَح نافذة تَعرِض مُحتوياته بهيئة أيقونات. يُمكِنك أن تُضيِف أي ملف <code>‎.java</code> إلى المشروع بسَحبُه من نظام الملفات (file system) إلى النافذة. سيُنسَخ الملف إلى مجلد المشروع وسيَظهَر أيضًا على النافذة. في المقابل، يُمكِنك أن تَنسَخ أي ملف مُباشرةً إلى مجلد المشروع، ولكنك لن تراه بيئة BlueJ حتى تُعيد فَتْح المشروع. عندما تُعيد تَشْغِيل بيئة BlueJ، سيَظهَر آخر مشروع كُنت تَعمَل عليه، ولكن يُمكنِك طبعًا فَتْح أي مشروع آخر من أحد الأوامر (command) بقائمة "Project".
</p>

<p>
	ستَجِد زرًا بنافذة المشروع لإنشاء صَنْف (class) جديد. عند النَقْر عليه، يُضيِف BlueJ أيقونة صَنْف إلى النافذة ويُنشِئ ملف شيفرة مصدرية بامتداد <code>‎.java</code> بمُجلد المشروع لكنه لا يَفتَحه تلقائيًا. يُمكِنك أن تَنقُر على أيقونة أي ملف نقرةً مزدوجة لفَتْحه، وسيَظهَر عندها مُحرّر يَعرِض مُحتوياته ضِمْن نافذة مُنفصلة. ستُلاحِظ أن أي صَنْف (class) جديد يَتَضمَّن افتراضيًا شيفرة لن تَرغَب بها عادةً. يُمكِنك حَذفَها وإضافة البرنامج <code>main()‎</code> بدلًا منها. يَختلِف مُحرّر بيئة BlueJ عن مُحرّر Eclipse بعدة أمور: أولًا، لا يَعرِض مُحرّر BlueJ أية أخطاء (errors) أثناء كتابة الشيفرة وإنما يُبلِّغ عنها عند محاولة تَصْرِيف (compile) البرنامج. ثانيًا، لا يَقترِح المُحرّر أية حلول تلقائية لأي من تلك الأخطاء. ثالثًا، يُوفِّر مُحرّر BlueJ مُساعد مُحتوى (content assist) بدائي يَقْتصِر دوره على عَرْض البرامج الفرعية (subroutines) المُعرَّفة بصَنْف (class) أو كائن (object). اِضغَط على زري "Control-Space" لاستدعائه بَعْد كتابة النقطة التي تأتي بَعْد اسم الصَنْف أو الكائن.
</p>

<p>
	تَحتوِي نافذة المُحرّر على زر لتَصْرِيف (compile) البرنامج المَعرُوض بينما تَحتوِي نافذة المشروع على زر آخر لتَصْرِيف جميع الأصناف (classes) ضِمْن المشروع.
</p>

<p>
	لابُدّ أن تُصرِّف (compile) البرنامج أولًا لكي تَتَمكَّن من تَشْغِيله. اُنقُر بزر الفأرة الأيمن على أيقونة البرنامج المُصرَّف. ستَظهَر قائمة، اِختَر منها "void main(String[] args)‎" لتَشْغِيل البرنامج ثم اُنقُر على "OK". ستُفتَح بَعْد ذلك نافذة مُنفصلة تَستقبِل مُدْخَلات البرنامج وتَعرِض مُخْرَجاته.
</p>

<p>
	يُمكِنك أن تُشغِّل أي برنامج فرعي (subroutine) وليس فقط البرنامج <code>main</code> ببيئة التَطوِير BlueJ، وهو ما يُعدّ واحدًا من أفضل مميزاتها. إذا كان لديك صَنْف (class) يَحتوِي على برامج فرعية (subroutines) آخرى غير البرنامج <code>main</code>، فستَجِدها ضِمْن القائمة المَعرُوضة بَعْد النَقْر بزر الفأرة الأيمن على أيقونة الصَنْف. إذا كان البرنامج (routine) يَتَطلَّب أية مُعاملات (parameters)، فسيُسمَح لك بإِدْخَالها عَبْر نافذة، وإذا كان دالة (function) -أي يُعيد قيمة-، فسيَظهَر صندوق آخر بَعْد تّنْفِيذ البرنامج ليُخبرِك بقيمته المُعادة (return value) مما يَسمَح لك بإجراء اختبار لأي برنامج فرعي (subroutine) بشكل مُستقِل. بالإضافة إلى ذلك، تستطيع أيضًا أن تُنشِئ كائنًا (object) من صَنْف معين ببيئة BlueJ، وستَظهَر بَعْدها أيقونة للكائن (object) أسفل نافذة المشروع. يُمكِنك أن تَنقُر بزر الفأرة الأيمن على أيقونة الكائن لتَحصُل على قائمة بجميع البرامج الفرعية (subroutines) المُعرَّفة بداخله. بالطبع لن يَكُون ذلك مفيدًا لك حتى نَصِل إلى الفصل الخامس حيث سنَتَعلَّم البرمجة كائنية التوجه (object-oriented programming).
</p>

<h2>
	الحزم (packages)
</h2>

<p>
	يَقَع أي صَنْف (class) بالجافا ضِمْن شيء يُطلق عليه اسم "حزمة (package)". تُعرَّف الأصناف التي لا يُعلَّن صراحةً عن وقوعها ضِمْن حزمة داخل "الحزمة الافتراضية (default package)" تلقائيًا. تَقَع جميع أصناف الجافا القياسية (standard classes) ضِمْن حزم مُسمَاة (named packages)، فمثلًا، الأصناف <code>String</code> و <code>System</code> مُعرَّفة ضِمْن حزمة <code>java.lang</code>، والتي تُستورَد (import) جميع أصنافها تلقائيًا إلى أي ملف جافا. في المقابل، ينبغي أن تَستخدِم المُوجِّه <code>import</code> لاستيراد الأصناف المُعرَّفة بأي حزم آخرى غَيْر حزمة <code>java.lang</code>. على سبيل المثال، يَقَع الصَنْف <code>TextIO</code> بحزمة اسمها <code>textio</code> لذا ينبغي أن تَستورِدها إلى أي برنامج يرغب باِستخدَامها. سنُناقش الحزم (packages) على نحو مُفصَّل بالقسم ٤.٦. تحتاج الآن فقط إلى مَعرِفة بعض الحقائق البسيطة.
</p>

<p>
	وفقًا للقواعد الإرشادية الرسمية للجافا، لا يُنصَح باِستخدَام الحزمة الافتراضية (default package)، ولكننا سنَعتمِد عليها بغالبية الأمثلة؛ لأنه من الأسهل دومًا للمبرمجين المبتدئين تَجنُّب أي حديث عن الحزم (packages) قَدْر الإمكان. إذا كنت تُنشِئ صنفًا (class) وحَاوَل إكلبس (Eclipse) أن يَضَعه ضِمْن حزمة، يُمكِنك حَذْف اسم الحزمة من نافذة إنشاء الصَنْف لتُجبره على اِستخدَام الحزمة الافتراضية (default package). في المقابل، إذا كان لديك صَنْف داخل حزمة (package) بالفعل، فستبدأ شيفرة ذلك الصَنْف بسطر يُخصِّص اسم الحزمة التي يَقَع ضِمْنها الصَنْف، فمثلًا، إذا كان الصَنْف بحزمة اسمها <code>test.pkg</code>، فسيَكُون أول سطر من ملف الصَنْف كالتالي:
</p>

<pre class="ipsCode">
package test.pkg;
</pre>

<p>
	على سبيل المثال، يبدأ ملف الشيفرة المصدرية للصَنْف <code>TextIO</code> بالسطر <code>package textio;‎</code>. لقد اِختَرنا تَعرِيف الصَنْف <code>TextIO</code> ضِمْن حزمة مُخصَّصة لأنه لا يُمكِن لأي صَنْف (class) يَقَع ضِمْن حزمة (package) غَيْر افتراضية أن يَستخدِم صَنْفًا من الحزمة الافتراضية (default package) أي إذا كان الصَنْف <code>TextIO</code> ضِمْن الحزمة الافتراضية، فيُمكِنك اِستخدَامه بالبرامج الواقعة ضِمْن الحزمة الافتراضية فقط. في الواقع، لقد كان الصَنْف <code>TextIO</code> مُعرَّفًا داخل الحزمة الافتراضية (default package) بالنُسخ الأقدم من هذا الكتاب.
</p>

<p>
	ملحوظة: ستُواجِه بعض التَعْقيدات إذا استخدَمت الحزم (packages) ببيئة سطر الأوامر (command-line environment). فلنَفْترِض مثلًا أنك عرَّفت برنامجًا ضِمْن حزمة اسمها <code>text.pkg</code>، لابُدّ إذًا أن يَقَع ملف ذلك البرنامج بمجلد فرعي اسمه "pkg" داخل مجلد آخر اسمه "test" والذي يَقَع بدوره داخل مُجلد العمل الرئيسي. في نفس الوقت، لابُدّ أن تَعمَل بمجلد العمل الرئيسي (main directory) أثناء تَصرِيف أي برنامج أو تّنْفِيذه. لذا عندما تُصرِّف (compile) ملف الشيفرة المصدرية لذلك البرنامج، ستَضطّر إلى كتابة اسم المجلد. على سبيل المثال، لتَصرِيف البرنامج الوَاقِع ضِمْن الحزمة <code>test.pkg</code>، ستَضطّر إلى اِستخدَام الأمر <code>javac test/pkg/ClassName.java</code> إذا كنت تَستخدِم لينكس أو ماك أو الأمر <code>javac test\pkg\ClassName.java</code> إذا كنت تَستخدِم ويندوز. بالنسبة لتّنْفِيذ البرنامج، فستَستخدِم الأمر <code>java test.pkg.ClassName</code> مع نقطة تَفصِل اسم الحزمة (package) عن اسم الصَنْف (class).
</p>

<h2>
	الأمر <code>jshell</code>
</h2>

<p>
	تُعدّ أداة سطر الأوامر <code>jshell</code> جزءًا قياسيًا من عُدة تطوير جافا (JDK) إصدار ٩ أو أحدث. إذا كان لديك أيًا من تلك الإصدارات وتستطيع اِستخدَام الأمرين <code>java</code> و <code>javac</code> بسطر الأوامر (command line)، فبإمكانك أيضًا اِستخدَام أداة <code>jshell</code>. إذا كنت تَستخدِم نظام ماك، فقد تحتاج إلى تَخْصِيص المسار الكامل للملف التّنْفيذي <code>jshell</code> الموجود بمُجلد "bin" بعُدة تَطوِير جافا. يَسمَح لك الأمر <code>jshell</code> بكتابة شيفرة جافا وتّنفِيذها دون الحاجة لإنشاء ملف <code>‎.java</code> وكتابة البرنامج <code>main</code>. اُكتُب الأمر <code>jshell</code> بنافذة سطر الأوامر لتَشْغِيله. ستَحصُل بَعْدها على محث الأمر <code>jshell</code> حيث ستَتَمكَّن من كتابة تَعْليمَة (statement) أو تعبير (expression) بالجافا. إذا أَدْخَلت تَعْليمَة، فإنها ستُنفَّذ أما إذا أَدْخَلت تعبيرًا، فستُطبَع قيمته. لاحِظ أنك لا تحتاج إلى كتابة فاصلة منقوطة (semicolon) بنهاية السطر. يَعرِض المثال التالي جلسة (session) قصيرة لاِستخدَام الأمر <code>jshell</code>:
</p>

<pre class="ipsCode">
$ jshell
|  Welcome to JShell -- Version 11.0.7
|  For an introduction type: /help intro

jshell&gt; System.out.println("Hello World")
Hello World

jshell&gt; int x = 42
x ==&gt; 42

jshell&gt; x * x
$3 ==&gt; 1764

jshell&gt; /exit
|  Goodbye
</pre>

<p>
	ستُساعدك أداة <code>jshell</code> بلا شك بينما تَتَعلَّم الجافا وتُجرِّب مميزاتها، ولكننا لن نتعمَّق في الحديث عنها. يُمكِنك مع ذلك الإطلاع على <a href="https://docs.oracle.com/en/java/javase/11/jshell/introduction-jshell.html" rel="external nofollow">توثيقها بموقع أوراكل</a>.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c2/s6.html" rel="external nofollow">Section 6: Programming Environments</a> من فصل Chapter 2: Programming in the Small I: Names and Things من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1020</guid><pubDate>Wed, 14 Oct 2020 13:08:03 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x628;&#x64A;&#x631;&#x627;&#x62A; (expressions) &#x641;&#x64A;  &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AA%D8%B9%D8%A8%D9%8A%D8%B1%D8%A7%D8%AA-expressions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1019/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/12.png.86aae4882da1914248cf6c6634295e1b.png" /></p>

<p>
	يُلقِي هذا القسم نظرة على التعبيرات (expressions) المُستخدَمة لتمثيل قيمة أو حسابها. قد يكون التعبير (expression) بهيئة قيمة مُصنَّفة النوع (literal) أو مُتْغيِّر (variable) أو استدعاء دالة (function call) أو مجموعة من تلك الأشياء مُجمَّعة معًا بعوامل (operators) مثل <code>+</code> و <code>&gt;</code>. يُمكِنك أن تُسنِد (assign) قيمة تعبير إلى مُتْغيِّر (variable) أو تُمرِّرها كمُعامل (parameter) أثناء استدعاء برنامج فرعي (subroutine call) أو تَدمِجها مع قيم آخرى ضِمْن تعبير آخر أكثر تعقيدًا. يمكنك أيضًا أن تتجاهلها ببعض الحالات إذا كان هذا ما تريد أن تفعله وهو أمر شائع أكثر مما قد تَظُنّ. تُعدّ التعبيرات في العموم جزءًا أساسيًا من البرمجة، ولقد كان تَعامُلنا معها حتى الآن غير رسمي نوعًا ما، ولكننا سنناقشها تفصيليًا خلال هذا القسم باستثناء بعض العوامل (operators) الأقل استخدامًا. تُعدّ كُلًا من القيم المُجرّدة مُصنَّفة النوع (literals) مثل <code>674</code> و <code>3.14</code> و <code>true</code> و <code>X</code>، والمُتْغيِّرات، واستدعاءات الدوال من أبسط اللبنات الأساسية بالتعبيرات. ينبغي أن تَتَذكَّر أن أي دالة (function) هي عبارة عن برنامج فرعي (subroutine) يُعيد قيمة، ولقد تَعرَّضنا بالفعل لعدة أمثلة منها برامج (routines) الإِدْخَال المُعرَّفة بالصنف <code>TextIO</code> وكذلك الدوال الرياضية بالصَنْف <code>Math</code>.
</p>

<p>
	يَحتوِي الصَنْف <code>Math</code> على مجموعة من الثوابت (constants) الرياضية التي يُمكِن اِستخدَامها ضِمْن أي تعبير رياضي مثل الثابت <code>Math.PI</code> المُمثِل لنسبة محيط أي دائرة إلى طول قُطرها <code>π</code>، وكذلك الثابت <code>Math.E</code> المُمثِل لقيمة أساس اللوغاريتم الطبيعي <code>e</code>. تلك الثوابت (constants) هي عبارة عن مُتْغيِّرات أعضاء (member variables) من النوع <code>double</code> مُعرَّفة بالصَنْف <code>Math</code>، ولأن القيم التي تُمثِلها تلك الثوابت الرياضية تَتَطلَّب عددًا لا نهائيًا من الأرقام لتَخْصِيصها بدقة، اِستخدَمنا أعدادًا تَقْرِيبية لقيم تلك الثوابت. بالإضافة إلى ذلك، يُعرِّف الصَنْف القياسي <code>Integer</code> ثوابتًا (constants) مُتْعلِّقة بالنوع <code>int</code>، فمثلًا، يُمثِل الثابت <code>Integer.MAX_VALUE</code> أكبر عدد يُمكِن للنوع <code>int</code> أن يَحْمله ويُساوِي <code>2147483647</code> بينما يُمثِل الثابت <code>Integer.MIN_VALUE</code> أصغر عدد يُمكِن حَمْله ويُساوِي <code>‎-2147483648</code>. بالمثل، يُعرِّف الصَنْف <code>Double</code> ثوابتًا مُتْعلِّقة بالنوع <code>double</code> فمثلًا يُمثِل الثابت <code>Double.MAX_VALUE</code> أكبر قيمة يُمكِن للنوع <code>double</code> أن يَحملها بينما يُمثِل الثابت <code>Double.MIN_VALUE</code> أصغر قيمة موجبة يُمكِن حَمْلها كما يُعرِّف الصَنْف ثوابتًا آخرى تُمثِل كُلًا من القيمتين اللانهائيتين <code>Double.POSITIVE_INFINITY</code> و <code>Double.NEGATIVE_INFINITY</code> وكذلك القيمة غَيْر المُعرَّفة <code>Double.NaN</code>. فمثلًا، قيمة <code>Math.sqrt(-1)‎</code> هي <code>Double.NaN</code>.
</p>

<p>
	في الواقع، القيم مُصنَّفة النوع (literals) والمُتْغيِّرات (variables) واِستدعاءات الدوال (function calls) هي مُجرّد تعبيرات (expressions) بسيطة يمكنك دَمْجها عن طريق عوامل (operators) لتَحصُل على تعبيرات أكثر تعقيدًا. تَتَضمَّن تلك العوامل كُلًا من العامل <code>+</code> لحساب حاصل مجموع عددين والعامل <code>&gt;</code> لموازنة قيمتين. عندما تَستخدِم أكثر من عامل ضِمْن تعبير (expression)، فعادةً ما تكون الكيفية التي ستُجمَّع بها تلك العوامل -فيما يُعرَف باسم أولوية (precedence) العوامل- لتَحْصِيل قيمها مَحلّ حيرة وتساؤل. فمثلًا، إذا كان لدينا تعبير مثل <code>A + B * C</code>، فإن قيمة <code>B * C</code> تُحسَب أولًا ثم تُضاف إلى <code>A</code>. يَعنِي ذلك أن عامل الضرب <code>*</code> له أولوية عن عامل الجمع <code>+</code> بشكل افتراضي، فإذا لم يَكُن ذلك هو ما تريده، يُمكِنك ببساطة إضافة أقواس تُحدِّد صراحةً الكيفية التي ستُجمَّع بها العوامل، فمثلًا، يمكنك كتابة <code>‎(A + B) * C</code> إذا أردت أن تَحسِب حاصل جمع <code>A</code> مع <code>B</code> أولًا ثم تضرب النتيجة في <code>C</code>.
</p>

<p>
	تُوفِّر الجافا عددًا كبيرًا من العوامل (operators) سنَمُرّ عبر الغالبية الأكثر شيوعًا واستخدامًا ببقية هذا القسم.
</p>

<h2>
	العوامل الحسابية (arithmetic)
</h2>

<p>
	تَتَضمَّن العوامل الحسابية (arithmetic operators) كُلًا من عمليات الجمع والطرح والضرب والقسمة، وتُستخدَم الرموز <code>+</code> و <code>-</code> و <code>*</code> و <code>/</code> بالجافا للإشارة إليها على الترتيب. يُمكِنك اِستخدَام تلك العمليات مع أي قيم من النوع العددي: <code>byte</code> و <code>short</code> و <code>int</code> و <code>long</code> و <code>float</code> و <code>double</code> وكذلك مع أي قيم من النوع <code>char</code> حيث تُعامَل كعدد صحيح (integer) ضِمْن ذلك السياق. تحديدًا عندما يُستخدَم محرف من النوع <code>char</code> مع عامل عددي (arithmetic operator)، يُحوِّله الحاسوب إلى عدده الترميزي باليونيكود (unicode code number). في العموم عندما يُحصِّل الحاسوب أيًا من تلك العمليات بشكل فعليّ، فينبغي أن تَكُون القيمتان المُدْمجتان من نفس النوع، فإذا أراد البرنامج أن يَدْمِج قيمتين من نوعين مختلفين، سيُحوِّل الحاسوب إحداهما إلى نوع الآخرى. فمثلًا عند حِسَاب <code>37.4 + 10</code>، سيُحوِّل الحاسوب العدد الصحيح <code>10</code> إلى نَظيره الحقيقي <code>10.0</code> ثُمَّ سيَحسِب قيمة <code>37.4 + 10.0</code>. يُطلَق على ذلك "تَحْوِيل نوع (type conversion)"، ولا تحتاج عادةً لأن تقلق بشأن ذلك عند حُدوثه ضِمْن تعبير (expression) لأن الحاسوب سيُجريه أتوماتيكيًا.
</p>

<p>
	عندما تَدمِج قيمتين عدديتين بغض النظر عما إذا كان الحاسوب قد اِضطّر لإِجراء عملية تَحْوِيل نوع (type conversion) لأي منهما أم لا، فإن الناتج سيَكُون من نفس النوع. فمثلًا، إذا حَسبت حاصل ضرب عددين صحيحين من النوع <code>int</code>، ستَحصُل على قيمة من النوع <code>int</code> أما إذا حَسبت حاصل ضرب عددين من النوع <code>double</code>، فستَحصُل على قيمة من النوع <code>double</code>. يُعدّ ذلك أمرًا متوقعًا على أية حال، ولكن عندما تَستخدِم عامل القسمة <code>/</code>، فلابُدّ أن تَكُون أكثر حرصًا، لأنه عند حِسَاب حاصل قسمة عددين صحيحين (integers)، دائمًا ما ستَكُون النتيجة عددًا صحيحًا أي ستُهمَل أية كُسور (fractional) قد يَتَضمَّنها خارج القسمة (quotient)، فمثلًا، قيمة <code>7/2</code> تُساوِي <code>3</code> لا <code>3.5</code>. لنَفْترِض مثلًا أن <code>N</code> عبارة عن مُتْغيِّر من النوع العددي الصحيح، ستَكُون إذًا قيمة <code>N/100</code> عددًا صحيحًا (integer) أما قيمة <code>‎1/N</code> فستُساوِي الصفر لأي <code>N</code> أكبر من الواحد. تُعدّ تلك الحقيقة مصدرًا شائعًا للكثير من الأخطاء البرمجية. يُمكِنك مع ذلك أن تُجبِر الحاسوب على أن يَحسِب الناتج بهيئة عدد حقيقي (real number) من خلال جَعل أحد المُعاملات عددًا حقيقيًا، فمثلًا، عندما يُحصِّل الحاسوب قيمة <code>‎1.0/N</code>، فإنه سيُحوِّل أولًا <code>N</code> إلى عدد حقيقي لكي يتماشى مع نوع القيمة <code>1.0</code>، لذلك يَكُون الناتج عددًا حقيقيًا.
</p>

<p>
	تُوفِّر الجافا عاملًا (operator) آخر لحِسَاب باقي قسمة (remainder) عددين على بعضهما، ويُستخدَم <code>%</code> للإشارة إليه. إذا كان كُلًا من <code>A</code> و <code>B</code> أعدادًا صحيحة، يُمثِل <code>A % B</code> باقي قسمة <code>A</code> على <code>B</code>. فمثلًا، <code>‎7 % 2</code> تُساوِي <code>1</code> بينما <code>‎34577 % 100</code> تُساوِي <code>77</code> أما <code>‎50 % 8</code> فتُساوِي <code>2</code>. لاحِظ أنه في حالة المُعاملات (operands) السالبة، لا يَعمَل <code>%</code> كما قد تَتَوقَّع من أي عامل باقي قسمة عادي، فمثلًا إذا كانت قيمة <code>A</code> أو <code>B</code> سالبة، فستَكُون قيمة <code>A % B</code> سالبة أيضًا. عادةً ما يُستخدَم العامل <code>%</code> لاختبار ما إذا كان عدد صحيح معين سالبًا أم موجبًا: إذا كانت قيمة <code>N % 2</code> تُساوِي 0، يَكُون <code>N</code> عددًا موجبًا أما إذا كانت قيمته تُساوِي 1، يَكُون عددًا سالبًا. ويُمكِنك عمومًا أن تَفْحَص ما إذا كان عدد صحيح <code>N</code> قابلًا للقسمة على عدد صحيح آخر <code>M</code> بشكل متساوٍ من خلال فَحْص ما إذا كانت قيمة <code>N % M</code> تُساوِي 0.
</p>

<p>
	يَعمَل العامل <code>%</code> أيضًا مع الأعداد الحقيقية (real numbers)، ففي العموم، يُمثِل <code>A % B</code> مقدار ما يَتبقَّى بعدما تَحذِف من العدد <code>A</code> أكبر قدر ممكن من <code>B</code>. فمثلًا، <code>‎7.52 % 0.5</code> يساوي <code>0.02</code>.
</p>

<p>
	قد تحتاج أحيانًا لأن تَحسِب القيمة السالبة من عدد معين. في هذه الحالة، بدلًا من اِستخدَام تعبير مثل <code>‎(-1)*X</code>، تُوفِّر الجافا لهذا الغرض عامل إشارة طرح أُحادي (unary) يُكْتَب على الصورة <code>‎-X</code>. بالمثل، تُوفِّر الجافا عامل إشارة جمع أُحادي يُكْتَب على الصورة <code>‎+X</code>، ولكنه لا يُنجز أي شيء فعليّ في الواقع.
</p>

<p>
	بالمناسبة، تَذكَّر أنه يُمكِنك أيضًا اِستخدَام العامل <code>+</code> لضمّ (concatenate) قيمة من أي نوع إلى قيمة آخرى عبارة عن سِلسِلة نصية من النوع <code>String</code>. ونظرًا لإمكانية تَحْوِيل أي نوع إلى النوع <code>String</code> أتوماتيكيًا، يُعدّ ذلك مثالًا آخر لعملية تَحْوِيل نوع (type conversion).
</p>

<h2>
	الزيادة (increment) والنقصان (decrement)
</h2>

<p>
	ستَجِد أن زيادة قيمة مُتْغيِّر (variable) معين بمقدار يُساوِي الواحد أو إنقاصها عملية شائعة للغاية بالبرمجة. يُمكِنك أن تُجرِي ذلك ضِمْن تَعْليمَة إِسْناد (assignment) كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_7" style="">
<span class="pln">counter  </span><span class="pun">=</span><span class="pln">  counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
goalsScored  </span><span class="pun">=</span><span class="pln">  goalsScored </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span></pre>

<p>
	تأخذ التَعْليمَة <code>x = x + 1</code> القيمة السابقة للمُتْغيِّر <code>x</code> وتَحسِب حاصل مجموعها مع العدد واحد ثم تُخزِّن النتيجة كقيمة جديدة للمُتْغيِّر <code>x</code>. في الحقيقة، يُمكِنك تّنْفيذ نفس تلك العملية فقط بكتابة <code>x++‎</code> أو <code>‎++x</code> حيث يُغيِّر كُلًا منهما قيمة <code>x</code> بنفس تأثير التَعْليمَة <code>x = x + 1</code>. يُمكِنك إذًا كتابة التَعْليمَتين السابقتين على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_9" style="">
<span class="pln">counter</span><span class="pun">++;</span><span class="pln">
goalsScored</span><span class="pun">++;</span></pre>

<p>
	بالمثل، يمكنك كتابة <code>x--‎</code> أو <code>‎--x</code> لطرح العدد واحد من <code>x</code> أي أن <code>x--‎</code> لها نفس تأثير التعليمة <code>x = x - 1</code>. تُعرَف إضافة مقدار يُساوِي الواحد إلى مُتْغيِّر باسم "الزيادة (increment)" أما عملية الطرح فتُعرَف باسم "النقصان (decrement)"، وعليه يُطلَق على العاملين <code>++</code> و <code>--</code> اسم عاملي الزيادة (increment operator) والنقصان (decrement operator) على الترتيب. يُمكِنك أن تَستخدِم تلك العوامل مع المُتْغيِّرات (variables) التي تنتمي إلى أي من الأنواع العددية وكذلك مع المُتْغيِّرات من النوع <code>char</code>. إذا كان <code>ch</code> يحتوي على المحرف 'A' فإن <code>ch++‎</code> تُغيِّر قيمته إلى 'B'.
</p>

<p>
	عادةً ما يُستخدَم العاملان <code>++</code> و <code>--</code> بتَعْليمَات مثل <code>x++;‎</code> أو <code>x--;‎</code>، وتَكُون في تلك الحالة بمثابة أوامر تُغيِّر من قيمة <code>x</code>. علاوة على ذلك، يُمكِنك أيضًا أن تَستخدِم <code>x++‎</code> أو <code>‎++x</code> أو <code>x--‎</code> أو <code>‎--x</code> كتعبير (expression) أو كجزء ضِمْن تعبير أكبر. اُنظر الأمثلة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_11" style="">
<span class="pln">y </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">++;</span><span class="pln">
y </span><span class="pun">=</span><span class="pln"> </span><span class="pun">++</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
</span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(--</span><span class="pln">x</span><span class="pun">);</span><span class="pln">
z </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(++</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y</span><span class="pun">--);</span></pre>

<p>
	تُضيِف التَعْليمَة <code>y = x++;‎</code> مقدارًا يُساوِي الواحد إلى قيمة المُتْغيِّر <code>x</code> كما أنها تُسنِد قيمة معينة إلى <code>y</code> والتي تُعرَّف على أنها القيمة السابقة للمُتْغيِّر <code>x</code> أي قبل إضافة الواحد. فمثلًا، إذا كانت قيمة <code>x</code> هي ٦، فإن التَعْليمَة <code>"y = x++;‎</code> ستُغيِّر قيمة <code>x</code> إلى ٧. ولأن القيمة السابقة للمُتْغيِّر <code>x</code> تُساوِي ٦، فستُغيِّر التَعْليمَة قيمة <code>y</code> إلى نفس تلك القيمة ٦. من الناحية الآخرى، تُعرَّف قيمة <code>‎++x</code> على أنها القيمة الجديدة للمُتْغيِّر <code>x</code> أي بعد إضافة مقدارًا يُساوِي الواحد. فمثلًا، إذا كانت قيمة <code>x</code> تُساوِي ٦، فستُغيِّر التَعْليمَة <code>y = ++x;‎</code> قيم كلًا من <code>x</code> و <code>y</code> إلى ٧. يَعمَل عامل النقصان (decrement operator) <code>--</code> بنفس الطريقة.
</p>

<p>
	لمّا كان التعبير <code>x = x++‎</code> يُسنِد القيمة السابقة للمُتْغيِّر <code>x</code> -أي قبل تّنْفيذ الزيادة- إلى نفس ذات المُتْغيِّر <code>x</code>، فإنه في الواقع لا يُغيِّر قيمته. إذا شئنا الدقة، فإن التعبير السابق يزيد (increment) قيمة <code>x</code> بمقدار الواحد ولكنها سرعان ما تَتَغيَّر إلى القيمة السابقة نتيجة لتَعْليمَة الإِسْناد (assignment). لاحِظ أن التعبير <code>x++‎</code> يختلف عن <code>x + 1</code> فالتعبير الأول يُغيِّر من قيمة <code>x</code> أما الثاني فلا يُغيِّرها.
</p>

<p>
	قد يَكُون ذلك مُربكًا نوعًا ما، وفي الحقيقة، يقع الطلبة عادةً بالكثير من الأخطاء البرمجية (bugs) نتيجة لذلك الارتباك، ولكن ليس هناك أي داعٍ لذلك فيُمكِنك مثلًا أن تَستخدِم العاملين <code>++</code> و <code>--</code> كتَعْليمَات مُفردة فقط وليس كتعبيرات (expressions)، وهو ما سنلتزم به خلال الأمثلة التالية.
</p>

<h2>
	العوامل العلاقية (relational)
</h2>

<p>
	تُوفِّر الجافا مُتْغيِّرات منطقية وكذلك تعبيرات (expressions) منطقية يُمكِن اِستخدَامها كشُروط (conditions) قد تؤول إلى أي من القيمتين <code>true</code> أو <code>false</code>. عادةً ما يَتَكوَّن التعبير المنطقي من عامل علاقي (relational) يُوازن بين قيمتين، فيَختبِر مثلًا ما إذا كانت قيمتان متساويتين أو ما إذا كانت قيمة إحداهما أكبر من الآخرى وهكذا. يَتَوفَّر بالجافا العوامل العلاقية التالية <code>==</code> و <code>‎!=‎</code> و <code>‎&lt;‎</code> و <code>‎&gt;‎</code> و <code>‎&lt;=‎</code> و <code>‎&gt;=‎</code>:
</p>

<pre class="ipsCode">
A == B       Is A "equal to" B?
A != B       Is A "not equal to" B?
A &lt; B        Is A "less than" B?
A &gt; B        Is A "greater than" B?
A &lt;= B       Is A "less than or equal to" B?
A &gt;= B       Is A "greater than or equal to" B?
</pre>

<p>
	تُستخدَم تلك العوامل (operators) لموازنة قيم من أي أنواع عددية. علاوة على ذلك، يُمكِنها أيضًا أن تُستخدَم لموازنة قيم من النوع <code>char</code>. بالنسبة للمحارف (characters)، فإن العوامل <code>‎&lt;‎</code> و <code>‎&gt;‎</code> مُعرَّفة لتَعمَل وفقًا لقيمها العددية باليونيكود (unicode) وهو ما يختلف عن الترتيب الأبجدي المُعتاد حيث تأتي الأحرف الأبجدية الكبيرة (upper case) بأكملها قبل الأحرف الأبجدية الصغيرة (lower case).
</p>

<p>
	فيما يَتَعلَّق بالتعبيرات المنطقية (boolean expressions)، لا تختلف قيم النوع المنطقي وفقًا للحاسوب عن قيم أي نوع آخر. فيُمكِنك مثلًا أن تُسنِد (assign) تعبيرات منطقية إلى أي مُتْغيِّر منطقي تمامًا مثلما بإِمكانك إِسْناد قيم عددية إلى أي مُتْغيِّر عددي، وكذلك يُمكِن للدوال (functions) أن تُعيد قيم من النوع المنطقي. إلى جانب ذلك، يُمكِنك أن تَستخدِم تلك التعبيرات ضِمْن تَعْليمَتي حَلْقة التَكْرار (loop) والتَفْرِيع (branch)، وهو ما سنُناقشه بالفصل التالي.
</p>

<p>
	بالمناسبة، يُمكِنك أن تَستخدِم العاملين <code>==</code> و <code>‎!=‎</code> لموازنة القيم المنطقية أيضًا، وهو ما قد يَكُون مفيدًا في بعض الأحيان. اُنظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_14" style="">
<span class="pln">boolean sameSign</span><span class="pun">;</span><span class="pln">
sameSign </span><span class="pun">=</span><span class="pln"> </span><span class="pun">((</span><span class="pln">x </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">));</span></pre>

<p>
	فيما يَتَعلَّق بالقيم من النوع <code>String</code>، لا يُمكِنك أن تَستخدِم العوامل العلاقية <code>&lt;</code> و <code>&gt;</code> و <code>‎&lt;=‎</code> و <code>‎&gt;=‎</code> لموازنة قيم ذلك النوع، ولكن يُسمَح باِستخدَام كُلًا من <code>==</code> و <code>‎!=‎</code> لموازنتها مع أنها لن تُعطِيك النتيجة التي تَتَوقَّعها بسبب الكيفية التي تَتَصرَّف الكائنات (objects) على أساسها. فمثلًا، يَختبِر العامل <code>==</code> ما إذا كان الكائنان (objects) مُخزَّنين بنفس مَوضِع الذاكرة (memory location) بدلًا من أن يَختبِر ما إذا كانت قيمتهما هي نفسها. قد تحتاج إلى إجراء تلك الموازنة لبعض أنواع الكائنات أحيانًا، ولكن نادرًا ما يَكُون ذلك هو الحال مع السَلاسِل النصية (strings) من النوع <code>String</code>. سنَعُود لمناقشة ذلك فيما بَعْد على أية حال. ينبغي عمومًا أن توازن السَلاسِل النصية باِستخدَام برامج فرعية (subroutines) مثل <code>equals()‎</code> و <code>compareTo()‎</code> والتي تَعرَّضنا لها بالقسم الفرعي ٢.٣.٣.
</p>

<p>
	إلى جانب ذلك، فإنه عند اِستخدَام كُلًا من العاملين <code>==</code> و <code>‎!=‎</code> مع الثابت <code>Double.NaN</code> المُمثِل للقيمة غَيْر المُعرَّفة من النوع <code>double</code>، فإنهما لا يَتَصرَّفان على النحو المُتوقَّع. فمثلًا إن كان <code>x</code> مُتْغيِّرًا من النوع <code>double</code>، فإن تعبيرات مثل <code>x == Double.NaN</code> و <code>x != Double.NaN</code> ستُكون مُساوِية للقيمة <code>false</code> بجميع الحالات سواء كانت <code>x</code> تَحتوِي على <code>Double.NaN</code> أم لا. لذا إذا أردت أن تَختبِر ما إذا كان المُتْغيِّر <code>x</code> يحتوي على القيمة غَيْر المُعرَّفة <code>Double.Nan</code>، يُمكِنك أن تَستخدِم الدالة <code>Double.isNan(x)‎</code> والتي تُعيد قيمة منطقية.
</p>

<h2>
	العوامل المنطقية (logical/boolean)
</h2>

<p>
	تَتَركَّب الشُروط (conditions) الأكثر تعقيدًا من عوامل منطقية (boolean operators) هي ‏"and" و "or" و "not" بالإنجليزية مثل الشرط التالي: "If there is a test <strong>and</strong> you did <strong>not</strong> study for it…". تُوفِّر الجافا لحسن الحظ تلك العوامل أيضًا كجزء من اللغة.
</p>

<p>
	يَدمِج العامل المنطقي "and" قيمتين من النوع المنطقي <code>boolean</code> لتَكُون النتيجة قيمة من النوع <code>boolean</code>. إذا كانت كلتا القيمتين تُساوِي <code>true</code>، فإن النتيجة النهائية ستُساوِي <code>true</code> أما إذا كانت قيمة أي منهما تُساوِي <code>false</code>، فإن النتيجة ستُساوِي <code>false</code>. يَعمَل الترميز <code>&amp;&amp;</code> مُمثِلًا للعامل المنطقي "and" بلغة الجافا، فمثلًا، يؤول التعبير <code>(x == 0) &amp;&amp; (y == 0)</code> إلى القيمة المنطقية <code>true</code> إذا كانت قيمة كُلًا من <code>x</code> و <code>y</code> تُساوِي صفرًا.
</p>

<p>
	في المقابل، يَعمَل الترميز <code>||</code> مُمثِلًا للعامل المنطقي "or" بلغة الجافا. يؤول التعبير <code>A || B</code> إلى <code>true</code> إذا كانت قيمة أي من <code>A</code> أو <code>B</code> أو كليهما تُساوِي <code>true</code> بينما يؤول إلى <code>false</code> إذا كانت قيمة كُلًا من <code>A</code> و <code>B</code> تُساوِي <code>false</code>. يَتبِع كُلًا من العاملين <code>&amp;&amp;</code> و <code>||</code> مفهوم الدارة القصيرة (short-circuited) أي لا يَكُون تَحْصِيل قيمة المُعامل الثاني ضروريًا إذا أَمْكَن معرفة النتيجة النهائية قبلها. اُنظر الاختبار التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_16" style="">
<span class="pun">(</span><span class="pln">x </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y</span><span class="pun">/</span><span class="pln">x </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span></pre>

<p>
	إذا كانت قيمة <code>x</code> تُساوِي صفر، فسيَكُون حاصل قسمة <code>y/x</code> غَيْر مُعرَّف رياضيًا. ولأن الحاسوب سيُحصِّل قيمة المعامل الأيسر <code>(x != 0)</code> أولًا، وسيَجِدها مُساوية للقيمة <code>false</code>، فإنه سيُدرك أن القيمة النهائية للشرط <code>(‎(x != 0) &amp;&amp; anything)</code> ككل لابُدّ وأن تُساوِي <code>false</code> لا محالة، لذا فإنه لا يُحصِّل قيمة المعامل الأيمن، ولا يُنفِّذ عملية القسمة من الأساس. يُعدّ هذا مثالًا على اِستخدَام الدارة القصيرة (short circuit) وهو ما جَنَّبَنا القسمة على صفر.
</p>

<p>
	تَستخدِم الجافا المحرف <code>!</code> لتمثيل العامل المنطقي "not" والذي هو عامل أحادي (unary) يُكْتَب قَبْل مُعامله الوحيد، فمثلًا إذا كان <code>test</code> مُتْغيِّر منطقي من النوع <code>boolean</code> فإن التعبير التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_18" style="">
<span class="pln">test </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln"> test</span><span class="pun">;</span></pre>

<p>
	سيَعكِس قيمة المُتْغيِّر <code>test</code> ويُغيِّرها من <code>true</code> إلى <code>false</code> ومن <code>false</code> إلى <code>true</code>.
</p>

<h2>
	العامل الشرطي (conditional)
</h2>

<p>
	تَملُك أي لغة برمجية جيدة بعض الخاصيات الصغيرة الأنيقة نوعًا ما والتي هي في الواقع ليست ضرورية بشكل فعليّ، فكل ما تَفعَله هي أنها تمنحك شعورًا جيدًا عند اِستخدَامها. تُوفِّر الجافا عاملًا شَّرْطيًا (conditional operator) عبارة عن عامل ثلاثي (ternary) أي لديه ٣ مُعاملات (operands)، ويَتَكوَّن من جزئين هما <code>?</code> و <code>:</code> يُستخدَمان معًا. يُكْتَب العامل بالصياغة التالية:
</p>

<pre class="ipsCode">
&lt;boolean-expression&gt; ? &lt;expression1&gt; : &lt;expression2&gt;
</pre>

<p>
	يَختبر الحاسوب قيمة التعبير المنطقي **<boolean-expression> **أولًا، فإذا كانت قيمته تُساوِي <code>true</code>، فسيؤول التعبير ككل إلى قيمة <strong><expression1></expression1></strong>، أما إذا كانت قيمته تُساوِي <code>false</code>، فسيؤول إلى <strong><expression2></expression2></strong>. اُنظر المثال التالي:</boolean-expression></p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_21" style="">
<span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N</span><span class="pun">/</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">3</span><span class="pun">*</span><span class="pln">N</span><span class="pun">+</span><span class="lit">1</span><span class="pun">);</span></pre>

<p>
	بالمثال السابق، إذا كان التعبير <code>N % 2 == 0</code> يُساوِي <code>true</code> أي إذا كانت قيمة <code>N</code> زوجية، فستُسنَد قيمة <code>N/2</code> إلى المُتْغيِّر <code>next</code> أما إذا كانت قيمة <code>N</code> فردية، فستُسنَد قيمة <code>(‎3*N+1)</code> إليه. لاحِظ أن الأقواس ضِمْن هذا المثال ليست مطلوبة ولكنها تُسهِل من قراءة التعبير (expression).
</p>

<h2>
	عوامل الإسناد (assignment) وتحويل الأنواع (type conversion)
</h2>

<p>
	لقد تَعرَّضنا بالفعل للترميز <code>=</code> ضِمْن تَعْليمَات الإِسْناد (assignment statement) المسئولة عن إِسْناد قيمة تعبير (expression) معين إلى مُتْغيِّر (variable). يُعدّ ذلك الترميز <code>=</code> بمثابة عامل (operator) بمعنى أنه من المُمكِن اِستخدَامه كتعبير (expression) بحد ذاته أو كجزء ضِمْن تعبير أكثر تعقيدًا. لاحِظ أن قيمة أي عملية إِسْناد (assignment) مثل <code>A=B</code> تَكُون مُساوِية للقيمة ذاتها المُسنَدة إلى <code>A</code>، لذا إذا أردت أن تُسنِد (assign) قيمة مُتْغيِّر <code>B</code> إلى آخر <code>A</code>، وأن تَفْحَص ما إذا كانت قيمته تُساوِي ٠ بنفس ذات الوقت، يُمكِنك أن تَستخدِم ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_23" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">(</span><span class="pln">A</span><span class="pun">=</span><span class="pln">B</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)...</span></pre>

<p>
	مع أنه لا يُحبذ القيام بذلك عمومًا.
</p>

<p>
	في العموم، لابُدّ أن يَكُون نوع التعبير (expression) على الجانب الأيمن من أي تَعْليمَة إِسْناد (assignment) من نفس نوع المُتْغيِّر (variable) على جانبها الأيسر. في بعض الحالات، يستطيع الحاسوب أن يُحوِّل قيمة التعبير أتوماتيكيًا لكي تتوافق مع نوع المُتْغيِّر (variable). فمثلًا، بالنسبة لقائمة الأنواع العددية: <code>byte</code> و <code>short</code> و <code>int</code> و <code>long</code> و <code>float</code> و <code>double</code>، يستطيع الحاسوب أن يُحوِّل قيمة من نوع مَذكُور بأول تلك القائمة أتوماتيكيًا إلى قيمة من نوع مَذكُور لاحقًا. اُنظر الأمثلة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_25" style="">
<span class="typ">int</span><span class="pln"> A</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">double</span><span class="pln"> X</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">short</span><span class="pln"> B</span><span class="pun">;</span><span class="pln">
A </span><span class="pun">=</span><span class="pln"> </span><span class="lit">17</span><span class="pun">;</span><span class="pln">
X </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">;</span><span class="pln">    </span><span class="com">// ‫ستحوّل A إلى النوع double</span><span class="pln">
B </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">;</span><span class="pln">    </span><span class="com">// ‫لا يمكن فليس هناك تحويل تلقائي من int إلى short</span></pre>

<p>
	الفكرة باختصار هو أنه يُمكِن دومًا التَحْوِيل بين نوعين أتوماتيكيًا طالما لن يؤدي ذلك التَحْوِيل إلى تَغْيير دلالة القيمة. فمثلًا، يُمكِن لأي قيمة من النوع <code>int</code> أن تُحوَّل دومًا إلى قيمة من النوع <code>double</code> بنفس قيمتها العددية. في المقابل، نظرًا لأن أكبر قيمة يُمكِن للنوع <code>short</code> أن يَحمِلها تُساوِي <code>32767</code>، فإنه لا يُمكِن لبعض القيم من النوع <code>int</code> التي تَقَع خارج النطاق المسموح به للنوع <code>short</code> مثل <code>100000</code> أن تُمثَل باِستخدَام النوع <code>short</code>.
</p>

<p>
	قد تَرغَب أحيانًا بأن تُجرِي تَحْوِيلًا لن يَحدُث أتوماتيكيًا. يُمكِنك القيام بذلك عن طريق ما يُعرَف باسم "التَحْوِيل بين الأنواع (type casting)" وذلك بكتابة اسم النوع المطلوب التَحْوِيل إليه بين قوسين أمام القيمة المُراد تَحْوِيلها. اُنظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_27" style="">
<span class="typ">int</span><span class="pln"> A</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">short</span><span class="pln"> B</span><span class="pun">;</span><span class="pln">
A </span><span class="pun">=</span><span class="pln"> </span><span class="lit">17</span><span class="pun">;</span><span class="pln">
B </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">short</span><span class="pun">)</span><span class="pln">A</span><span class="pun">;</span><span class="pln">  </span><span class="com">// ‫يصح لأن A حولت صراحة إلى قيمة من النوع short</span></pre>

<p>
	يُمكِنك إجراء عملية "التَحْوِيل بين الأنواع (type casting)" من أي نوع عددي إلى أي نوع عددي آخر، ولكنه قد يتسبَّب بتَغْيِير القيمة العددية للعدد. فمثلًا، <code>‎(short)100000</code> تُساوِي <code>‎-31072</code>. أخذنا العدد الصحيح <code>100000</code> من النوع <code>int</code> المُكوَّن من ٤ بايت ثُمَّ تركنا ٢ بايت منه حتى نَحصُل على قيمة من النوع <code>short</code>، وعليه فقد خَسرنا المعلومات الموجودة بتلك البايتات المُلغَاة.
</p>

<p>
	عندما تُجرِي عملية "التحويل بين الأنواع (type-casting)" من عدد حقيقي (real) إلى عدد صحيح (integer)، يُهمَل الجزء الكسري (fractional) منه تلقائيًا. فمثلًا، <code>‎(int)7.9453</code> تُساوِي <code>7</code>. تُعدّ مسألة الحصول على عدد صحيح عشوائي بين ١ و ٦ بمثابة مثال آخر: تُعيد الدالة <code>Math.random()‎</code> عددًا حقيقيًا يتراوح بين <code>0.0</code> و <code>0.9999</code>، لذا فإن قيمة التعبير <code>6*Math.random()‎</code> تَكُون عددًا يتراوح بين <code>0.0</code> و <code>5.999</code>. يُمكِننا الآن أن نَستخدِم عامل التَحْوِيل بين الأنواع (type-cast operator)‏ <code>(int)</code> لتَحْوِيل قيمة ذلك التعبير إلى عدد صحيح كالتالي <code>(int)(6*Math.random(‎)‎)</code>، والتي تُصبِح نتيجته واحدة من قيم الأعداد الصحيحة ٠ و ١ و ٢ و ٣ و ٤ و ٥. والآن، لنَحصُل على عدد يتراوح بين العددين ١ و ٦، يُمكِننا أن نُضيف مقدارًا يُساوِي الواحد كالتالي <code>‎(int)(6*Math.random()) + 1</code>. لاحِظ أن الأقواس حول <code>6*Math.random()‎</code> ضرورية لأنه وبحسب قواعد الأولوية (precedence rules)، سيُطبَق عامل التحويل بين الأنواع (type cast operator) على العدد ٦ فقط إذا لم نَستخدِم أية أقواس.
</p>

<p>
	يُعدّ النوع <code>char</code> بمثابة نوع عددي صحيح (integer) أي يُمكِنك مثلًا أن تُسنِد (assign) قيمة من النوع <code>char</code> إلى مُتْغيِّر من النوع <code>int</code> كما تستطيع أن تُسنِد ثابت (constant) صحيح تتراوح قيمته من ٠ وحتى ٦٥٥٣٥ إلى مُتْغيِّر من النوع <code>char</code>. يُمكِنك حتى أن تُطبِق عملية التَحْوِيل بين الأنواع (type-casting) صراحةً بين النوع <code>char</code> وأي نوع عددي آخر. فمثلًا، <code>‎(char)97</code> تُساوِي 'a' أما <code>‎(int)'+'‎</code> فتُساوِي <code>43</code> بينما <code>(char)('A' + 2)</code> تُساوِي 'C'.
</p>

<p>
	أما بالنسبة للنوع <code>String</code>، فلا يُمكِنك أن تَستخدِم عامل التَحْوِيل بين الأنواع (type-casts) لكي تُحوِّل بين النوع <code>String</code> وأي نوع آخر. في المقابل، يُمكِنك أن تَضُمّ (concatenate) قيم من أي نوع إلى سِلسِلة نصية فارغة لتَحْوِيلها إلى النوع <code>String</code>، فمثلًا، قيمة <code>‎"" + 42</code> تُساوِي السِلسِلة النصية "42". على نحوٍ أفضل، يُمكِنك أن تَستخدِم الدالة (function)‏ <code>String.valueOf(x)‎</code> المُعرَّفة كعضو ساكن (static member) بالصَنْف <code>String</code> حيث تُعيد تلك الدالة قيمة <code>x</code> بعد تَحْوِيلها إلى سِلسِلة نصية من النوع <code>String</code>، فمثلًا، يُعيد الاستدعاء <code>String.valueOf(42)‎</code> القيمة "42". إذا كان <code>ch</code> مُتْغيِّرًا من النوع <code>char</code>، فإن الاستدعاء <code>String.valueOf(ch)‎</code> يُعيد سِلسِلة نصية (string) طولها يُساوِي ١ ومُكوَّنة من محرف واحد يُمثِل قيمة <code>ch</code>.
</p>

<p>
	تستطيع أيضًا تَحْوِيل بعض السَلاسِل النصية (strings) إلى قيم من أنواع آخرى. فمثلًا، يُمكِنك تَحْوِيل سِلسِلة نصية مثل "10" إلى القيمة <code>10</code> من النوع <code>int</code> وكذلك تَحْوِيل سِلسِلة نصية مثل "17.42e-2" إلى قيمة من النوع <code>double</code> تُساوي <code>0.1742</code>. تُوفِّر الجافا دوالًا مبنية مُسْبَقًا (built-in functions) لمُعالجة تلك التَحْوِيلات.
</p>

<p>
	يُعرِّف الصَنْف القياسي <code>Integer</code> عضو دالة ساكن (static member function) للتَحْوِيل من النوع <code>String</code> إلى النوع <code>int</code>. لنَفْترِض مثلًا أن <code>str</code> عبارة عن مُتْغيِّر يَتَضمَّن تعبيرًا (expression) من النوع <code>String</code>، سيُحاوِل استدعاء الدالة <code>Integer.parseInt(str)‎</code> إذًا أن يُحوِّل قيمة ذلك المُتْغيِّر إلى قيمة من النوع <code>int</code>. على سبيل المثال، سيُعيد استدعاء <code>Integer.parseInt("10")‎</code> القيمة <code>10</code> من النوع <code>int</code>. إذا لم تَكُن قيمة المُعامل (parameter) المُمرَّرة للدالة <code>Integer.parseInt</code> تُمثِل قيمة صالحة من النوع <code>int</code>، فسيَحدُث خطأ.
</p>

<p>
	بالمثل، يُعرِّف الصَنْف القياسي <code>Double</code> الدالة <code>Double.parseDouble</code>. لنَفْترِض أن <code>str</code> عبارة عن مُتْغيِّر من النوع <code>String</code>، سيُحاوِل إذًا استدعاء الدالة <code>Double.parseDouble(str)‎</code> أن يُحوِّل قيمة المُتْغيِّر <code>str</code> إلى قيمة من النوع <code>double</code>، وسيَحدُث خطأ إذا لم تَكُن قيمة <code>str</code> تُمثِل قيمة صالحة من النوع <code>double</code>.
</p>

<p>
	لنعود الآن إلى تَعْليمَات الإِسْناد (assignment statements)، تُوفِّر الجافا تشكيلة متنوعة من عامل الإِسْناد لتَسهِيل الكتابة. فمثلًا، <code>A += B</code> مُعرَّف ليَعمَل بنفس كيفية عَمَل <code>A = A + B</code>. في العموم، يَتوفَّر عامل إِسْناد مشابه لأي عامل (operator) طالما كان مُطبَقًا على مُعاملين (operands) -باستثناء العوامل العلاقية (relational operators)-. اُنظر الأمثلة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_31" style="">
<span class="pln">x </span><span class="pun">-=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">     </span><span class="com">// x = x - y;</span><span class="pln">
x </span><span class="pun">*=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">     </span><span class="com">// x = x * y;</span><span class="pln">
x </span><span class="pun">/=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">     </span><span class="com">// x = x / y;</span><span class="pln">
x </span><span class="pun">%=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">     </span><span class="com">// x = x % y;</span><span class="pln">
q </span><span class="pun">&amp;&amp;=</span><span class="pln"> p</span><span class="pun">;</span><span class="pln">    </span><span class="com">// q = q &amp;&amp; p;  (for booleans q and p)</span></pre>

<p>
	يُمكِن لعامل تَعْليمَة الإِسْناد المُدْمَج <code>‎+=‎</code> أن يُطبَق حتى على السَلاسِل النصية من النوع <code>String</code>. لقد طَبَقنا العامل <code>+</code> من قبل على سِلسِلة نصية، وكان ذلك بمثابة عملية ضَمّ (concatenation). لمّا كان التعبير <code>str += x</code> مُكافِئًا تمامًا للتعبير <code>str = str + x</code>، فإنه عند وجود سِلسِلة نصية (string) على الجانب الأيسر من العامل <code>‎+=‎</code>، تُلحَق القيمة الموجودة على جانبه الأيمن إلى نهاية السِلسِلة النصية، فمثلًا، إذا كانت قيمة <code>str</code> تُساوِي "tire"، تُغيِّر التَعْليمَة <code>str += 'd'‎</code> قيمة <code>str</code> إلى "tired".
</p>

<h2>
	قواعد الأولوية (precedence rules)
</h2>

<p>
	إذا اِستخدَمت أكثر من عامل (operator) واحد ضِمْن تعبير (expression)، وفي ذات الوقت لم تَستخدِم أي أقواس لتُشير صراحةً إلى الترتيب الذي ينبغي أن تُحصَّل (evaluate) على أساسه قيمة ذلك التعبير، فلابُدّ عندها إذًا من أن تنتبه لما يُعرَف باسم قواعد الأولوية (precedence rules)، والتي تُستخدَم لتَحْدِيد الترتيب الذي سيتبعه الحاسوب لتَحْصِيل قيمة التعبير. يُنصَح عمومًا باِستخدَام الأقواس لتَجنُّب أي ارتباك مُحتمَل لك أو لقارئ البرنامج في العموم.
</p>

<p>
	تَستعرِض القائمة التالية العوامل (operators) التي ناقشناها بهذا القسم مُرتَّبة تنازليًا بحسب الأولوية (precedence) من الأعلى (يُحصَّل أولًا) إلى الأقل (يُحصَّل أخيرًا):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_205_33" style="">
<span class="typ">Unary</span><span class="pln"> operators</span><span class="pun">:</span><span class="pln">              </span><span class="pun">++,</span><span class="pln"> </span><span class="pun">--,</span><span class="pln"> </span><span class="pun">!,</span><span class="pln"> unary </span><span class="pun">-,</span><span class="pln"> unary </span><span class="pun">+,</span><span class="pln"> type</span><span class="pun">-</span><span class="pln">cast
</span><span class="typ">Multiplication</span><span class="pln"> and division</span><span class="pun">:</span><span class="pln">  </span><span class="pun">*,</span><span class="pln">  </span><span class="pun">/,</span><span class="pln">  </span><span class="pun">%</span><span class="pln">
</span><span class="typ">Addition</span><span class="pln"> and subtraction</span><span class="pun">:</span><span class="pln">     </span><span class="pun">+,</span><span class="pln">  </span><span class="pun">-</span><span class="pln">
</span><span class="typ">Relational</span><span class="pln"> operators</span><span class="pun">:</span><span class="pln">         </span><span class="pun">&lt;,</span><span class="pln">  </span><span class="pun">&gt;,</span><span class="pln">  </span><span class="pun">&lt;=,</span><span class="pln">  </span><span class="pun">&gt;=</span><span class="pln">
</span><span class="typ">Equality</span><span class="pln"> and inequality</span><span class="pun">:</span><span class="pln">      </span><span class="pun">==,</span><span class="pln">  </span><span class="pun">!=</span><span class="pln">
</span><span class="typ">Boolean</span><span class="pln"> and</span><span class="pun">:</span><span class="pln">                  </span><span class="pun">&amp;&amp;</span><span class="pln">
</span><span class="typ">Boolean</span><span class="pln"> or</span><span class="pun">:</span><span class="pln">                   </span><span class="pun">||</span><span class="pln">
</span><span class="typ">Conditional</span><span class="pln"> </span><span class="kwd">operator</span><span class="pun">:</span><span class="pln">         </span><span class="pun">?:</span><span class="pln">
</span><span class="typ">Assignment</span><span class="pln"> operators</span><span class="pun">:</span><span class="pln">         </span><span class="pun">=,</span><span class="pln">  </span><span class="pun">+=,</span><span class="pln">  </span><span class="pun">-=,</span><span class="pln">  </span><span class="pun">*=,</span><span class="pln">  </span><span class="pun">/=,</span><span class="pln">  </span><span class="pun">%=</span></pre>

<p>
	تَملُك العوامل (operators) ضِمْن نفس السطر بالقائمة السابقة نفس الأولوية (precedence). إذا اِستخدَمت عواملًا لها نفس الأولوية ضِمْن تعبير بدون تَخْصِيص أي أقواس، تُحصَّل كُلًا من العوامل الأحادية (unary) وعوامل الإسناد (assignment) من اليمين إلى اليسار بينما تُحصَّل قيمة بقية العوامل من اليسار إلى اليمين. فمثلًا، تُحصَّل قيمة التعبير <code>A*B/C</code> كما لو كان مَكْتُوبًا كالتالي <code>‎(A*B)/C</code> بينما تُحصَّل قيمة التعبير <code>A=B=C</code> على النحو التالي <code>A=(B=C)‎</code>. بفَرْض أن قيمة التعبير <code>B=C</code> هي نفسها قيمة المُتْغيِّر <code>B</code>، هل تَعرِف الغرض من التعبير <code>A=B=C</code> ؟
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c2/s5.html" rel="external nofollow">Section 5: Details of Expressions</a> من فصل Chapter 2: Programming in the Small I: Names and Things من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1019</guid><pubDate>Thu, 08 Oct 2020 12:40:07 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x62F;&#x62E;&#x644;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x645;&#x62E;&#x631;&#x62C;&#x627;&#x62A; &#x627;&#x644;&#x646;&#x635;&#x64A;&#x629; &#x641;&#x64A;  &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D8%AE%D8%B1%D8%AC%D8%A7%D8%AA-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1018/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/11.png.e3933b6d6b6526083e5cc5606592e389.png" /></p>

<p>
	لقد رأينا مدى سهولة اِستخدَام دوال (functions) مثل <code>System.out.print</code> و <code>System.out.println</code> لعَرْض نص معين للمُستخدِم، ولكن لا يُمثِل ذلك سوى جزءًا صغيرًا من موضوع مُخْرَجات النصوص. تَعتمِد غالبية البرامج عمومًا على البيانات التي يُدخِلها المُستخدِم أثناء زمن تَشْغِيل البرنامج لذا لابُدّ من فهم الكيفية التي ينبغي أن نَتَعامَل على أساسها مع كُلًا من المُدْخَلات والمُخْرَجات. سنشرح خلال هذا القسم كيف يُمكِننا قراءة البيانات المُدْخَلة من قِبَل المُستخدِم كما سنناقش المُخْرَجات على نحو أكثر تفصيلًا، وأخيرًا سنتناول اِستخدَام الملفات كوسيلة للمُدْخَلات والمُخْرَجات.
</p>

<h2>
	الخرج البسيط والخرج المنسق
</h2>

<p>
	تُعدّ الدالة <code>System.out.print(x)‎</code> واحدة من أبسط دوال الخَرْج حيث تَستقبِل مُعاملًا <code>x</code> عبارة عن قيمة أو تعبير (expression) من أي نوع. إذا لم تَكُن قيمة المُعامل <code>x</code> المُمرَّرة سِلسِلةً نصية من النوع <code>String</code>، فإنها ستُحوَّل أولًا إلى قيمة من النوع <code>String</code> ثم ستُرسَل إلى مقصد خَرْج (output destination) يُعرَف باسم "الخَرْج القياسي (standard output)" مما يَعنِي أنها ستُعرَض للمُستخدِم. لاحِظ أنه في حالة برامج واجهة المُستخدِم الرسومية (GUI)، ستُرسَل تلك السِلسِلة إلى مكان لا يُحتمَل للمُستخدِم أن يراه. بالإضافة إلى ذلك، يُمكِننا أيضًا أن نُعيد توجيه الخَرْج القياسي (standard output) لكي يَكْتُب إلى مقصد خَرْج (output destination) مختلف، ولكن فيما هو مُتَعلِّق بالبرنامج التالي، سيتولَّى الكائن <code>System.out</code> مسئولية عَرْض النص للمُستخدِم.
</p>

<p>
	تُرسِل الدالتان <code>System.out.println(x)‎</code> و <code>System.out.print</code> نفس النص إلى الخَرْج، ولكن تُضيف الأولى سطرًا جديدًا (line feed) إلى نهاية النص أي سيُعرَض الخَرْج التالي بسطر جديد. يُمكِنك أيضًا أن تَستخدِم الدالة <code>System.out.println()‎</code> بدون أية مُعاملات (parameter) لإخراج سطر جديد أي يُكافِئ استدعاء الدالة <code>System.out.println(x)‎</code> ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_7" style="">
<span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">x</span><span class="pun">);</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span></pre>

<p>
	ربما تَكُون قد لاحظت أن <code>System.out.print</code> تُخرِج أعدادًا حقيقية مُكوَّنة من عدد أرقام مناسب بَعْد العلامة العشرية، فمثلًا، تُخرِج العدد <code>π</code> كالتالي "3.141592653589793" أما الأعداد المُمثِلة للنقود فتُخرِجها على الصورة التالية "1050.0" أو "43.575". قد تُفضِّل إِخراج تلك الأعداد بهيئة مختلفة مثل "3.14159" و "1050.00" و "43.58"، وعندها ينبغي أن تَستخدِم ما يُعرَف باسم "الخَرْج المُنسَّق (formatted output)" والذي سيُساعدك على التَحكُّم بكيفية طباعة الأعداد الحقيقية وغيرها من القيم الآخرى. تَتَوفَّر العديد من خيارات التنسيق سنُناقِش هنا أبسطها وأكثرها شيوعًا.
</p>

<p>
	يُمكِنك اِستخدَام الدالة <code>System.out.printf</code> للحصول على خَرْج مُنسَّق. يُعدّ الاسم <code>printf</code> اختصارًا للكلمتين "print formatted" أي "اِطبَع بصورة مُنسَّقة"، وهو في الواقع مأخوذ من لغتي البرمجة <code>C</code> و <code>C++‎</code>. تَستقبِل الدالة <code>System.out.printf</code> مُعاملًا (parameter) واحدًا أو أكثر بحيث يكون مُعاملها الأول عبارة عن سِلسِلة نصية من النوع <code>String</code> تُحدِّد صياغة الخَرْج (output format)، ويُطلَق عليها اسم "صِيْغة سلسلة التنسيق (Format String)" أما بقية المُعاملات فتُخصِّص القيم المطلوب إرسالها للخَرْج. تَطبَع التَعليمَة التالية عددًا بصياغة تتناسب مع قيمة نقدية بالدولار بحيث يُمثِل <code>amount</code> مُتْغيِّرًا من النوع <code>double</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_9" style="">
<span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%1.2f"</span><span class="pun">,</span><span class="pln"> amount </span><span class="pun">);</span></pre>

<p>
	تتكوَّن أي صِيْغة سلسلة تنسيق (format string) من "مُحدِّد تنسيق (format specifiers)" واحد أو أكثر بحيث يكون كُلًا منها مسئولًا عن صيغة الخَرْج لقيمة واحدة تُمرَّر عبر مُعامل آخر إضافي. في المثال أعلاه، احتوت صيغة سلسلة التنسيق على مُحدِّد تنسيق واحد هو <code>‎%1.2f</code>. يبدأ أي مُحدِّد تنسيق عمومًا بعلامة نسبة مئوية <code>%</code> وينتهي بحرف أبجدي يُحدِّد نوع الخَرْج المطلوب كما قد يَتَضمَّن معلومات تنسيق آخرى تُكْتَب بينهما، فمثلًا، ها هي بعض من مُحدِّدات التنسيق المُحتمَلة: <code>‎%d</code> و <code>‎%12d</code> و <code>‎%10s</code> و <code>‎%1.2f</code> و <code>‎%1.8g</code>. يُشير الحرف "d" بمُحدِّديّ التنسيق <code>‎%d</code> و <code>‎%12d</code> إلى أن القيمة المطلوب كتابتها عبارة عن عدد صحيح (integer) أما "12" بالمُحدِّد الثاني فتُشير إلى أقل عدد من الخانات ينبغي للخَرْج أن يحتلّه، فمثلًا، إذا تَطلَّب إخراج عدد صحيح عدة خانات عددها أقل من ١٢، ستُضَاف خانات فارغة إضافية إلى مُقدمة ذلك العدد لكي يُصبِح مجموع الخانات بالنهاية مساويًا لأقل عدد مُمكِن أي ١٢. يُقال عندها أن الخَرْج "وَاقِع على مُحاذاة اليمين بحقل طوله ١٢" أما إذا تطلَّب إخراجه عددًا أكبر من ١٢ خانة، ستُطبَع جميع الأرقام بدون أي خانات إضافية. لاحِظ أن مُحدِّديّ التنسيق <code>‎%d</code> و <code>‎%1d</code> لهما نفس المعنى أي إخراج القيمة بهيئة عدد صحيح بأي عدد ضروري من الخانات. يُعدّ الحرف "d" اختصارًا لكلمة "decimal" كما تستطيع اِستخدَام الحرف "x" بدلًا منه لإِخراج عدد صحيح بصياغة ست عشريّة (hexadecimal).
</p>

<p>
	يُمكِنك أيضًا اِستخدَام الحرف "s" بنهاية مُحدِّد تنسيق (format specifier) مع أي قيمة من أي نوع، مما يَعنِي ضرورة إخراج تلك القيمة بصيغتها الافتراضية كما لو أننا لم نَستخدِم خرجًا مُنسَّقًا من الأساس، فمثلًا، يُمكننا أن نُخصِّص مُحدِّد تنسيق مثل <code>‎%20s</code> بحيث يُمثِل العدد "20" أقل عدد ممكن من المحارف. يُعدّ الحرف "s" اختصارًا لكلمة "string" ويُمكِن استخدامه للقيم من النوع <code>String</code> أو مع أي قيم من أي نوع آخر بحيث تُحوَّل تلك القيم إلى النوع <code>String</code> بالطريقة المُعتادة.
</p>

<p>
	تُعدّ مُحدِّدات تنسيق القيم من النوع <code>double</code> أكثر تعقيدًا بقليل. يُستخدَم الحرف "f" بمُحدِّد تنسيق مثل <code>‎%1.2f</code> لإخراج عدد بصيغة عدد عشري مُكوَّن من فاصلة عائمة (floating-point form) أي يحتوي على عدة أرقام بعد العلامة العشرية. يُخصِّص العدد "2" بذلك المُحدِّد عدد الأرقام المُستخدَمة بَعْد العلامة العشرية أما العدد "1" فيُخصِّص أقل عدد من المحارف يلزم إخراجه. تعني القيمة "1" بذلك المَوضِع إمكانية إخراج أي عدد ضروري من المحارف. كمثال آخر، يُخصِّص المُحدِّد <code>‎%12.3f</code> صيغة عدد عشري مُكوَّن من ثلاثة أرقام بَعْد العلامة العشرية بحيث يُطبَع على محاذاة اليمين داخل حقل طوله ١٢. بالنسبة لكُلًا من الأعداد الكبيرة جدًا والصغيرة جدًا، فينبغي أن تُكْتَب بصيغة أسية (exponential format) مثل <code>6.00221415e23</code> وهو ما يُمثِل حاصل ضرب <code>6.00221415</code> في ١٠ مرفوعة للأس ٢٣. يُخصِّص مُحدِّد صيغة مثل <code>‎%15.8e</code> خَرْجًا بصيغة أُسية بحيث تُشير "8" إلى عدد الأرقام المُستخدَمة بَعْد العلامة العشرية. لاحِظ أنه إذا كنت تَستخدِم "g" بدلًا من "e"، فسيَكوُن الخرج بصيغة أُسية فقط للقيم الصغيرة جدًا والكبيرة جدًا أما القيم الآخرى فستُعرَض بصيغة عدد عشري كما ستُشير القيمة "8" بمُحدِّد صيغة مثل <code>‎%1.8g</code> إلى عدد الأرقام الكلي بما في ذلك كُلًا من الأرقام قَبْل وبَعْد العلامة العشرية.
</p>

<p>
	بالنسبة لخرج القيم العددية، فيُمكِنك أن تُضيف فاصلة <code>,</code> إلى مُحدِّد الصيغة لتقسيم أرقام العدد إلى مجموعات مما يُسهِل من قراءة الأعداد الكبيرة. بالولايات المتحدة الأمريكية، تَتَكوَّن كل مجموعة من ثلاثة أرقام يَفصِل بينها محرف فاصلة، فمثلًا إذا كانت قيمة <code>x</code> تُساوِي واحد بليون، فسيَكُون الخَرْج الناتج عن <code>System.out.printf("%,d",x)‎</code> هو <code>1,000,000,000</code>. بدول آخرى، قد يختلف المحرف الفاصل وكذلك عدد الأرقام بكل مجموعة. لابُدّ من كتابة الفاصلة ببداية مُحدِّد الصيغة (format specifier) أي قبل تَخْصِيص عَرْض الحقل (field width) كالتالي <code>‎%,12.3f</code>. إذا أردت محاذاة الخرج إلى اليسار بدلًا من اليمين، يمكنك إضافة علامة سالبة إلى بداية مُحدِّد الصيغة كالتالي <code>‎%-20s</code>.
</p>

<p>
	إلى جانب مُحدِّدات الصيغة (format specifiers)، قد تَتَضمَّن صيغ سَلاسِل التنسيق (format string) المُمرَّرة إلى الدالة <code>printf</code> محارفًا آخرى عادية تُنسَخ إلى الخَرْج كما هي. يَكُون ذلك مناسبًا لتَضْمِين بعض القيم بمنتصف سِلسِلة نصية. فلنَفْترِض مثلًا أن كُلًا من <code>x</code> و <code>y</code> عبارة عن مُتْغيِّرات (variables) من النوع <code>int</code>، يُمكِننا إذًا كتابة التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_11" style="">
<span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"The product of %d and %d is %d"</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">y</span><span class="pun">);</span></pre>

<p>
	عندما تُنفَّذ تلك التَعْليمَة، فستَحِلّ قيمة <code>x</code> محلّ أول حُدوث لمُحدِّد الصيغة <code>‎%d</code> بالسِلسِلة النصية (string) بينما ستَحِلّ قيمة <code>y</code> محلّ الحُدوث الثاني، وأخيرًا ستَحِلّ قيمة التعبير <code>x*y</code> محلّ الحُدوث الثالث. فمثلًا، قد يَكُون الخَرْج كالتالي "The product of 17 and 42 is 714" (علامتي الاقتباس ليست ضِمْن الخَرْج).
</p>

<p>
	إذا أردت أن تُخرج علامة نسبة مئوية، فينبغي أن تَكْتُب مُحدِّد الصيغة <code>%%</code> بصيغة سِلسِلة التنسيق (format string) أما إذا كنت تريد أن تُخرِج سطرًا جديدًا، فاستخدِم مُحدِّد الصيغة <code>‎%n</code>. بالمثل من السَلاسِل النصية العادية، يُمكِنك أيضًا أن تَستخدِم خطًا مائلًا عكسيًا <code>\</code> لإخراج محارف خاصة كعلامة الاقتباس المزدوجة أو المحرف "tab".
</p>

<h2>
	مثال لمدخل نصي
</h2>

<p>
	اعتادت الجافا لسبب غَيْر مفهوم أن تُصعِب من قراءة البيانات المُدْخَلة من قِبَل مُستخدِم البرنامج. كما ذكرنا من قبل، يتَوفَّر الكائن <code>System.out</code> بصورة مُسْبَقة ويُستخَدم لعَرْض الخَرْج للمُستخدِم حيث يَتَضمَّن البرنامج الفرعي (subroutine)‏ <code>System.out.print</code> لذلك الغرض. يَتَوفَّر أيضًا الكائن <code>System.in</code> لأغراض قراءة البيانات المُدْخَلة من قِبَل المُستخدِم، ولكنه يُوفِّر خدمات إِدْخَال بدائية جدًا تَتَطلَّب بعض المهارات البرمجية المُتقدمة بالجافا لاستخدامه بكفاءة.
</p>

<p>
	قدمت الجافا منذ إصدارها الخامس الصَنْف <code>Scanner</code> مما سَهَّل قليلًا من عملية قراءة البيانات المُدْخَلة من قِبَل المُستخدِم، ولكنه يَتطلَّب بعض المعرفة بالبرمجة كائنية التوجه (object-oriented programming) لكي تَتَمكَّن من اِستخدَامه، لذلك ربما لا يَكُون الحل الأمثل حاليًا بينما ما نزال نبدأ خطواتنا الأولى. بالإضافة إلى ذلك، قدمت الجافا منذ إصدارها السادس الصَنْف <code>Console</code> لأغراض التواصل مع المُستخدِم، ولكنه يُعاني هو الآخر من بعض المشاكل، فهو أولًا غَيْر متاح دائمًا للاِستخدَام كما أنه قادر على قراءة السَلاسِل النصية (strings) فقط وليس الأعداد. يرى الكاتب أن الصَنْفين <code>Scanner</code> و <code>Console</code> لا يقومان بالأشياء على نحوٍ صحيحٍ تمامًا، لذلك فإنه سيَعتمِد على صَنْف خاص <code>TextIO</code> عَرَّفه بنفسه، ولكن سنتعرَّض أيضًا إلى الصَنْف <code>Scanner</code> بنهاية هذا القسم في حال أردت أن تبدأ باِستخدَامه.
</p>

<p>
	يُمكِنك أن تُنشِئ أصنافًا (classes) جديدة تَتَضمَّن برامجًا فرعيةً (subroutines) غَيْر مُتاحة بالجزء القياسي من لغة الجافا. بمُجرّد إِنشائك لصنف جديد، يُمكِنك أن تَستخدِم البرامج الفرعية (subroutines) المُعرَّفة بداخله بنفس الكيفية التي تَستخدِم بها البرامج المبنية مُسْبَقًا (built-in). على سبيل المثال، يَحتوِي الصَنْف <code>TextIO</code> الذي عرَّفه الكاتب على برامج فرعية (subroutines) لقراءة أي مُدْخَلات يَكْتُبها المُستخدِم من خلال كائن الدَخْل القياسي (standard input)‏ <code>System.in</code> وذلك بدون الحاجة لأي مَعرِفة مُتقدمة بالجافا والتي يَتَطلَّبها كُلًا من اِستخدَام الصنف <code>Scanner</code> والاِستخدَام المباشر للكائن <code>System.in</code>.
</p>

<p>
	لاحِظ أن الصَنْف <code>TextIO</code> مُعرَّف بـ"حزمة (package)" اسمها <code>textio</code> مما يَعنِي وقوع الملف <code>TextIO.java</code> بمجلد اسمه <code>textio</code> كما يَعنِي أنه من الضروري لأي برنامج يَرغَب باِستخدَام الصَنْف <code>TextIO</code> من أن "يستورد (import)" ذلك الصَنْف من الحزمة <code>textio</code> أولًا بكتابة مُوجِّه الاستيراد <code>import</code> التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_13" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span></pre>

<p>
	لابُدّ أن يأتي الموجِّه بالأعلى قَبْل عبارة <code>public class</code> المُستخدَمة لبدء البرنامج. لاحِظ أن غالبية أصناف الجافا القياسية (standard classes) مُعرَّفة ضِمْن حزم (packages) ينبغي اِستيرادها (import) بنفس الطريقة إلى البرامج التي تَستخدِمها.
</p>

<p>
	لكي تَتَمكَّن من اِستخدَام الصَنْف <code>TextIO</code> ضِمْن برنامج، لابُدّ أن تَتَأكَّد أولًا من تَوفُّر الصَنْف (class) بذلك البرنامج. يختلف ما يَعنِيه ذلك بحسب بيئة برمجة الجافا (Java programming environment) المُستخدَمة، ولكن ينبغي عمومًا أن تُضيف المجلد <code>textio</code> -الذي يحتوي على الملف <code>TextIO.java</code>- إلى مجلد البرنامج الرئيسي. اُنظر القسم ٢.٦ لمزيد من المعلومات عن كيفية اِستخدَام الصَنْف <code>TextIO</code>.
</p>

<p>
	تُعدّ برامج (routines) الإِدْخَال المُعرَّفة بالصَنْف <code>TextIO</code> أعضاء دوال ساكنة (static member functions) ضِمْن ذلك الصنف (ناقشنا ما يعنيه ذلك بالقسم السابق). إذا كنت تَرغَب بكتابة برنامج يَقرأ عددًا صحيحًا مُدْخَلًا من قِبَل المُستخدِم، فيُمكِنك إذًا أن تَستخدِم الصَنْف <code>TextIO</code> حيث يَتَضمَّن عضو دالة ساكن مُعرَّف خصيصًا لذلك الغرض اسمه هو <code>getlnInt</code>. نظرًا لأن تلك الدالة (function) مُعرَّفة ضِمْن الصَنْف <code>TextIO</code>، فلابُدّ إذًا أن تَستخدِم الاسم <code>TextIO.getlnInt</code> للإشارة إليها ضِمْن البرنامج. لا تَستقبِل تلك الدالة أية مُعاملات (parameters)، لذا يَكُون استدعائها على الصورة <code>TextIO.getlnInt()‎</code>. يُعيد ذلك الاستدعاء قيمة من النوع <code>int</code> تُمثِل القيمة التي أَدْخَلها المُستخدِم، والتي ستَرغَب عادةً في اِستخدَامها بشكل أو بآخر لذا سنُسنِدها إلى مُتْغيِّر (variable). بِفَرض أن <code>userInput</code> عبارة عن مُتْغيِّر (variable) من النوع <code>int</code> صَرَّحنا عنه بتَعْليمَة تّصْرِيح (declaration statement) مثل <code>int userInput;‎</code>، نستطيع إذًا أن نُسنِد إليه القيمة المُعادة باِستخدَام تَعْليمَة الإِسْناد (assignment statement) التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_15" style="">
<span class="pln">userInput </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span></pre>

<p>
	عندما يُنفِّذ الحاسوب التَعْليمَة بالأعلى، فإنه سينتظر إلى أن يُدْخِل المُستخدِم قيمة من النوع العددي الصحيح أي لابُدّ أولًا أن يُدْخِل المُستخدِم عددًا ثم يَضغَط على مفتاح العودة إلى بداية السطر (return) لكي يُكمِل البرنامج عمله. ستُعيد الدالة (function) المُستدعَاة بالأعلى القيمة التي أَدْخَلها المُستخدِم، والتي ستُخزَّن بالمُتْغيِّر <code>userInput</code>. يَستخدِم البرنامج التالي الدالة <code>TextIO.getlnInt</code> لقراءة العدد المُدْخَل من قِبَل المُستخدِم ثم يَعرِض مربع ذلك العدد (لاحِظ مُوجّه الاستيراد [import] بأول سطر):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_17" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">PrintSquare</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

     </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">int</span><span class="pln"> userInput</span><span class="pun">;</span><span class="pln">  </span><span class="com">// العدد الذي أدخله المستخدم</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> square</span><span class="pun">;</span><span class="pln">     </span><span class="com">// قيمة مربع العدد الذي أدخله المستخدم</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Please type a number: "</span><span class="pun">);</span><span class="pln">
        userInput </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">
        square </span><span class="pun">=</span><span class="pln"> userInput </span><span class="pun">*</span><span class="pln"> userInput</span><span class="pun">;</span><span class="pln">

        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The number that you entered was "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> userInput</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"The square of that number is "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> square</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">

     </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية main()</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// نهاية الصنف‫ PrintSquare</span></pre>

<p>
	يَعرِض البرنامج بالأعلى الرسالة النصية "Please type a number:‎" عند تَشْغِيله ثم يَنتظِر إلى أن يَتَلقَّى إجابة مُكوَّنة من عدد يتبعه محرف العودة إلى بداية السطر (carriage return). لاحِظ أنه من الأفضل دومًا لأي برنامج أن يَطبَع سؤالًا للمُستخدِم قبلما يُحاوِل أن يقرأ أي قيم مُدْخَلة؛ لأنه في حالة غياب ذلك، قد لا يَتَمكَّن المُستخدِم من معرفة نوع القيمة التي ينتظرها الحاسوب بل إنه قد لا يَتَمكَّن حتى من ملاحظة كَوْن البرنامج ينتظره لأن يُدْخِل قيمة في العموم.
</p>

<h2>
	دوال الإدخال بالصنف <code>TextIO</code>
</h2>

<p>
	يَتَضمَّن الصَنْف <code>TextIO</code> تشكيلة متنوعة من الدوال (functions) لقراءة الأنواع (types) المختلفة التي يُمكِن للمُستخدِم أن يُدْخِلها. تَستعرِض القائمة التالية عددًا من تلك الدوال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_19" style="">
<span class="pln">j </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnInt</span><span class="pun">();</span><span class="pln">     </span><span class="com">// ‫اقرأ قيمة من النوع int</span><span class="pln">
y </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">  </span><span class="com">// ‫اقرأ قيمة من النوع double</span><span class="pln">
a </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnBoolean</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫اقرأ قيمة من النوع boolean</span><span class="pln">
c </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnChar</span><span class="pun">();</span><span class="pln">    </span><span class="com">// ‫اقرأ قيمة من النوع char</span><span class="pln">
w </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnWord</span><span class="pun">();</span><span class="pln">    </span><span class="com">// ‫اقرأ كلمة واحدة كقيمة من النوع String</span><span class="pln">
s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">        </span><span class="com">// ‫اقرأ سطرًا مدخلًا بالكامل كقيمة من النوع String</span></pre>

<p>
	لكي تُصبِح أي من تَعْليمَات الإِسْناد (assignment) بالأعلى صالحة، ينبغي أولًا أن تُصرِّح (declare) عن المُتْغيِّر الموجود على جانبها الأيسر كما ينبغي للمُتْغيِّر أن يَكُون من نفس النوع المُعاد (return type) من الدالة على الجانب الأيمن. لا تَستقبِل تلك الدوال أية مُعاملات (parameters)، وتُعيد قيم تُمثِل ما أَدْخَله المُستخدِم أثناء تَشْغِيل البرنامج، والتي ينبغي أن نُسنِدها (assign) إلى مُتْغيِّرات (variable) حتى نَتَمكَّن من اِستخدَامها ضِمْن البرنامج، حيث سنَتَمكَّن عندها من اِستخدَام أسماء تلك المُتْغيِّرات للإشارة إلى مُدْخَلات المُستخدِم.
</p>

<p>
	عندما تَستدعِي واحدة من تلك الدوال (functions)، فإنها ستُعيد دومًا قيمة صالحة من النوع المُحدَّد، ففي حالة أَدْخَل المُستخدِم قيمة غَيْر صالحة كمُدْخَل أي إذا طلب البرنامج قيمة من النوع <code>int</code> ولكن المُستخدِم أَدْخَل محرفًا (character) غَيْر عددي أو أَدْخَل عددًا يَقَع خارج النطاق المسموح به للقيم التي يُمكِن تَخْزِينها بمُتْغيِّر (variable) من النوع <code>int</code>، فسيَطلُب الحاسوب من المُستخدِم أن يُعيد إِدْخَال القيمة وسيتصرف كما لو أنه لمْ يَر القيمة غَيْر الصالحة نهائيًا. تَسمَح الدالة <code>TextIO.getlnBoolean()‎</code> للمُستخدِم بكتابة أي من القيم التالية: <code>true</code> و <code>false</code> و <code>t</code> و <code>f</code> و <code>yes</code> و <code>no</code> و <code>y</code> و <code>n</code> و <code>1</code> و <code>0</code> كما تَسمَح باِستخدَام كُلًا من الأحرف الأبجدية الكبيرة (upper case) والصغيرة (lower case). في جميع الأحوال، يُفسَّر مُدْخَل المُستخدِم على أساس كَوْنه مُكافِئ للقيمة <code>true</code> أو للقيمة <code>false</code>. عادةً ما تُستخدَم الدالة <code>TextIO.getlnBoolean()‎</code> لقراءة إجابة المُستخدِم على أسئلة "نعم أم لا".
</p>

<p>
	يُوفِّر الصَنْف <code>TextIO</code> دالتي إِدْخَال (input functions) تُعيد كلتاهما قيمة من النوع <code>String</code> هما: <code>getlnWord()‎</code> و <code>getln()‎</code>. تُعيد الأولى <code>getlnWord()‎</code> سِلسِلة نصية (string) مُكوَّنة من محارف (characters) فقط بدون أي فراغات (spaces)، حيث تَتَخطَّى عند اِستدعَائها أي فراغ (spaces) أو محرف عودة إلى بداية السطر (carriage return) يُمكِن أن يَكُون المُستخدِم قد أَدْخَله ثم تبدأ بقراءة المحارف إلى أن تَصِل إلى أول فراغ أو أول محرف عودة إلى بداية السطر، وعندها تُعيد سِلسِلة نصية من النوع <code>String</code> مُكوَّنة من المحارف المقروءة. في المقابل، تُعيد دالة الإِدْخَال الثانية <code>getln()‎</code> سِلسِلة نصية (string) مُكوَّنة من أية محارف أَدْخَلها المُستخدِم بما في ذلك أي فراغات إلى أن تَصِل إلى محرف عودة إلى بداية السطر (carriage return) أي أنها تَقرَأ سطرًا كاملًا من النص المُدْخَل. في حين يقرأ الحاسوب محرف العودة إلى بداية السطر (carriage return) إلا أنه لا يَعُدّه جزءًا من السِلسِلة النصية المُدْخَلة حيث يُهمله الحاسوب بَعْد قراءته. لاحِظ أنه إذا اِكتفَى المُستخدِم بالضغط على محرف العودة إلى بداية السطر بدون أن يَكْتُب أي شيء قبلها، ستُعيد عندها الدالة <code>TextIO.getln()‎</code> سِلسِلة نصية فارغة <code>""</code> لا تَحتوِي على أية محارف نهائيًا.
</p>

<p>
	لا تتخطَّى دالة الإِدْخَال <code>TextIO.getln()‎</code> أية فراغات أو محارف نهاية السطر قبل قراءة القيمة المُدْخَلة. يختلف ذلك عن دوال الإِدْخَال الآخرى <code>getlnInt()‎</code> و <code>getlnDouble()‎</code> و <code>getlnBoolean()‎</code> و <code>getlnChar()‎</code> والتي تُشبه الدالة <code>getlnWord()‎</code> فيما يَتَعلَّق بتخطّيها لأية فراغات أو محارف عودة إلى بداية السطر (carriage returns) قبل بدئها بقراءة القيمة الفعليّة المُدْخَلة. عندما تَتَخطَّى إحدى تلك الدوال (functions) محرف نهاية السطر، فإنها تَطبَع العلامة '?' كإشارة للمُستخدِم بأن البرنامج ما يزال يَتَوقَّع بعض المُدْخَلات الآخرى.
</p>

<p>
	بالإضافة إلى ذلك، إذا أَدْخَل المُستخدِم محارفًا إضافية بنفس سطر القيمة الفعليّة المُدْخَلة، سيُهمِل الحاسوب جميع تلك المحارف الإضافية مع محرف العودة إلى بداية السطر (carriage return) الموجود بنهاية السطر. يترتب على ذلك أنه إذا اِستدعَى برنامج معين دالة إِدْخَال (input function) آخرى، فسيَكُون المُستخدِم مُضطّرًا لأن يُدْخِل سطرًا جديدًا حتى لو كان قد أَدْخَل عدة قيم بالسطر الأول. قد لا يَكُون إهمال الحاسوب لمُدْخَلات المُستخدِم بتلك الطريقة أمرًا جيدًا، ولكنه في الواقع الحل الأسلم بغالبية البرامج.
</p>

<p>
	باِستخدَامنا للصَنْف <code>TextIO</code> لكُلًا من المُدْخلات والمخرجات، نستطيع الآن أن نُحسِّن برنامج حساب قيمة الاستثمار من القسم ٢.٢، فيُمكِننا مثلًا أن نَسمَح للمُستخدِم بأن يُدْخِل قيمًا مبدئية لكُلًا من الاستثمار ومُعدّل الفائدة مما سيُعطِينا برنامجًا أكثر فائدة نَرغَب بتَشْغِيله أكثر من مرة. يَستخدِم البرنامج التالي خَرْجًا مُنسَّقًا (formatted output) لطباعة القيم النقدية بالصياغة المناسبة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_21" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Interest2</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

       </span><span class="kwd">double</span><span class="pln"> principal</span><span class="pun">;</span><span class="pln">  </span><span class="com">// قيمة الاستثمار</span><span class="pln">
       </span><span class="kwd">double</span><span class="pln"> rate</span><span class="pun">;</span><span class="pln">       </span><span class="com">// قيمة معدل الفائدة السنوية</span><span class="pln">
       </span><span class="kwd">double</span><span class="pln"> interest</span><span class="pun">;</span><span class="pln">   </span><span class="com">// الفائدة المكتسبة خلال العام</span><span class="pln">

       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter the initial investment: "</span><span class="pun">);</span><span class="pln">
       principal </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">

       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter the annual interest rate (as a decimal): "</span><span class="pun">);</span><span class="pln">
       rate </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">

       interest </span><span class="pun">=</span><span class="pln"> principal </span><span class="pun">*</span><span class="pln"> rate</span><span class="pun">;</span><span class="pln">       </span><span class="com">// إحسب فائدة العام</span><span class="pln">
       principal </span><span class="pun">=</span><span class="pln"> principal </span><span class="pun">+</span><span class="pln"> interest</span><span class="pun">;</span><span class="pln">  </span><span class="com">// أضفها إلى المبلغ الأساسي</span><span class="pln">

       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"The amount of interest is $%1.2f%n"</span><span class="pun">,</span><span class="pln"> interest</span><span class="pun">);</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"The value after one year is $%1.2f%n"</span><span class="pun">,</span><span class="pln"> principal</span><span class="pun">);</span><span class="pln">

   </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية main()</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف Interest2</span></pre>

<p>
	قد تتساءل عن سبب وجود برنامج خَرْج (output routine) وحيد <code>System.out.println</code> بإِمكانه طباعة جميع أنواع القيم بينما تَتَوفَّر برامج إِدْخَال (input routine) متعددة لكل نوع على حدى. في الواقع، نظرًا لأن دالة الخَرْج (output function) تَستقبِل القيمة المطلوب طباعتها بهيئة مُعامل، فإن الحاسوب يُمكِنه أن يُحدِّد نوع القيمة بفَحْص قيمة المُعامل. في المقابل، لا تَستقبِل برامج الإِدْخَال (input routines) أية مُعاملات (parameters) لذا كان من الضروري اِستخدَام اسم مختلف لكل برنامج من برامج الإِدْخَال حتى يَتَمكَّن الحاسوب من التمييز بينها.
</p>

<h2>
	الملفات كمدخلات ومخرجات
</h2>

<p>
	يُرسِل <code>System.out</code> الخَرْج إلى مقصد خَرْج (output destination) يُعرَف باسم "الخَرْج القياسي (standard output)". يُمثِل الخَرْج القياسي مقصدًا واحدًا فقط ضِمْن عدة مقاصد خَرْج مُحتمَلة، فيُمكِنك مثلًا أن تَكْتُب البيانات إلى ملف مُخزَّن ضِمْن قرص صلب، وهو ما يتميز بعدة أمور منها أن البيانات ستَبقَّى مُخزَّنة بالملف إلى ما بَعْد انتهاء البرنامج كما ستَتَمكَّن من طباعة الملف أو إرساله عبر البريد الالكتروني إلى شخص آخر أو حتى تَعْدِيله باستخدام برنامج آخر. على نحو مُشابه، يُمثِل <code>System.in</code> مصدرًا واحدًا مُحتمَلًا للمُدْخَلات.
</p>

<p>
	يستطيع الصَنْف <code>TextIO</code> أن يقرأ من ويَكْتُب إلى الملفات. يَتَضمَّن الصنف <code>TextIO</code> دوال الخَرْج <code>TextIO.put</code> و <code>TextIO.putln</code> و <code>TextIO.putf</code> والتي تَعمَل بنفس طريقة عَمَل الدوال <code>System.out.print</code> و <code>System.out.println</code> و <code>System.out.printf</code> على الترتيب. علاوة على ذلك، يُمكِن أيضًا اِستخدَامها لإرسال نصوص إلى ملفات أو إلى أي مقاصد خَرْج آخرى.
</p>

<p>
	عندما تَستخدِم أي من دوال الخَرْج <code>TextIO.put</code> أو <code>TextIO.putln</code> أو <code>TextIO.putf</code>، يُرسَل الخَرْج إلى مقصد الخَرْج الحالي (output destination)، والذي يُمثِل ما يُعرَف باسم "الخَرْج القياسي (standard output)" على نحو افتراضي، ولكن تستطيع تَغْيِيره باِستخدَام برامج فرعية (subroutines) مُعرَّفة بالصَنْف <code>TextIO</code>، فمثلًا، يُمكِنك أن تَستخدِم التَعْليمَة التالية لكي تَكْتُب إلى ملف اسمه "result.txt":
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_23" style="">
<span class="typ">TextIO</span><span class="pun">.</span><span class="pln">writeFile</span><span class="pun">(</span><span class="str">"result.txt"</span><span class="pun">);</span></pre>

<p>
	بمُجرّد تّنْفيذ التَعْليمَة السابقة، سيُرسَل الخَرْج الناتج عن أي من تَعْليمَات الصَنْف <code>TextIO</code> إلى ملف اسمه هو "results.txt" بدلًا من أن تُرسَل إلى الخَرْج القياسي (standard output). لاحظ أنه إذا لم يَكُن هنالك أي ملف يَحمِل نفس الاسم، فسيُنشَئ واحدًا جديدًا أما في حالة وجوده، فستُحذَف محتوياته السابقة دون أي تحذير.
</p>

<p>
	بَعْد استدعاء <code>TextIO.writeFile</code>، سيَتَذكَّر الصَنْف <code>TextIO</code> ذلك الملف وسيُرسِل أي خَرْج ناتج عن الدالة <code>TextIO.put</code> أو عن أي دوال خَرْج آخرى إلى ذلك الملف أتوماتيكيًا. إذا أردت أن تعود مجددًا إلى الكتابة إلى الخَرْج القياسي (standard output)، يُمكِنك استدعاء ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_25" style="">
<span class="typ">TextIO</span><span class="pun">.</span><span class="pln">writeStandardOutput</span><span class="pun">();</span></pre>

<p>
	يَطلُب البرنامج بالأسفل من المُستخدِم أن يُجيب على بضعة أسئلة ثم يُخرِج تلك الإجابات إلى ملف اسمه "profile.txt". يَستخدِم البرنامج الصَنْف <code>TextIO</code> لإرسال الخَرْج إلى كُلًا من الخَرْج القياسي (standard output) والملف المذكور، ولكن يُمكِن أيضًا اِستخدَام <code>System.out</code> لإرسال الخَرْج إلى الخَرْج القياسي (standard output).
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_27" style="">
<span class="kwd">import</span><span class="pln"> textio</span><span class="pun">.</span><span class="typ">TextIO</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CreateProfile</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">String</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">     </span><span class="com">// اسم المستخدم</span><span class="pln">
        </span><span class="typ">String</span><span class="pln"> email</span><span class="pun">;</span><span class="pln">    </span><span class="com">// البريد الإلكتروني للمستخدم</span><span class="pln">
        </span><span class="kwd">double</span><span class="pln"> salary</span><span class="pun">;</span><span class="pln">   </span><span class="com">// المرتب السنوي للمستخدم</span><span class="pln">
        </span><span class="typ">String</span><span class="pln"> favColor</span><span class="pun">;</span><span class="pln"> </span><span class="com">// اللون المفضل للمستخدم</span><span class="pln">

        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(</span><span class="str">"Good Afternoon!  This program will create"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(</span><span class="str">"your profile file, if you will just answer"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(</span><span class="str">"a few simple questions."</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">();</span><span class="pln">

        </span><span class="com">/* اقرأ إجابات المستخدم */</span><span class="pln">

        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="str">"What is your name?           "</span><span class="pun">);</span><span class="pln">
        name </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="str">"What is your email address?  "</span><span class="pun">);</span><span class="pln">
        email </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="str">"What is your yearly income?  "</span><span class="pun">);</span><span class="pln">
        salary </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getlnDouble</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="str">"What is your favorite color? "</span><span class="pun">);</span><span class="pln">
        favColor </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getln</span><span class="pun">();</span><span class="pln">

        </span><span class="com">// ‫اكتب بيانات المستخدم المدخلة إلى الملف profile.txt</span><span class="pln">

        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">writeFile</span><span class="pun">(</span><span class="str">"profile.txt"</span><span class="pun">);</span><span class="pln">  </span><span class="com">// يرسل الخرج التالي إلى الملف</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(</span><span class="str">"Name:            "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name</span><span class="pun">);</span><span class="pln"> 
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(</span><span class="str">"Email:           "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> email</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(</span><span class="str">"Favorite Color:  "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> favColor</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putf</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Yearly Income:   %,1.2f%n"</span><span class="pun">,</span><span class="pln"> salary</span><span class="pun">);</span><span class="pln">

        </span><span class="com">/* اطبع رسالة أخيرة إلى الخرج القياسي */</span><span class="pln">

        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">writeStandardOutput</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">putln</span><span class="pun">(</span><span class="str">"Thank you.  Your profile has been written to profile.txt."</span><span class="pun">);</span><span class="pln">

    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	إذا أردت أن تَسمَح للمُستخدِم بأن يختار الملف المطلوب اِستخدَامه للخَرْج، يُمكِنك مثلًا أن تَطلُب منه أن يَكْتُب اسم الملف، ولكن يَكُون ذلك عُرضة للخطأ كما أن المُستخدِمين عادةً ما يكونوا مُعتادين على نوافذ اختيار الملفات، لهذا سنَستخدِم التَعْليمَة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_29" style="">
<span class="typ">TextIO</span><span class="pun">.</span><span class="pln">writeUserSelectedFile</span><span class="pun">();</span></pre>

<p>
	ستَعرِض التَعْليمَة السابقة واجهة مُستخدِم رسومية (graphical user interface) عبارة عن نافذة اختيار ملف تقليدية. ستَسمَح تلك النافذة للمُستخدِم بأن يختار ملف خَرْج معين أو بأن يُغلِقها دون اختيار أي ملف. تتميز تلك الطريقة بإمكانية تَنبِيه المُستخدِم في حالة كان مُوشِكًا على استبدال ملف موجود بالفعل. تُعيد الدالة <code>TextIO.writeUserSelectedFile</code> قيمة من النوع <code>boolean</code> ستُساوِي <code>true</code> في حالة اختيار ملف وستُساوِي <code>false</code> في حالة غلق النافذة. قد يَفْحَص برنامج معين القيمة المُعادة (return value) من تلك الدالة ليَعرِف ما إذا كان عليه أن يَكْتُب البيانات إلى ملف أم لا.
</p>

<p>
	إلى جانب قراءة المُدْخَلات من "الدَخْل القياسي (standard input)"، يستطيع الصَنْف <code>TextIO</code> القراءة من ملف. ستحتاج فقط إلى تَخْصِيص مصدر المُدْخَلات (input source) الخاصة بالدوال المُعرَّفة بالصَنْف <code>TextIO</code>، وهو ما يُمكِنك القيام به إما باِستخدَام التَعْليمَة <code>TextIO.readFile("data.txt")‎</code> للقراءة من ملف اسمه "data.txt" أو باِستخدَام <code>TextIO.readUserSelectedFile()‎</code> والتي تُظهِر واجهة مُستخدِم رسومية (GUI) عبارة عن نافذة اختيار ملف تَسمَح للمُستخدِم بأن يختار ملفًا. بََعْد انتهائك من ذلك، سيُقرَأ أي دَخْل بَعْدها من الملف المُختار لا من مُدْخَلات المُستخدِم. يُمكِنك استدعاء الدالة <code>TextIO.readStandardInput()‎</code> للعودة مرة آخرى إلى الوضع الافتراضي أي قراءة المُدْخَلات المَكْتُوبة من قِبَل المُستخدِم.
</p>

<p>
	إذا كان البرنامج يَقَرأ المُدْخَلات من الدَخْل القياسي (standard input)، فسيَتَمكَّن المُستخدِم إذًا من تصحيح أية أخطاء ضِمْن تلك المُدْخَلات أما إذا كان يَقَرأها من ملف، فلن يَكُون ذلك مُمكِنًا لذا إذا عُثِر على بيانات غَيْر صالحة، سيَحدُث خطأ وسينهار (crash) البرنامج. قد تَحدُث بعض الأخطاء أيضًا عند مُحاولة الكتابة إلى ملف ولكنها تُعدّ أقل شيوعًا.
</p>

<p>
	يَتَطلَّب الفهم الكامل للمُدْخَلات والمُخْرَجات بلغة الجافا مَعرِفة بمفاهيم البرمجة كائنية التوجه (object oriented programming)، لذا سنعود مجددًا إلى نفس هذا الموضوع بالفصل الحادي عشر بَعْدما نَكُون قد ناقشنا تلك المفاهيم. تُعدّ إمكانيات الصَنْف <code>TextIO</code> فيما يَتَعلَّق بقراءة الملفات وكتابتها بدائية نوعًا ما، ولكنها كافية لغالبية التطبيقات كما أنها ستَمنَحك بعض الخبرة في التَعامُل مع الملفات.
</p>

<h2>
	خصائص أخرى بالصنف <code>TextIO</code>
</h2>

<p>
	تَعرَّضنا لمجموعة من دوال الإِدْخَال المُعرَّفة بالصَنْف <code>TextIO</code> والتي بإِمكانها قراءة قيمة واحدة فقط من سطر مُدْخَل. إذا أردت قراءة أكثر من مُجرّد قيمة واحدة من نفس السطر المُدْخَل، فمثلًا، قد تَرغَب بتَمْكِين المُستخدِم من كتابة سطر مثل "42 17" لكي يُدْخِل العددين ٤٢ و ١٧. يُوفِّر الصَنْف <code>TextIO</code> لحسن الحظ دوال إِدْخَال (input functions) آخرى مُعرَّفة خصيصًا لذلك الغرض. اُنظر الأمثلة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_31" style="">
<span class="pln">j </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getInt</span><span class="pun">();</span><span class="pln">     </span><span class="com">// ‫اقرأ قيمة من النوع int</span><span class="pln">
y </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getDouble</span><span class="pun">();</span><span class="pln">  </span><span class="com">// ‫اقرأ قيمة من النوع double</span><span class="pln">
a </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getBoolean</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫اقرأ قيمة من النوع boolean</span><span class="pln">
c </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getChar</span><span class="pun">();</span><span class="pln">    </span><span class="com">// ‫اقرأ قيمة من النوع char</span><span class="pln">
w </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextIO</span><span class="pun">.</span><span class="pln">getWord</span><span class="pun">();</span><span class="pln">    </span><span class="com">// ‫اقرأ كلمة واحدة كقيمة من النوع String</span></pre>

<p>
	تبدأ أسماء الدوال بالأعلى بكلمة "get" بدلًا من كلمة "getln" التي تُعدّ اختصارًا للكلمتين "get line" أي "اِجلب سطرًا" وهو ما ينبغي أن يُذكِّرك بأنها تقرأ سطرًا مُدْخَلًا بالكامل. في المقابل، تقرأ الدوال بدون "ln" قيمة مُدْخَلة واحدة بنفس الطريقة لكنها لا تُهمِل بقية السطر المُدْخَل بل تَحتفِظ به كما هو ضِمْن ذاكرة داخلية تُعرَف باسم "مُخزِّن المُدْخَلات المُؤقت (input buffer)". عندما يحتاج الحاسوب إلى قراءة قيمة مُدْخَلة آخرى، فإنه سيَفْحَص أولًا مُخزِّن المُدْخَلات المؤقت قبلما يَطلُب من المُستخدِم إِدْخِال أي قيم جديدة، مما سيَسمَح بقراءة عدة قيم من سطر مُدْخَل واحد. بتعبير أكثر دقة، يقرأ الحاسوب دومًا من مُخزِّن المُدْخَلات المؤقت، ففي المرة الأولى التي سيُحاوِل فيها البرنامج قراءة قيمة مُدْخَلة من المُستخدِم، سينتظر الحاسوب إلى أن ينتهي المُستخدِم من كتابة سطر كامل من المُدْخَلات، ثُمَّ سيَحتفِظ الصَنْف <code>TextIO</code> بذلك السطر ضِمْن مُخزِّن مُدْخَلات مُؤقت (input buffer) إلى أن يُقرأ أو يُهمَل بواسطة إحدى دوال "getln". سيَضطّر المُستخدِم إلى إِدْخَال سطر جديد فقط عندما يُصبِح مُخزِّن المُدْخَلات المُؤقت (buffer) فارغًا.
</p>

<p>
	ستَتَخطَّى دوال الإِدْخَال (input functions) المُعرَّفة بالصَنْف <code>TextIO</code> أية فراغات (spaces) أو محارف عودة إلى بداية السطر (carriage returns) عند محاولتها قراءة القيمة المُدْخَلة التالية، ولكنها مع ذلك لن تَتَخطَّى أية محارف آخرى. فمثلًا، إذا أَدْخَل المُستخدِم السطر "42,17" بينما كنت تُحاوِل قراءة قيمتين من النوع <code>int</code>، فسيَتَمكَّن الحاسوب من قراءة العدد الأول بشكل سليم، ولكنه عندما يُحاوِل قراءة العدد الثاني، فستُقابله فاصلة <code>,</code>، وهو ما يُعدّ خطأ لذا سيَطلُب الحاسوب من المُستخدِم أن يُعيد إدخال العدد الثاني أي إذا أردت أن تَسمَح للمُستخدِم بأن يُدْخِل عدة قيم ضِمْن سطر واحد، فينبغي أن تُخبره بأن عليه أن يَستخدِم فراغًا لا فاصلة بين كل عدد والذي يليه. أما إذا كنت تُفضِّل السماح له باِستخدَام فاصلة (comma)، فاِستخدِم الدالة <code>getChar()‎</code> لقرائتها أولًا قَبْل أن تُحاوِل قراءة العدد الثاني.
</p>

<p>
	يُوفِّر الصَنْف <code>TextIO</code> دالة آخرى لإِدْخَال محرف واحد هي <code>TextIO.getAnyChar()‎</code> والتي لا تَتَخطَّى أية محارف نهائيًا، فهي ببساطة تقرأ المحرف التالي المُدْخَل من قِبَل المُستخدِم حتى لو كان ذلك المحرف فراغًا أو محرف عودة إلى بداية السطر (carriage return). فمثلًا، إذا أَدْخَل المُستخدِم محرف عودة إلى بداية السطر، فسيَكُون المحرف المُعاد من الدالة <code>getAnyChar()‎</code> عبارة عن محرف إضافة سطر جديد <code>‎\n</code>. يُوفِّر الصَنْف <code>TextIO</code> دالة (function) آخرى هي <code>TextIO.peek()‎</code> تَفْحَص المحرف المُدْخَل التالي دون قرائته بصورة فعلية أي أنه سيَظِلّ متاحًا للقراءة حتى بَعْدما تَفْحَصه باِستخدَام تلك الدالة، وعليه ستَتَمكَّن من مَعرِفة قيمة المُدْخَل التالي وربما حتى اتِّخاذ إِجراءات مختلفة وفقًا لقيمته. يُوفِّر الصَنْف <code>TextIO</code> مجموعة آخرى من الدوال (functions) يُمكِنك الإطلاع عليها بملف الشيفرة المصدرية <code>TextIO.java</code> كما أنها مرفقة بتعليقات (comments) للمساعدة.
</p>

<p>
	يتَّضح لنا أن المُدْخَلات أكثر تعقيدًا من المُخْرَجات إلى حد ما، ولكن يُعدّ اِستخدَامها بسيطًا بأغلب التطبيقات من الناحية العملية أما إذا كنت تُحاوِل القيام بشيء مميز، فقد تحتاج إلى المزيد من التفاصيل. يُنصَح عمومًا بالاعتماد على برامج الإِدْخَال (input routines) التي يَحتوِي اسمها على كلمة "getln" وليس كلمة "get" لأنها أبسط بكثير إلا إذا كانت هنالك حاجة لقراءة أكثر من قيمة ضِمْن سطر مُدْخَل واحد.
</p>

<h2>
	استخدام الصنف <code>Scanner</code> للمدخلات
</h2>

<p>
	يُسهِل الصَنْف <code>TextIO</code> من قراءة مُدْخَلات المُستخدِم، ولكن ينبغي أن تُتيِح الملف <code>TextIO.java</code> لأي برنامج يَستخدِمه لأنه ليس صَنْفًا قياسيًا (standard class). في المقابل، يُعدّ الصَنْف <code>Scanner</code> جزءًا قياسيًا من الجافا أي سيَكُون متاحًا دائمًا أينما أردت اِستخدَامه لذا قد تُفضِّل اِستخدَامه.
</p>

<p>
	يُستخدَم الصَنْف <code>Scanner</code> لقراءة مُدْخَلات المُستخدِم، ويتميز في العموم بسمات رائعة، ولكن ربما يَكُون اِستخدَامه صعبًا نوعًا ما حيث يَتَطلَّب مَعرِفة ببعض قواعد الصيغة (syntax) التي لن نَتَعرَّض لها حتى نَصِل إلى الفصلين الرابع والخامس. سنَذكُر هنا طريقة اِستخدَامه سريعًا دون الخوض بأية تفاصيل، لذا لا تَقْلَق إن لم تفهم كل ما هو مَكْتُوب هنا. سنناقش الصَنْف <code>Scanner</code> تفصيليًا بالقسم الفرعي ١١.١.٥.
</p>

<p>
	أولًا، لمّا كان الصنف <code>Scanner</code> مُعرَّف بحزمة <code>java.util</code>، ينبغي أن تُضيف مُوجّه (directive) الاستيراد <code>import</code> التالي إلى بداية ملف الشيفرة بالبرنامج الخاص بك أي قَبْل كلمة <code>public class</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_33" style="">
<span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.</span><span class="typ">Scanner</span><span class="pun">;</span></pre>

<p>
	ثم سنُضِيف التَعْليمَة التالية إلى بداية البرنامج <code>main()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_35" style="">
<span class="typ">Scanner</span><span class="pln"> stdin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Scanner</span><span class="pun">(</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="pln">in </span><span class="pun">);</span></pre>

<p>
	تُنشِي تلك التَعْليمَة مُتْغيِّرًا (variable) اسمه <code>stdin</code> من النوع <code>Scanner</code>. تُعدّ كلمة <code>stdin</code> اختصارًا للكلمتين "standard input" مما يَعنِي "دَخْل قياسي"، ولكن يُمكِنك أن تَستخدِم أي اسم آخر للمُتْغيِّر إن أردت. تستطيع اِستخدَام المُتْغيِّر <code>stdin</code> للوصول إلى تشكيلة من البرامج الفرعية (subroutines) المُختصَّة بقراءة مُدْخَلات المُستخدِم، فمثلًا، تقرأ الدالة <code>stdin.nextInt()‎</code> قيمة واحدة مُدْخَلة من النوع <code>int</code> ثُم تُعيدها كقيمة للدالة أي تُشبه <code>TextIO.getInt()‎</code> إلى حد كبير باستثناء أمرين: أولًا، إذا كانت القيمة المُدْخَلة مِن قِبَل المُستخدِم غَيْر صالحة، فلن تَطلُب الدالة <code>stdin.nextInt()‎</code> من المُستخدِم أن يُعيد إِدْخَال قيمة جديدة وإنما ستَتسبَّب بحُدوث انهيار (crash). ثانيًا، لابُدّ من أن يُدْخِل المُستخدِم فراغًا أو محرف نهاية السطر بَعْد قيمة العدد الصحيح المُدْخَلة. في المقابل، تَتَوقَّف الدالة <code>TextIO.getInt()‎</code> عن قراءة المُدخلات مع أول محرف لا يُمثِل رقمًا تُقابِله.
</p>

<p>
	علاوة على ذلك، تَتَوفَّر توابعًا (methods) لقراءة الأنواع الآخرى مثل <code>stdin.nextDouble()‎</code> و <code>stdin.nextLong()‎</code> و <code>stdin.nextBoolean()‎</code> (تَقبَل الدالة <code>stdin.nextBoolean()‎</code> القيم <code>true</code> و <code>false</code> فقط). تقرأ تلك البرامج الفرعية (subroutines) أكثر من قيمة واحدة ضِمْن سطر لذا فهي أَشْبه للنُسخ "get" من البرامج الفرعية المُعرَّفة بالصَنْف <code>TextIO</code> وليس النُسخ "getln"، فمثلًا، يُعدّ التابع <code>stdin.nextLine()‎</code> مكافئًا للتابع <code>TextIO.getln()‎</code> أما التابع <code>stdin.next()‎</code> فيُكافِئ <code>TextIO.getWord()‎</code> حيث يُعيد كلاهما سِلسِلة نصية (string) من المحارف غَيْر الفارغة.
</p>

<p>
	يَستعرِض المثال التالي البرنامج <code>Interest2.java</code> مجددًا ولكن باِستخدَام الصَنْف <code>Scanner</code> بدلًا من الصَنْف <code>TextIO</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8177_37" style="">
<span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.</span><span class="typ">Scanner</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Interest2WithScanner</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

      </span><span class="typ">Scanner</span><span class="pln"> stdin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Scanner</span><span class="pun">(</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="pln">in </span><span class="pun">);</span><span class="pln">  </span><span class="com">// أنشئ كائن جديد</span><span class="pln">

      </span><span class="kwd">double</span><span class="pln"> principal</span><span class="pun">;</span><span class="pln">  </span><span class="com">// قيمة الاستثمار</span><span class="pln">
      </span><span class="kwd">double</span><span class="pln"> rate</span><span class="pun">;</span><span class="pln">       </span><span class="com">// معدل الفائدة السنوي</span><span class="pln">
      </span><span class="kwd">double</span><span class="pln"> interest</span><span class="pun">;</span><span class="pln">   </span><span class="com">// الفائدة المكتسبة خلال العام</span><span class="pln">

      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter the initial investment: "</span><span class="pun">);</span><span class="pln">
      principal </span><span class="pun">=</span><span class="pln"> stdin</span><span class="pun">.</span><span class="pln">nextDouble</span><span class="pun">();</span><span class="pln">

      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"Enter the annual interest rate (as a decimal): "</span><span class="pun">);</span><span class="pln">
      rate </span><span class="pun">=</span><span class="pln"> stdin</span><span class="pun">.</span><span class="pln">nextDouble</span><span class="pun">();</span><span class="pln">

      interest </span><span class="pun">=</span><span class="pln"> principal </span><span class="pun">*</span><span class="pln"> rate</span><span class="pun">;</span><span class="pln">       </span><span class="com">// إحسب فائدة العام</span><span class="pln">
      principal </span><span class="pun">=</span><span class="pln"> principal </span><span class="pun">+</span><span class="pln"> interest</span><span class="pun">;</span><span class="pln">  </span><span class="com">// أضف إلى الأساسي</span><span class="pln">

      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"The amount of interest is $%1.2f%n"</span><span class="pun">,</span><span class="pln"> interest</span><span class="pun">);</span><span class="pln">
      </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">printf</span><span class="pun">(</span><span class="str">"The value after one year is $%1.2f%n"</span><span class="pun">,</span><span class="pln"> principal</span><span class="pun">);</span><span class="pln">

   </span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية main()</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫نهاية الصنف Interest2WithScanner</span></pre>

<p>
	بالبرنامج أعلاه، أضفنا سطرًا لاِستيراد الصَنْف <code>Scanner</code> وآخرًا لإِنشاء الكائن <code>stdin</code>. علاوة على ذلك، بدلًا من التابع <code>TextIO.getlnDouble()‎</code>، اِستخدَمنا <code>stdin.nextDouble()‎</code>، والذي يُعدّ في العموم مُكافئًا للتابع <code>TextIO.getDouble()‎</code> ولكن كل ذلك لا يَعنِينا طالما كان المُستخدِم سيُدْخِل عددًا واحدًا فقط بكل سطر.
</p>

<p>
	سنستمر بالاعتماد على الصَنْف <code>TextIO</code> فيما يَتَعلَّق بالمُدْخَلات في العموم، ولكننا سنَستخدِم الصَنْف <code>Scanner</code> مرة آخرى بعدة أمثلة ضِمْن التمارين المُرفقة بنهاية الفصل كما سنُناقِشه تفصيليًا فيما بَعْد.
</p>

<p>
	ترجمة -بتصرّف- للقسم <a href="http://math.hws.edu/javanotes/c2/s4.html" rel="external nofollow">Section 4: Text Input and Output</a> من فصل Chapter 2: Programming in the Small I: Names and Things من كتاب <a href="http://math.hws.edu/javanotes/index.html" rel="external nofollow">Introduction to Programming Using Java</a>.
</p>
]]></description><guid isPermaLink="false">1018</guid><pubDate>Thu, 08 Oct 2020 12:40:01 +0000</pubDate></item></channel></rss>
