שיעור 02: תחביר ג'אווה

מתוך גרינפוט ישראל - מדריך ציבורי ללימוד גרינפוט
קפיצה אל: ניווט, חיפוש

<- השיעור הקודם: איך מתחילים      השיעור הבא: מערכים->

מטרת השיעור

הכתיבה בסביבת גרינפוט היא בשפת ג'אווה. בשיעור זה נכיר את התחביר הבסיסי של ג'אווה:

  • הגדרת משתנים
  • לולאות ותנאים
  • פונקציות
  • שימוש בפונקציות ספריה וב-import
  • קצת על מחלקות, על קצה המזלג

רקע נדרש

אם עדיין אינך מכיר את סביבת גרינפוט, כדאי להתחיל בשיעור 01: איך מתחילים.


אז בואו נתחיל

ג'אווה היא שפת תכנות, וכמו כל שפה - גם לה יש כללי תחביר. קוד שאינו כתוב לפי כללי התחביר לא יוכל לרוץ כתוכנית, או - גרוע יותר - יצור תוכנית שלא תעשה את מה שתכננו.

לפני שנתחיל בתחביר עצמו, כמה כללים בסיסיים לשפה:

  • ניתן לשלב בקוד הערות מהן המהדר יתעלם ולא יחשיב כקוד. מטרת ההערות היא להסביר לעצמנו ולאחרים מה קורה בקוד. בג'אווה ישנם שלושה סוגי הערות:
   1. הערת שורה - הערה בת שורה אחת, נכתבת לאחר הסימון "//"
   2. הערת קטע - קטע שכולו הערה ארוכה, נכתב בין הסימנים "/*" ו"*/"
   3. javadoc - משמש לכתיבת API עליו לא נרחיב בשיעור זה, נכתב בין הסימנים "/**" ו"*/"

דוגמא לשימוש בהערות:

/** 
API
*/
 
/*
This is a long comment
We can start a new line
and another new line
*/
 
//This is a one line comment 
 
if (i!=0) //We can also write a code and a comment in the same line
  • השפה הינה Case - sensitive, כלומר, ישנה חשיבות לאותיות גדולות וקטנות:
int num;//Create an "Integer" data type, named "num"
Num = 1; //Error! num in not Num
  • כל קטע קוד בשפה נקרא "בלוק" ותחום בין שני סוגריים מסולסלים ("מסולסליים" - {} ) ניתן "לקנן" בלוקים, כלומר, לכתוב בלוק אחד בתוך בלוק אחר. כדי לא להתבלבל, נהוג להכנס ב"טאב" אחד בכל בלוק, כמו בדוגמא הבאה (אין צורך להבין את הקוד, רק את עקרון הבלוקים):
public class myClass()
{
     public int getNum (int num)
     {
          int counter = 0;
          if(num>=0)
          {
               for (int i=0;i<num;i++)
               {
                    counter++; 
               }//End of block 4
          }//End of block 3
          return counter;
     }//End of block 2
}//End of block 1
  • כל פקודה מסתיימת ב";" (נקודה פסיק) מקובל לרדת שורה אחרי ";" אם כי מבחינת תחביר השפה אין חובה לעשות כך:
int x = 0, y = 3;
int z;
z = x*y; //That's OK
 
int x = 0, y = 3; int z; z = x*y; //That's OK but looks bad

הגדרת משתנים

מהו משתנה?

משתנים הם יחידות זכרון בהן נשתמש במהלך התוכנית. לכל משתנה ישנם שלושה מאפיינים:

  • סוג המשתנה - האם הוא מכיל מספר שלם? מספר ממשי? תו?
  • שם המשתנה - שם שניתן למשתנה בזמן ההגדרה ואינו ניתן לשינוי במהלך התוכנית. בשם זה נשתמש כשנרצה "לדבר" עם המשתנה. נהוג ששם המשתנה מתחיל באות קטנה וכל מילה חדשה בשם המשתנה תתחיל באות גדולה, לדוגמא myFirstVariable.
  • תוכן המשתנה - מספר, תו או כל ערך אחר אותו מכיל המשתנה. לרוב, ערך זה יכול להשתנות במהלך התוכנית.

סוגי משתנים

בג'אווה סוגים רבים של משתנים, נכיר כעת את הנפוצים שבהם שבהם:

סוג המשתנה תוכן דוגמאות
int מספר שלם 5, 96532876, -645
double מספר ממשי ארוך -5.89, 0.3333, 99999999999999
char תו בודד 7, r, *
boolean משתנה שיכול לקבל רק את הערכים "אמת" ו"שקר" true, false
String מחרוזת, מספר תוים Hello World, g, 7865

שימו לב! הטיפוס "String" אינו משתנה אלא אובייקט ולכן בתחילתו S גדולה. עם זאת, ג'אווה מאפשרת לנו גם להתייחס אליו כאל משתנה רגיל.

להרחבה - ישנם עוד סוגים רבים של משתנים עליהם ניתן לקרוא כאן: [1]

שימוש במשתנים

  • ליצירת המשתנה נציין את סוג המשתנה ולאחריו שמו. לדוגמא:
     int num;
    יצור משתנה מסוג "int" בשם "num"
  • ניתן להשתמש בכל שם משתנה פעם אחת בלבד. המשתנה מוכר בבבלוק בו הוא הוגדר ובבלוקים הפנימיים יותר לדוגמא:
 
int num = 0;
if (num == 0)
{
    num++;//That's OK
    int i = 3;
    int num//Error!
}
i=4;//Error!

אי אפשר להשתמש בi מחוץ לבלוק כיוון שהגדרנו אותו בתוך הבלוק. לעומת זאת num שהוגדר מחוץ לבלוק ניתן לשימוש גם בבלוק הפנימי יותר. כאשר ננסה להגדיר בתוך הבלוק משתנה נוסף בשם num נקבל שגיאה כיוון שכבר הגדרנו משתנה בשם זה מחוץ לבלוק.

  • על מנת להכניס ערך למשתנה נכתוב את שם המשתנה, הסימן "=" ולאחריו הערך. לדוגמא:
 
num = 5;
res = num;

יכניס למשתנה "num" את הערך 5, ולמשתנה "res" את הערך השמור במשתנה "num", במקרה הזה 5.

  • ניתן להגדיר מספר משתנים מאותו סוג באותה שורה, מופרדים באמצעות פסיקים. ניתן לאחד את הגדרת המשתנה והשמת הערך לשורה אחת. לדוגמא:
 
int x, y, z;
char myChar = '*';
boolean isUp = true, isOK = false;

יצרנו שלושה משתנים מסוג int בשמות x,y,z יצרנו משתנה מסוג char בשם myChar והכנסנו אליו את הערך '*'. יצרנו שני משתנים מסוג boolean, לראשון קראנו isUp והכנסנו לו את הערך true, לשני קראנו isOK והכנסנו אליו את הערך false.

קיצורים

ניתן להעלות או להוריד את הערך של משתנה במספר אחד ע"י ++ או --. ניתן להוסיף/ לחסר/ לכפול או לחלק מספר מסויים למשתנה ע"י +=, -=, *=, \= לדוגמא:

 
int x = 0
x++; //Now x = 1
x+=2; //Now x = 3
x*=5; //Now x = 15
x--; //Now x = 14


תנאים ולולאות

תנאים

  • לפעמים נרצה שפעולה מסוימת תתבצע רק כאשר תנאי מסויים מתקיים. לשם כך נועדה הפקודה if. לאחר הפקודה נכתוב את התנאי בסוגריים ואת הפקודה בבלוק. אם יש רק פקודה אחת - אין צורך בסוגריים מסלוסלים, לדוגמא:
 
if (num > 0)
   num = 2;
if (num < 0)
{
    num = -2;
    int i = num;
}

הפקודה num = 2 תתבצע רק אם המשתנה num גדול מ-0. הפקודות num = -2 וint i = num יתבצעו רק אם num קטן מ-0.

  • לאחר פקודת if ניתן להוסיף את פקודת else if, שתבדוק את התנאי רק במידה והתנאי הראשון לא התקיים, או את פקודת else שתתבצע אם אף אחד מהתנאים הקודמים לא התקיים, לדוגמא:
 
if (num > 0)
    num++;
else if (num < 0)
    num--;
else
    int x = 0;

הפקודה int x=0 תתבצע רק אם אף אחד מהתנאים הקודמים לא התקיים, כלומר num=0

אופרטורים בוליאנים

אלו האופרטורים בהם ניתן להשתמש בכתיבת התנאים:

שם האופרטור סימון דוגמא הסבר מילולי לדוגמא
שווה ל ==
if (x==0)
אם x שווה ל - 0
גדול מ, קטן מ >, <
if (x>0)
אם x גדול מ-0
גדול שווה, קטן שווה
<=,>=
if (x>=0)
אם x גדול מ-0 או שווה ל-0
לא !
if (x!=0)
אם x לא שווה ל-0
או ||
if (x > 0 || x != -2)
אם x גדול מ-0 או x שונה מ-2
וגם &&
if (x != 4 && !(x < 0))
אם x שונה מ-4 וגם לא מתקיים שx קטן מ-0

לולאות

לפעמים נרצה לבצע פעולה מסויימת או מספר פעולות כמה פעמים. לפעמים יהיה זה מספר מוגדר מראש של פעמים ולפעמים מספר הפעמים יהיה תלוי בתנאי כלשהו. ישנם שלושה סוגי לולאות:

  • לולאת for - בלולאה זו נאתחל בסוגריים שלושה פרמטרים, מופרדים באמצעות ";": אתחול משתנה, תנאי עצירה וקידום המשתנה. לאחר מכן נכתוב בבלוק או בשורה אחת את הפעולות שנרצה לחזור עליהן. לדוגמא:
for (int i = 0 ; i < 10 ; i++)
{
    if (i == num)
    {
        res = num;
    }
}

הסבר: בתחילת הלולאה נוצר משתנה int בשם i ואותחל לערך 0. בכל סיבוב של הלולאה נבדוק תחילה את תנאי העצירה - האם i קטן מ-10. אם התנאי מתקיים - נבצע את הפעולות שנמצאות בתוך הבלוק. לאחר ביצוע הפעולות נבצע i++, כלומר נעלה את הערך של i באחד ונבדוק שוב את התנאי, וחוזר חלילה. במקרה הזה, לאחר 10 "סיבובים" של הלולאה i יהיה שווה ל-10. כשנבדוק את התנאי - הוא לא יתקיים ולכן הלולאה תעצר.

  • לולאת while - בלולאה זו הקטע שבבלוק ימשיך להתבצע כל עוד התנאי שבסוגריים מתקיים, לדוגמא:
while(num > 0)
{
   res *= 10;
   num--;
}

בכל "סיבוב" של הלולאה המשתנה res יוכפל ב10 והמשתנה num ירד ב-1 עד שהמשתנה num יהיה שווה ל-0 והלולאה תעצר.

  • לולאת do while במקרה הקודם - יתכן שהמשתנה num קטן מ-0 כבר בתחילת הלולאה ובמקרה זה הקטע שבתוך הלולאה לא יתבצע כלל. אם נרצה שהלולאה תתבצע לכל הפחות פעם אחת, נשתמש בלולאת do while, כמו בדוגמא הבאה:
do
{
   res *= 10;
   num--;
}
while(num > 0);

המשתנה res יוכפל ב10, המשתנה num יקטן ב-1 ורק לאחר מכן יבדק התנאי. אם num חיובי - הלולאה תמשיך לרוץ עד שnum יהיה שווה ל-0

פונקציות

מהי פונקציה?

נניח שאתם נדרשים לכתוב תוכנית שמחשבת את ממוצע הציונים של כיתה שלמה בכל המקצועות. במהלך תוכנית כזאת נצטרך לחשב את הממוצע של כל תלמידי ותלמיד, ונראה קצת מיותר לכתוב את הקוד שעובר על מערך הציונים ומחשב את הממוצע שוב ושוב. לשם כך נועדו הפונקציות - אוסף של פקודות שיופעלו בעת הקריאה לפונקציה.

סוגי פונקציות

ישנם שני סוגי פונקציות:

  • פונקציות שמחזירות ערך
  • פונקציות void שמבצעות אוסף פעולות אך אינן מחזירות ערך.

מבנה הפונקציה

כל פוקנציה בנויה בצורה הבאה: הרשאה, הערך המוחזר מהפונקציה, שם הפונקציה, בסוגריים - הפרמטרים המועברים לפונקציה ובתוך הבלוק - הפעולות שמתבצעות בפונקציה.

  • לדוגמא, פונקציה המקבלת שני מספרים ומחשבת את הממוצע שלהם:
public double average (int num1, int num2)
{
   double res = (num1 + num2) / 2
   return res;
}

הסבר: הגדרנו פונקציה ציבורית (public), כלומר - כל מחלקה יכולה להשתמש בה, שתחזיר ערך מסוג double ושמה average. הפונקציה מקבלת כפרמטרים שני משתנים מסוג int. הפונקציה מחשבת את הממוצע של שני המספרים לתוך משתנה בשם res ומחזירה אותו באמצעות המילה השמורה return

  • דוגמא נוספת - פונקציה המקבלת כפרמטר מחרוזת ומספר שלם num ומדפיסה num פעמים על המסך "Hello, " והמילה הכתובה במחרוזת
private void specialPrint (String name, int num)
{
    for (int i = 0 ; i < num ; i++)
        System.out.println ("Hello, "+name);
}

הגדרנו פונקציה פרטית (private), כך שרק המחלקה בה היא כתובה יכולה להשתמש בה. הפונקציה היא void, כלומר לא מחזירה ערך ושמה specialPrint. היא מקבלת כפרמטר String בשם name ואז מדפיסה את המילה Hello, ואת name למסך בעזרת הפונקציה System.out.println, פונקצית הפלט הבסיסית של ג'אווה. הפעולה מתבצעת num פעמים בעזרת לולאת for

קריאה לפונקציה

כאשר נרצה לקרוא לפונקציה במהלך התוכנית נעשה זאת באמצעות שמה והכנסת הפרמטרים בסוגריים בדיוק בסדר בו הם כתובים בפונקציה. אם הפונקציה מחזירה ערך - ניתן להכניס את הערך למשתנה או להשתמש בו כמשתנה לכל דבר. לדוגמא, עבור הפונקציות מהסעיף הקודם:

double avg = average (6,10);//Now avg = 8
int x = 2, y = 6;
if (average (x,y) == 4 ) //true
    avg++;//Now avg = 9
specialPrint ("Moshe", 9);
specialPrint (9, "Moshe");//Error!
specialPrint ("Moshe", avg);//Error!

בשורה הראשונה יצרנו משתנה מסוג double בשם avg והכנסנו אליו את הערך החוזר מהפונקציה average עבור הפרמטרים 6 ו10, כלומר - ערכו יהיה 8. לאחר מכן הגדרנו שני משתנים מסוג int בשם x ו y ואתחלנו אותם לערכים 2 ו6 בהתאמה. אם הממוצע שלהם שווה ל-4 נעלה את ערך avg ב-1. לאחר מכן נפעיל את הפונקציה specialPrint עם הפרמטר Moshe, כך שעל המסך תודפס 9 פעמים המחרוזת Hello, Moshe. בקריאה השניה לפונקציה נקבל שגיאה כיוון שהחלפנו את סדר המשתנים. בקריאה השלישית לפונקציה נקבל שגיאה כיוון שהפונקציה מצפה לקבל int והמשתנה avg הוא double.

שימוש בפונקציות ספריה וב-import

בג'אווה יש פונקציות רבות שכבר נכתבו ולכן אין צורך לכתוב אותן בעצמנו. על מנת להשתמש בהן, נצטרך "לייבא" לתוכנית שלנו את הספריה בה הן נמצאות. יבוא של ספריה נעשה באמצעות המילה השמורה import ולאחר מכן שם הספריה. בדרך כלל כל ספריה מכילה גם תתי ספריות. אם נרצה לייבא את כל תתי הספריות נשתמש ב*. הספריה הראשית של ג'אווה היא java.util ושל גרינפוט - greenfoot. כדי לדעת איזה פונקציות קיימות בכל ספריה ואיך משתמשים בהן ניתן להסתכל בjavadoc שלהן, שנמצא באתר של oracle כאן: [[2]]. דוגמא לשימוש בimport:

import java.util.*;
import greenfoot.*;

קצת על מחלקות, על קצה המזלג

  • מחלקה היא גוף, בסיסי או מורכב, המכיל מאפיינים ושיטות (פונקציות).
  • ניקח כדוגמא שחקן במשחק יריות, Player לצורך הענין. המאפיינים שהוא עשוי להכיל: כח, חיים, כלי נשק, מהירות וכו'. הפונקציות שעשויות להיות לו הן הליכה, ריצה, סיבוב, קפיצה, יריה, מוות וכו'.
  • כלי הנשק שהוזכרו בסעיף הקודם יכולים להיות גם הם מחלקה - Weapon, כך שלכל אובייקט במחלקה יש מאפיינים, למשל - שם הנשק, עוצמה, כמות תחמושת, ופונקציות - יריה, טעינה, בדיקה האם הנשק ריק וכו'.
  • נראה דוגמא למימוש של מחלקות כאלו. הפונקציות עצמן לא יכתבו כיוון שהדוגמא רק באה להמחיש מבנה של מחלקה. שימו לב - מקובל בג'אווה ששם של מחלקה מתחיל באות גדולה ושמות משתנים במחלקה מתחילים ב"_". המשתנים עצמם יהיו private ולא תהיה אליהם גישה למחלקות אחרות, אלא באמצעות פונקציות יעודיות שיהיו public:
public class Player ()
{
     //Data members:
     private int _health, _life, _speed;
     private Weapon _myWeapon;
 
     //Functions:
     public void walk ()
     {
         //Some code...
     }  
     public void turn (int degrees)
     {
         //Some code...
     }  
     public int getHealth ()
     {
         return _health;
     }  
}
 
public class Weapon ()
{
    //Data members:
    private String _name;
    private int _ammo, _power;
 
    //Functions:
    public String getName ()
    {
        return _name;
    }
    public boolean isEmpty()
    {
        if (_ammo > 0)
            return false;
        return true;
    }
    public void fire ()
    {
        if (!(isEmpty()))
        {
            //Some code...
            _ammo--;
        }
    }
    public void reload (int newAmmo)
    {
        _ammo += newAmmo;
    }
}

סיכום

בשיעור זה הכרנו את כללי התחביר הבסיסיים בג'אווה - כללי כתיבה, הגדרת משתנים, תנאים ולולאות. בדוגמאות השתדלנו לתת מדגם מייצג של שורות תקינות ושגיאות, ולכן מומלץ לעבור על כל הדוגמאות שורה אחר שורה ולוודא שהכל מובן. בנוסף, הזכרנו באופן כללי מושגים כמו הרשאות, import, javadoc, ומחלקות והראנו את התחביר שלהם על מנת שלא נבהל אם נתקל בהם. אם זאת, זוהי ממש נגיעה על קצה המזלג בנושאים אלו. על חלקם נרחיב בשיעורים הבאים ועל כולם ניתן לקרוא באתר של oracle.

שיעורי בית

עליכם להוסיף ניקוד למשחק מכונית המירוץ במסלול באופן הבא:

1. על כל השלמת מסלול - הניקוד יעלה ב-1
2. על כל יציאה מטווח המסלול - הניקוד ירד ב-1

יוצג מונה בצד המשחק שיציג את הניקוד הנוכחי.


<- השיעור הקודם: איך מתחילים      השיעור הבא: מערכים->