Java/גרסה להדפסה

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


נמצאה תבנית הקוראת לעצמה: תבנית:Java ג'אווה היא שפת תכנות מתקדמת המיועדת לפעול תחת סביבות עבודה שונות. ג'אווה פותחה בידי חברת סאן מיקרוסיסטמס בשנת 1991. השפה היא שפה מונחת עצמים (Object oriented), והתחביר שלה דומה מאוד ל-C ו-C++(אם כי, ישנם כמה הבדלים בולטים בין השפות). הספר הזה מלמד ג'אווה, אך בראש ובראשונה מיועד ללימוד של עקרונות התכנות הבסיסיים - משתנים, תנאים, לולאות, מערכים ושיטות. לכן, למרות היותה של ג'אווה שפה המיועדת לתכנות מונחה עצמים, בספר זה נתעלם מגישה תכנותית זו ונתמקד בעקרונות כלליים המשותפים לכל שפת תכנות. עבור אלו שכבר מכירים את העקרונות הבסיסיים, תספיק קריאה זריזה של הספר לפני המעבר לספר ההמשך שמתמקד בתכנות מונחה עצמים.

[עריכה] מה צריך לדעת לפני?

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

[עריכה] איך להשתמש בספר

  • משימות: חלק בלתי נפרד מלימוד תכנות הוא העבודה המעשית - כתיבה והתמודדות עם תקלות ("באגים"). בפרקים הראשונים תמצאו משימות המסומנות בצורה הבאה:


Thumbs up.png

עכשיו תורך:

כאן כתובה המשימה

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

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

[עריכה] מה לא יהיה בספר?

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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

הכנה

נמצאה תבנית הקוראת לעצמה: תבנית:Java לפני שמתחילים, ישנם כמה דברים שכדאי לדעת וצריך לעשות.

[עריכה] איך מתחילים

בשלב ראשון, תזדקקו לג'אווה עצמה. מכיוון שהמטרה היא תכנות, יש להוריד את גרסת ה-JDK, מהאתר של חברת סאן - כאן. הורידו משם את הגירסה הנוכחית של ג'אווה - נכון לעכשיו, גירסה 7u3 (הגירסה שמכונה JDK X Update X. אין צורך בגרסאות הכוללות תוספות כגון Java EE או NetBeans). מאחר וספר זה עוסק רק בנושאים בסיסיים, קרוב לוודאי שהוא יתאים לכל גירסה.

כדאי מאוד גם להוריד תוכנה איתה ניתן לערוך קבצי ג'אווה. כעיקרון, ניתן לעשות זאת עם כל מעבד תמלילים בסיסי (כמו Notepad של חלונות, למשל). עם זאת, נוח ויעיל הרבה יותר לעבוד עם תוכנה ייעודית, המכונה "סביבת פיתוח" (IDE). תוכנות לדוגמה הן:

  1. BlueJ, תוכנה קלה ופשוטה.
  2. Eclipse, שהיא תוכנה כבדה הרבה יותר אך גם מציעה מגוון גדול מאוד של אפשרויות.
  3. NetBeans.

שלוש התוכנות לעיל הן חינמיות, ומתאימות הן לסביבת חלונות והן לסביבת לינוקס (וייתכן שגם לסביבות נוספות).

[עריכה] עבודה משורת הפקודה

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

רשימת עורכים מתאימים נמצאת כאן.

עבודה מסביבת הפקודה בסביבת לינוקס, אחרי התקנת Java, היא טבעית ואין צורך בהכנה נוספת עבורה.

כדי להדר קבצים דרך MS-DOS (ממשק שורת הפקודה של חלונות) תצטרכו לסמן למחשב היכן למצוא את המהדר שהורדתם, לכן מומלץ לזכור להיכן הורדתם את קובץ הJDK ‏(Java Development Kit). כעת יש שתי אפשרויות:

  • אפשרות ראשונה: להקליד בשורת הפקודה (Command line) (מגיעים לזה דרך התחל>הפעל, (Start>run)) את הפקודה הבאה: java classpath ‎-C:\my path\bin (כאשר את מקום המילים my path יחליף המיקום בו מותקן המהדר).
  • אפשרות נוספת היא לשנות את המשתנה classpath דרך מאפייני "המחשב שלי". כדי לעשות זאת,
    1. היכנסו ל-התחל, לחצו על הכפתור הימני של העכבר על "המחשב שלי" ואז על "מאפיינים" (properties).
    2. היכנסו ללשונית "מתקדם" (Advance) ולחצו למטה על הכפתור "משתני סביבה" (Environment Variables).
    3. בחלון "משתני משתמש" (User Variables) יש רשימה של משתנים:
      • אם אתם רואים משתנה בשם CLASSPATH, סמנו אותו וליחצו על "ערוך" (Edit).
      • אם אין משתנה כזה, ליחצו על "חדש" (new) ובשדה "שם" (name) כתבו CLASSPATH.
      • בשדה "ערך" (Value) כתבו נקודה - "." (לא חשוב מה זה אומר), אחר כך נקודה פסיק (";"), ולאחר מכן את הנתיב בו נמצא המהדר (נניח ששמרתם את המהדר של java בתיקיה שנמצאת בכונן c ששמה myjava, אז כתבו "‎.;\C:\myjava\bin".
    4. לחצו OK ואתם מוכנים.

[עריכה] איך להשתמש בספר

  • משימות: חלק בלתי נפרד מלימוד תכנות הוא העבודה המעשית - כתיבה והתמודדות עם תקלות ("באגים"). בפרקים השונים תמצאו משימות המסומנות בצורה הבאה:


Thumbs up.png

עכשיו תורך:

כאן כתובה המשימה

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

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

[עריכה] מונחים בסיסיים

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

  • Class - (בעברית: מחלקה) תוכניות בג'אווה מורכבות מחלקים הנקראים Class. חשוב: שם המחלקה חייב להיות כשם הקובץ שבו היא נמצאת. כך למשל, אם כתבת תוכנית הממוקמת בקובץ Hello.java, שם ה-Class חייב גם הוא להיות Hello. במקרים של מחלקות הנמצאות אחת בתוך השניה המצב שונה, אך זהו נושא מתקדם יותר.
  • Method - (בעברית: מתודה או שיטה. בשפות אחרות לרוב יכונו "פונקציות" או "פרוצדורות"). אלו הם קטעי קוד המיועדים לשרת מטרה מסויימת. בדרך כלל יקבלו המתודות ערכים כלשהם ו\או יחזירו תוצאה. כל תוכנית ג'אווה בנוייה ממתודות.
  • Main - זוהי המתודה הראשית. אין משמעות הדבר שתפקידה הוא החשוב ביותר, אלא רק שהיא המתודה שתופעל כאשר ינסה מישהו להריץ את התוכנית. אם לא קיימת מתודת Main בתוכנית, לא ניתן יהיה להריץ את התוכנית. עם זאת, לעיתים קרובות מאוד יורכב פרוייקט מקבצים רבים. במקרה כזה ייתכן שיהיה יותר מקובץ אחד עם מתודת Main, אך חייבים להגדיר במפורש באיזו מהן משתמשים.
  • Project - בדרך כלל תהייה תוכנית מורכבת מקבצים רבים (לא בהכרח רק קבצי ג'אווה). בתוכנות שהוזכרו למעלה וברבות אחרות נעשית העבודה בדרך כלל עם "פרוייקטים", שמכילים את קבצי התוכנית השונים.

נמצאה תבנית הקוראת לעצמה: תבנית:Java

שלום עולם!

נמצאה תבנית הקוראת לעצמה: תבנית:Java נתחיל עם תוכנית פשוטה הכותבת על המסך "Hello World".

[עריכה] התחלה

[עריכה] eclipse

העלו את התוכנה, ובחרו מתוך התפריט (ב-File) או משורת המשימות "New", ומשם את האפשרות "Project". בתפריט אשף יצירת הפרוייקטים בחרו Java Project. כעת, בחרו שם כלשהו (למען הנוחות, נניח כי השם הוא "MyProject"), ולחצו על כפתור ה-"Finish", שנמצא בתחתית העמוד. כרגע נתעלם משאר האפשרויות.

עד כאן יצרנו פרוייקט חדש, שיכיל את כל הקבצים איתם נעבוד. כעת אנו רוצים ליצור מחלקה (Class) חדשה. לחצו שוב על אפשרות ה-"New", ובחרו הפעם "Class". כעת יפתח תפריט יצירת המחלקה. גם כאן נתעלם מהאפשרויות המוצעות לנו, נבחר שם (בשדה ה-Name). גם הפעם, למען הנוחות, נניח שהשם הוא "HelloWorld", אם כי גם במקרה הזה ניתן לבחור בשם אחר, ואז נלחץ על ה-"Finish". במרכז המסך צריכה להופיע כעת לשונית שכותרתה HelloWorld. בתוך לשונית זו נכתוב את התוכנית.

[עריכה] עורך טקסט

בשלב הזה העבודה פשוטה הרבה יותר: יוצרים קובץ חדש בשם HelloWorld.java, ומקלידים לתוכו את תוכן התוכנית.

[עריכה] BlueJ

העלו את התוכנה, ומהתפריט Project בחרו "New Project...". כעת בחרו שם לפרוייקט ואשרו. עכשיו, לחצו על הלחצן "New Class", שנמצא בצד ימין של החלון. גם כאן נבחר את השם HelloWorld. שימו לב שמתוך האפשרויות למטה מסומנת האפשרות "Class". אם מסומנת אפשרות אחרת, שנו זאת. אחרי יצירת המחלקה, היא תופיע על משטח העבודה הגדול שבאמצע החלון, כשהיא נראית כמלבן עליו רשום "HelloWorld" (או כל שם שבחרתם). לחיצה כפולה עליו תפתח חלון עריכה.

[עריכה] NetBeans

העלו את התוכנה, ומהתפריט File בחרו "New Project...". בתיבה השמאלית בחרו בJava ובתיבה הימנית בחרו ב"Java application". לחצו על Next. בחרו שם לפרוייקט ובטלו את הסימון של שתי התיבות בתחתית העמוד.

בחרו מתוך התפריט File את האפשרות "New File...". בתיבה העליונה בחרו בפרוייקט שיצרתם, בתיבה השמאלית בחרו בJava ובתיבה הימנית בחרו ב"Java class". לחצו על Next. כתבו את שם המחלקה (במקרה הזה "HelloWorld"), וודאו שבתיבה "Project" כתוב שם הפרוייקט שלכם ולחצו Finish.

[עריכה] כתיבת התוכנית

העתיקו את השורות הבאות:

public class HelloWorld {
 
public static void main(String[] args)
{
    System.out.println("Hello World!");
}
 
}

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

[עריכה] הסבר

השורה הראשונה כוללת הכרזה על המחלקה. המילה Class, מכריזה שזוהי מחלקה. המילה public מכריזה כי זוהי מחלקה ציבורית, כלומר - כל אחד יכול לגשת אליה. שימו לב כי סימן צומדיים (סוגריים מסולסלים) מסמן את תחילת המחלקה. לאחר מכן, אנו מכריזים על מתודת ה-main. כפי שניתן לראות, התוכנית פשוטה מאוד ולכן לא זקוקה למתודות נוספות. גם את תחילת המתודה אנו מסמנים בצומדיים. הפקודה System.out.print היא הפקודה שכותבת את השורה הרצוייה על המסך. בשלב האחרון באים סימני הצומדיים לסמן את סוף מתודת ה-main, ואז סימן צומדיים נוסף לסמן את סוף המחלקה.

[עריכה] הרצת התוכנית

[עריכה] eclipse

לחצו על הלחצן הימני של העכבר בתוך הלשונית בה אתם עובדים. מהתפריט שייפתח בחרו "Run As", ואז "Java Application". התוצאה אמורה להופיע בחלון קטן (Console) בחלקו התחתון של המסך. במידה וחלון כזה לא מופיע, הכנסו לתפריט "Window". מתת התפריט "Show View" בחרו "Console" והחלון אמור להופיע.

[עריכה] עורך טקסט

שמרו את הקובץ. כעת משורת הפקודה כתבו:

   javac HelloWorld.java

זוהי פקודה המפעילה את המהדר של ג'אווה, והיא תיצור קובץ ששמו HelloWorld.class. שימו לב: אם אתם עובדים בסביבת לינוקס קרוב לוודאי שתוכלו להריץ את הפקודה מכל מקום. בסביבת חלונות תצטרכו לדאוג שתוכלו להריץ את הקובץ מהספרייה בה אתם עובדים (או, לחילופין, לעבור לתיקיית ג'אווה ומשם להריץ את המהדר). כעת כתבו:

   java HelloWorld

ואם הכל כשורה - תפעל התוכנית.

[עריכה] BlueJ

סגרו את חלון העריכה של התוכנית. במידה ותישאלו אם רצונכם לשמור - שמרו את הקובץ. כעת, במשטח העבודה לחצו עם הלחצן הימני של העכבר על המחלקה ובחרו "Compile". לאחר מכן לחצו שוב על הלחצן הימני והפעם בחרו ב"void main(String[] args)". בחלון שיפתח בחרו "OK", ואז יוצג בפניכם חלון ובו תוצאות התוכנית - אם הכל ילך כשורה, תראו על חלון זה את הטקסט "Hello World".

[עריכה] בעיות נפוצות

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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

הערות בסיסיות

נמצאה תבנית הקוראת לעצמה: תבנית:Java הערות בסיסיות בנוגע לכתיבת תוכניות שיכולות לחסוך הרבה זמן ותסכול:

[עריכה] הפרטים הקטנים

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


{{{גודל}}}

כדאי לדעת:

סביבת העבודה eclipse מסוגלת לאתר טעויות אלה עוד בשלב הכתיבה על ידי סימון (בדומה לבודק איות במעבד תמלילים) ולפעמים אף להציע דרכי תיקון.


[עריכה] סגנון ותיעוד

מספר עקרונות יסייעו לכתיבת קוד ברור, נקי וקריא:

[עריכה] יישור

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

מחלקה

שיטה
...
לולאה
תוכן הלולאה
...

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

[עריכה] תיעוד

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

[עריכה] הערות פשוטות

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

// This is a text


אם רוצים לכתוב הערות ארוכות יותר, אפשר להשתמש בסימן */ כדי לפתוח בלוק הערה, ו- /* כדי לסגרו. לדוגמה:

/*
This is a text
And more
*/


גם מהערות כאלה יתעלם המהדר.

[עריכה] Javadoc

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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

משתנים

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

[עריכה] מה זה משתנים?

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

[עריכה] אופן השימוש

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

ב-Java, כדי להשתמש במשתנים, יש להקצות להם מקום תחילה - לקבוע את סוגם ולתת להם שם. לדוגמה: int x היא פקודה שמורה למחשב להקצות משתנה מסוג int, כלומר - משתנה המכיל מספר שלם כלשהו, ושמו יהיה x. שם המשתנה משמש אותנו בכל הפעולות בהן נרצה לקרוא לו, כמו למשל

System.out.println(x);


פקודה שתגרום להדפסת הערך שמכיל כרגע x על המסך.

[עריכה] סוגים בסיסיים

  • int - מספרים שלמים. לדוגמה: 3232
  • char - אותיות. לדוגמה: 'א'
  • float - מספרים עם נקודה עשרונית. לדוגמה: 32.24, 1.0, 23232.454
  • boolean - אופרטור בוליאני, כלומר - משתנה המסוגל להכיל "אמת" או "שקר" בלבד
  • long - דומה ל-int, אך בעל טווח גדול הרבה יותר
  • double - דומה ל-float, אך בעל טווח ודיוק גדולים יותר
  • byte ו-short - שני סוגים שימושיים פחות, הדומים ל-int אך בעלי טווח קטן יותר. מועילים בדרך כלל במצבים בהם יש צורך לחסוך בזיכרון.

[עריכה] הערות

  • סוגים אלה מכונים primitives, והם אכן מתקדמים פחות מהמשתנים שנכיר בהמשך, הנקראים "אובייקטים". בשלב זה נתעסק רק איתם.
  • יש לשים לב כי ברגע שמגדירים משתנה, Java לא תאפשר לשים בו ערך שאינו מתאים לו, והדבר יגרום לקריסת התוכנית. אם, לדוגמה, נגדיר משתנה מטיפוס int וננסה להכניס אליו את הערך 5.7, נקבל הודעת שגיאה והתוכנית לא תוכל לרוץ או - גרוע יותר - תקרוס בזמן הריצה.
  • משתנה בוליאני, למרות תוכנו המוגבל, הוא שימושי מאוד עבורנו. ב-Java הוא יכול לקבל אך ורק את הערכים "true" או "false" (באותיות קטנות).
  • כאשר מכניסים ערך למשתנה מטיפוס char, יש להקיף אותו בגרש מכל צד, כך: 'a'.

[עריכה] דוגמאות

כדי להגדיר משתנה מסוג int בשם a, נכתוב

int a;


כדי להגדיר משתנה מסוג int בשם a, ולהכניס אליו את הערך 5, נכתוב

int a=5;


או לחילופין

int a;
a=5;


כדי להגדיר משתנה מסוג float בשם b, נכתוב

float b;


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

char a='H', b='E', c='L', d='L', e='O';




Thumbs up.png

עכשיו תורך:

איך מגדירים משתנה בשם Y מסוג long? ואיך מגדירים משתנה בוליאני בשם doYouKnow המקבל את הערך true?


[עריכה] מתן ערך למשתנים

כאשר משתמשים במשתנים נצטרך לדעת איך לקבוע ולשנות את ערכיהם. הדרך הפשוטה ביותר נעשית בצורה A=B, פעולה שתגרום למשתנה A (השמאלי) לקבל את הערך B (הימני). B עשוי להיות מספר, משתנה אחר, או תוצאת חישוב.

תזכורת: כדי שנוכל לבצע פעולה זו חייבים להתקיים שני תנאים: על A להיות מוגדר, ועל B להיות מתאים לסוגו של A (לדוגמה - מספר שלם עם מספר שלם). אם אחד התנאים לא מתקיים - התוכנית לא תרוץ!

[עריכה] חישובים

בדומה להצבת ערך, ניתן להציב במשתנה תוצאת חישוב כלשהי, כמו A=B*C. באותו אופן ניתן לכתוב גם חישובים מורכבים, כמו A=B+(11*5)+C/4, כאשר A, B ו-C הם משתנים מטיפוס float. המהדר מכיר את ארבעת הפעולות הבסיסיות: חיבור (+), חיסור (-), כפל (*), וחילוק (/), וכן את פעולת המודולו - שארית (%). בהמשך נלמד כיצד לבצע פעולות מורכבות יותר.


Thumbs up.png

עכשיו תורך:

כתבו קטע קוד המאתחל שלושה משתנים מטיפוס int, ומכניס לשניים מהם את הערכים 1 ו-2 בהתאמה. הכניסו למשתנה השלישי את תוצאת סכום החיבור של שני הראשונים. איך תגרמו למחשב להדפיס את התוצאה?

משתנה יכול לקבל אפילו את הערך של עצמו. הפקודה X=X היא חוקית לחלוטין (למרות שהיא חסרת תועלת). פקודה דומה מאוד תשמש אותנו אם נרצה להוסיף ערך B למשתנה A כלשהו: A=A+B. שימו לב כי פקודה כמו A+B, שנראית כמו הדרך הטבעית לחבר את A עם B אינה חוקית ואינה מובנת עבור המחשב. קיצור שימושי ומפורסם הוא A++, שעבור המחשב שקול בדיוק ל A=A+1 (ולהפך: A-- יחסיר 1 מ-A). קיצור שימושי מאוד אך מוכר פחות הוא A+=B, השקול ל A=A+B. עם קיצור זה ניתן להשתמש בכל ארבעת פעולות החשבון.


Thumbs up.png

עכשיו תורך:

כתבו תוכנית המאתחלת משתנה מסוג int, שערכו הראשוני יהיה 100. בלי להיעזר במשתנים נוספים, הוסיפו לו 10, הכפילו אותו ב-4, והדפיסו את התוצאה.


[עריכה] מתן שמות למשתנים

כאשר בוחרים שמות למשתנים, השם חייב להיות חוקי, ורצוי שיהיה הגיוני ומתאים. שם חוקי יכול להכיל אותיות (אנגליות, גדולות או קטנות), ספרות, סימני קו-תחתון (_) וסימני $. השם לא יכול להתחיל בספרה, אבל יכול להתחיל בכל אחד מהסימנים האחרים. כמו כן, השם אינו יכול להכיל סימן שלא הוזכר כאן כמו '^', '%' או '*'. כמו כן, השם לא יכול להיות מילה שמורה של Java. מילה שמורה היא מילה השייכת לאחת הפונקציות הבסיסיות של Java, כמו שמות המשתנים הבסיסיים, המילים public ו-private, המילה new, וכן הלאה.

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

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

[עריכה] דוגמאות

[עריכה] הכרזות חוקיות

int _a;


char givenLetter;


float divider;


char thisIsAnExtremelyLongButLegalVariableName;



[עריכה] הכרזות לא חוקיות

int 9a


char given Letter


int float


double myDouble!




Thumbs up.png

עכשיו תורך:

מה לא חוקי בכל אחת מהכרזות אלה?


[עריכה] נספח

נמצאה תבנית הקוראת לעצמה: תבנית:Java

פלט וקלט

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

[עריכה] פלט

כבר בפרקים הקודמים נתקלתם בפקודה System.out.println(...), שמדפיסה על המסך את מה שנמצא בין הסוגריים. פקודה דומה היא System.out.print(...), שמבצעת פעולה זהה, אך בלא להעביר שורה לבסוף. המשתמע מכך הוא ששורות הקוד

System.out.print("Hello ");
System.out.print("World");


יציגו את התוצאה

Hello World

ולא

Hello
World


שהייתה מושגת אם היינו משתמשים בפקודה System.out.println. בשלב זה נסתפק בשתי פקודות פשוטות אלו.

[עריכה] קלט

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

[עריכה] ייבוא מחלקות

בדומה ל-C, גם Java בנויה בצורה מודולרית ומציעה חבילות רבות המרחיבות את ההיצע הקטן של הפקודות המובנות. עם הזמן נכיר חבילות רבות. כרגע נשתמש בחבילה בסיסית הנקראת java.util, ובפרט - במחלקה בשם Scanner. כדי להשתמש במחלקה זו, אפשר לייבא אותה באמצעות הפקודה

import java.util.Scanner;


. אפשר גם לייבא את כל חבילת java.util בפקודה אחת, באמצעות

import java.util.*;



{{{גודל}}}

כדאי לדעת:

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


את פקודת הייבוא יש לכתוב בראש התוכנית, עוד לפני ההכרזה על המחלקה (כלומר, לפני הפקודה public class ...).

[עריכה] אובייקטים ובנאים

בשלב זה עדיין לא נעסוק באובייקטים ובבנאים (Constructors), ובשורות הבאות נשתמש בהם מבלי להבין לגמרי את משמעותם. בתוך מתודת ה-main נכתוב את השורות הבאות:

Scanner s = new Scanner(System.in);


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

int i;
i = s.nextInt();


השורה הראשונה כבר מוכרת לנו: היא מאתחלת משתנה מטיפוס int בשם i. השורה השנייה קולטת לתוך i את הערך אותו מכניס המשתמש.

Achtung.svg

שימו לב:

מה לדעתכם יקרה אם יכניס המשתמש מספר לא שלם, או גרוע מכך - אות? בדקו!

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

import java.util.Random;


.

וכדי להכריז על אובייקט מהמחלקה נשתמש בשורה

Random r = new Random();



[עריכה] צורות שימוש

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

  • הפקודה s.next()‎ תחזיר מחרוזת, כלומר - תאפשר לנו לקלוט משתנה מטיפוס String.

לאובייקט מסוג random גם יש פקודה שנקראת nextInt(), שמאפשרת לקבל מספרים שלמים (כי זה int) אקראיים מאפס עד המספר שבחרת פחות אחד. אם לא תכתבו מספר בסוגריים, המחשב ייתן מספר מסוג int.

אם נרצה מספר רנדומלי בין 0-9 אנו נוסיף את התחום בתוך הסוגריים כך:

num=r.nextInt(10);


בפלט המחשב ייתן לנו מספר אקראי בין 0-9. כדי לקבל מספר בין 1 ל-10 נוסיף 1 כמו בדוגמא:

num=r.nextInt(10)+1;



כדי לקבל תחום מספרים אחר פשוט נוסיף מספר אחר. למשל, כדי לקבל מספר אקראי בין 2-10 נכתוב:

num=r.nextInt(9)+2;


Achtung.svg

שימו לב:

מה קרה פה בתכנית.


Thumbs up.png

עכשיו תורך:

מה לדעתכם הנוסחה לתחום של מספרים אקראיים?


[עריכה] דוגמה

נציג כעת תוכנית קצרה המשתמשת בפקודות הקלט והפלט שלמדנו עד כה:

import java.util.*;
 
public class IOExample {
 
        public static void main(String[] args) {
                int a, b, c;
                Scanner s = new Scanner(System.in);
                System.out.println("Enter a number: ");
                a=s.nextInt();
                System.out.println("Enter another number: ");
                b=s.nextInt();
                c=a+b;
                System.out.println(c);
        }
 
}


Thumbs up.png

עכשיו תורך:

מה לדעתכם עושה התוכנית? כיצד תוכלו לשנות אותה כך שהיא תייצר עוד משתנה רנדומלי ותציג את מכפלתם של כל המשתנים?


[עריכה] נספח

נמצאה תבנית הקוראת לעצמה: תבנית:Java

מחרוזות

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

String s;


או

String s = "Bla-Bla-Bla";


הבדל חשוב בין מחרוזות (String) לתווים (char) הוא אופן הסימון: תווים מקיפים בסימן גרש ('c'), אך מחרוזות מקיפים בסימן גרשיים ("c").

[עריכה] עבודה עם מחרוזות

Java מאפשרת גמישות גבוהה בעבודה עם המחרוזות:

  • ניתן לחבר מספר מחרוזות יחד באמצעות הסימן '+'. לדוגמה: "This "+"Is "+"a "+"String" היא מחרוזת חוקית ושקולה בדיוק ל-"This Is a String".
  • באותה צורה, ניתן לחבר מחרוזת עם גורם נוסף שאינו בהכרח מחרוזת, אך ניתן לתרגום למחרוזת, כמו לדוגמה משתנים בסיסיים. את עבודת ההמרה מבצעת עבורנו Java בצורה אוטומטית. כך, לדוגמה, אם מוגדר משתנה כלשהו מסוג int בשם num, המחרוזת הבאה היא חוקית: "My number is "+num.
גמישות זו נוחה מאוד, בשילוב עם פונקצייות הפלט. אם נרצה לכתוב מחרוזת ומייד אחריה מספר - לא נצטרך לכתוב שתי פקודות שונות, אלא נוכל לכתוב זאת בשורה אחת:
System.out.println("My number is "+num);


גם ביטויים מורכבים הרבה יותר יתקבלו, כל עוד הסוגריים והגרשיים יהיו ממוקמים בכל מקום בו הם נחוצים.
  • לא ניתן להשוות שתי מחרוזות באמצעות הסימן "=", אלא רק באמצעות הפונקציה equals (ראו למטה). המהדר יקבל השוואה זו כחוקית, אך במקום להשוות את תוכן המחרוזות, הוא ישווה את מיקום האובייקט בזיכרון ובכך יביא לתוצאות לא רצויות.
  • בתוך המחרוזת ניתן להשתמש במספר תווים מיוחדים. הסימן "n\" (סלאש-n, באות קטנה) יגרום למעבר שורה. הסימן "t\" מסמן טאב, כלומר - קפיצה של כמה רווחים בבת אחת, והסימן "r\" יחזיר את הסמן לתחילת השורה. כדי לכתוב את הסימן \ עצמו נצטרך לכתוב "\\", ובשביל לכתוב גרש או גרשיים נצטרך, בהתאמה, לכתוב "'\" ו-""\". לדוגמה:
    System.out.print("Hello\nCruel\nWorld\n");


יביא להדפסת הפלט הבא:

Hello
Cruel
World


קיימים מספר סימנים נוספים, שימושיים פחות, שלא יפורטו כאן.

[עריכה] כלים

לרשותנו עומדים כלים רבים בעבודה עם מחרוזות. נעבור כאן על החשובים שביניהם, כאשר בכל הדוגמאות - str הוא מחרוזת כלשהי.

  • כדי למצוא את אורך המחרוזת נשתמש בפונקציה length, המחזירה את אורך המחרוזת בצורת מספר מטיפוס int. שימוש: str.length();.
  • כדי לדעת איזה תו נמצא במקום כלשהו במחרוזת, נשתמש בפונקציה charAt, המחזירה את התו שנמצא במקום הרצוי. המיקום של האות הראשונה הוא 0 (ולא 1!), ושל האות האחרונה - אורך המחרוזת פחות 1 (כלומר - str.length() - 1). הפונקציה מחזירה משתנה מטיפוס char. שימוש: str.charAt(index);, כאשר index הוא משתנה מטיפוס int המציין את המיקום הרצוי.
  • כדי להשוות בין שני משתנים מטיפוס String לא ניתן להשתמש ב-"=", וזאת כי מדובר באובייקטים ולא במשתנים בסיסיים. כדי להשוות נזדקק לפונקציה equals, המחזירה משתנה מטיפוס boolean, שערכו "אמת" אם המחרוזות שוות, ו"שקר" אם לא. שימוש: str.equals(str2);, כאשר str2 היא מחרוזת אליה אנו רוצים להשוות את str.
  • כדי לקבל חלק ממחרוזת נשתמש בפונקציה substring, שמחזירה משתנה מטיפוס String המכיל את הקטע הרצוי. ניתן להשתמש בפונקציה זו בשני אופנים: אם מכניסים שני משתנים מטיפוס int, הפונקציה תחזיר את המחרוזת שנמצאת בין המיקום הראשון לשני. אם מכניסים משתנה אחד, מקבלים את המחרוזת החל ממיקום זה ועד הסוף. שימוש: str.substring(index); או str.substring(begin, end);
  • קיימות עוד פונקציות רבות ומועילות. ניתן לראותן בצירוף הסברים באתר של חברת סאן.

נמצאה תבנית הקוראת לעצמה: תבנית:Java

תרגילים

בתרגיל זה נבנה תוכנית פשוטה שתדע לבצע פעולות פשוטות על מחרוזות.

[עריכה] קליטה

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


[עריכה] חיבור מחרוזות

הוסיפו לתוכנית שורות קוד כך שעכשיו התוכנית תבקש מהמשתמש להכניס את שמו, ואחרי שיכניס - תכתוב "Hello " ואז את השם שיתקבל. תזכורת: אפשר לחבר מחרוזות בעזרת חיבור פשוט (כלומר - str1+str2).


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

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

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

[עריכה] תנאים

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

if (condition)
   Command;

כאשר במקום המילה condition נכתוב את התנאי שלנו. התנאי הוא תמיד בוליאני, כלומר - מסוגל להיות אמת (true), או שקר (false). כאשר התשובה חיובית (התנאי מתקיים) תופעל הפקודה שכתובה מיד אחרי התנאי, וכשהתשובה שלילית התוכנית תתעלם מהפקודה שאחרי פקודת ה-if, ותמשיך הלאה. לדוגמה:

if (x==5)
   System.out.println("X is 5");

תביא להדפסת המחרוזת "X is 5" אך ורק אם המשתנה x שווה ל-5. כל ערך אחר יגרום לתוכנית להמשיך הלאה. התנאי לא מוגבל לפקודה אחת: ניתן להשתמש בצומדיים ('{ }') כדי להגדיר קבוצת פקודות שתתבצענה אם יתקיים התנאי, בצורה הבאה:

if (condition) {
   Command 1;
   Command 2;
...
}

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

if (x == 5)
    System.out.println("X is 5");
else
    System.out.println("X is not 5");

בדוגמה זו אם X יהיה שווה ל-5 ההודעה "X is 5" תודפס, ואם X לא יהיה שווה ל-5 תודפס ההודעה "X is not 5".

[עריכה] תנאים מורכבים

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

  • האופרטור "וגם" יהיה נכון אם ורק אם גם תנאי א' מתקיים וגם תנאי ב' מתקיים. בג'אווה אנו מסמנים אופרטור זה ב-"&&".
  • האופרטור "או" יהיה נכון אם ורק אם אחד מהתנאים יתקיים. בג'אווה אנו מסמנים אופרטור זה ב-"||".
  • סימן השלילה הופך את התנאי. בג'אווה אנו מסמנים זאת ב-"!".

[עריכה] דוגמאות

נניח ש-x הוא משתנה אותו הגדרנו להיות משתנה מסוג int.

if (x>4 && x<9)

הוא תנאי שיתקיים רק אם ערך המשתנה x נמצא בין 5 ל-8 (שימו לב: אם x שווה ל-4 או ל-9, התנאי לא מתקיים!)

if (x>4 || x<9)

הוא תנאי שיתקיים עבור כל x שהוא, מכיוון שכל מספר אפשרי הוא גדול מ-4 או קטן מ-9.

if (x<4 || x>9)

הוא תנאי שיתקיים עבור כל x שערכו קטן מ-4 או גדול מ-9.

if (!(x>4))

הוא תנאי שיתקיים עבור כל x שאינו גדול מ-4, כלומר - עבור כל x שקטן או שווה ל-4.

ניתן לחבר גם תנאים מורכבים יותר, כמו התנאי הבא:

if ((x<4 || x>9) && (y>15 && y<35))

כאשר גם y הוא משתנה מטיפוס int. תנאי כזה יתקיים רק אם יתקיים התנאי השמאלי, כלומר - x גדול מ-9 או קטן מ-4, וגם התנאי הימני, כלומר - y גדול מ-15 וקטן מ-35. בצורה זהה, ניתן לחבר מספר רב של תנאים בהתאם לצורך. בהמשך נראה דוגמאות שונות לכך - תנאים פשוטים ומורכבים.

[עריכה] תנאים מקוננים

ראינו כבר שבתוך בלוק תנאי ניתן לכתוב פקודות רבות. הבה נראה דוגמה, בהנחה ש-str הוא משתנה מוגדר מטיפוס String:

if (str.equals("Hello"))
        System.out.println("This is hello");

בדוגמה זו אנו בודקים אם המשתנה str שווה למחרוזת "Hello". מכיוון שאנו מתעסקים עם מחרוזות נעשה שימוש בפקודה equals במקום בצורת ההשוואה המוכרת (באמצעות סימני ה"=="). אם אכן str שווה למחרוזת זו, מודפס הפלט "This is hello".

באותה צורה בה כתבנו פקודות שיתבצעו אם יתקיים התנאי, ניתן גם לכתוב תנאים נוספים - תנאי בתוך תנאי. תנאים כאלה מכונים תנאים מקוננים, והם שימושיים מאוד בתכנות. נראה דוגמה דומה, והפעם עם תנאי מקונן (הפעם, str ו-str2, שניהם משתנים מוגדרים מטיפוס String):

if (str.equals("Hello"))
        if (str2.equals("World"))
                System.out.println("This is hello and world");

בדוגמה זו מתבצעות שתי בדיקות, בזו אחר זו: אם הבדיקה הראשונה מתקיימת, כלומר ערך המחרוזת str הוא "Hello", ממשיכה התוכנית לרוץ ולבדוק גם את התנאי השני, כלומר - בדיקה האם str2 שווה ל-"World". אם התנאי הראשון לא מתקיים - התנאי השני כלל לא נבדק.

[עריכה] ומה אם לא?

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

if (x>30 && y<10)
        System.out.println("It's OK");
if (x<=30 || y>=10)
        System.out.println("You're in trouble");

זוהי דוגמה פשוטה למדי - התנאי שלנו הוא שמשתנה מסוג int בשם x גדול מ-30 וגם משתנה מסוג int בשם y קטן מ-10 (כמובן, בהנחה ששני משתנים אלה כבר הוגדרו קודם). אם מתקיים אחד התנאים ההפוכים - x קטן או שווה ל-30 או y גדול או שווה ל-10 - ברור שהתנאי לא מתקיים. בדומה למרבית שפות התכנות, גם ג'אווה מציעה מנגנון שמקצר תהליך זה והופך אותו לפשוט יותר - מנגנון ה-else. קטע הקוד הבא שקול בדיוק לקטע שבתחילת הסעיף:

if (x>30 && y<10)
        System.out.println("It's OK");
else
        System.out.println("You're in trouble");

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

import java.util.Scanner;
 
public class GradeSystem {
        public static void main(String[] args) {
                Scanner s;
                s=new Scanner(System.in);
                int grade=s.nextInt();
                String str;
                if (grade>100 || grade<0)
                        str="Illegal grade";
                else if (grade>=90)
                        str="Very good";
                else if (grade>=80)
                        str="Good";
                else if (grade>=70)
                        str="Moderate";
                else if (grade>=60)
                        str="Passed";
                else
                        str="Failed";
                System.out.println(str);
        }
}


Thumbs up.png

עכשיו תורך:

מה עושה התוכנית? מה מטרתה?

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

[עריכה] לולאות

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

for (int i=0; i<50; i++)
        System.out.print("*");

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

for (init; condition; step)

כאשר במקום init נכתב המצב ההתחלתי (כלומר, פקודה שתתבצע בשעה שהתוכנית נכנסת ללולאה לראשונה), במקום condition נכתוב תנאי סיום - הלולאה תמשיך לרוץ כל עוד התנאי מתקיים, ובמקום step נכתוב מה קורה בכל פעם שהתוכנית חוזרת ללולאה. בדוגמה שלנו השתמשנו בכמה תנאים נפוצים ופשוטים מאוד: בתחילת הלולאה אתחלנו משתנה מסוג int בשם i להיות 0, ופקדנו על התוכנית להפעיל את הפקודות שבתוך הלולאה (דהיינו, הפקודה להדפיס "*") כל זמן ש-i קטן מ-50. בכל פעם שמסיימת התוכנית לבצע את הפקודות, i גדל ב-1. אם כך, לאחר 50 פעמים בהן רצה הלולאה, המשתנה i יהיה שווה ל-50 - התנאי לא יתקיים, והלולאה תסתיים.

חשוב לציין כי התנאים האלו אינם הכרחיים. הפקודה for (;;) היא חוקית - לולאה זו תרוץ לנצח. ניתן להשמיט כל אחד מהחלקים, לפי הצורך.

כעת נראה דוגמה שממחישה יתרון גדול של לולאת ה-for - השימוש במשתנה הלולאה.

for (int i=0; i<10; i++) {
        System.out.println(i);
}

שורות קוד אלו יגרמו להדפסת המספרים מ-0 ועד 9 (חשבו: למה לא 1 עד 10?). נראה דוגמה מורכבת יותר:

for (int i=1; i<=10; i++) {
        for (int j=1;j<=10;j++) {
                System.out.print(i*j+"\t");
        }
        System.out.println();
}

בדוגמה זו השתמשנו בלולאות מקוננות על מנת להדפיס את לוח הכפל. תזכורת: הסימן "\t" משמש ליצירת רווח קבוע (טאב), על מנת שצורת ההדפסה תהייה נעימה יותר לעין. נעבור על אופן הריצה בצורה מפורטת:

  1. בשלב הראשון, נכנס המחשב ללולאה הראשונה - for (int i=1; i<=10; i++). כפי שכבר ראינו, מתבצע כעת איתחול: המשתנה i מוכרז להיות משתנה מטיפוס int, ומקבל את הערך 1.
  2. כעת, ממשיכה התוכנית ומגיעה אל תחילת הלולאה השנייה - for (int j=1;j<=10;j++). גם כאן מתבצע האיתחול. כעת קיימים שני משתנים: i ו-j, שניהם משתנים מטיפוס int, ובשלב זה - שניהם שווים 1.
  3. התוכנית מתקדמת אל השורה הבאה - System.out.print(i*j+"\t");, ומדפיסה את התוצאה הראשונה: 1 (שני המשתנים שווים 1 - לכן גם מכפלתם).
  4. כאן מגיעה התוכנית אל הצומדיים שמסמנים את סוף הקטע אליו מתייחסת הלולאה השנייה (הלולאה של j). התוכנית חוזרת אל הלולאה: j גדל ב-1, והתוכנית בודקת אם הוא עדיין עומד בתנאי. j עומד בתנאי, כיוון ש-2 קטן מ-10, לכן מתבצע תוכן הלולאה פעם נוספת, הפעם - j שווה ל-2 ו-i שווה ל-1. המספר שיודפס הפעם הוא 2 (כי 2*1=2).
  5. הלולאה ממשיכה לחזור על עצמה עד שהתנאי מפסיק להתקיים: בפעם העשירית, j הופך להיות 11, לא עומד בתנאי, והלולאה מסתיימת. בשלב זה מודפסת כבר שורת המספרים הראשונה: 1 2 3 4 5 ... 10
  6. הגענו אל השורה הבאה: System.out.println();. גם שורה זו מיועדת למטרות נוי בלבד - תפקידה לעבור שורה בכל פעם, כדי שכל עשרה מספרים יודפסו בשורה אחת. בלי שורה זו, היו מודפסים כל המספרים בשורה אחת ארוכה.
  7. התוכנית הגיעה אל קצה הלולאה הראשונה (לולאת ה-i). כמו עם ה-j, גם i מתקדם ב-1, עומד בתנאי (כי 2 קטן מ-10), והלולאה מתחילה מחדש, רק שהפעם - i שווה ל-2. פרט לכך, כל השלבים זהים.
  8. לסיכום, בכל מעבר של הלולאה החיצונית - הלולאה של i, מתבצעת ריצה מלאה של הלולאה הפנימית - הלולאה של j. כל ריצה של הלולאה הפנימית מדפיסה שורת מספרים אחת, כל מעבר של הלולאה החיצונית גורם למעבר שורה ולהמשך ההדפסה של השורה הבאה. סך הכל, מתבצעות 100 פקודות הדפסה, ו-10 פקודות מעבר שורה.

[עריכה] לולאות do-while

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

  • צורה ראשונה - while בלבד:
while(condition) {
        // to do
}
  • צורה שנייה - do ו-while בסוף:
do {
        // to do
} while(condition);

בשתי הצורות שהוצגו יבוא הקוד (הפקודות שהלולאה אמורה לבצע) במקום בו כתוב // to do, ותנאי היציאה במקום בו כתוב condition. ההבדל בין הצורות הוא הרגע בו נבדק התנאי: בצורה הראשונה, כאשר משתמשים ב-while בלבד, נבדק התנאי כאשר נכנסים ללולאה לראשונה, ואז - בכל פעם שמסתיימות הפקודות בבלוק הלולאה. אם משתמשים גם ב-do, נבדק התנאי בכל פעם שמסתיימת הלולאה. במקרה כזה, תמיד תתבצע הלולאה לפחות פעם אחת. כמו לולאת for, גם כאן אפשר להשתמש בלולאות מקוננות ובתנאים מורכבים.

[עריכה] אם כך, באיזו לולאה כדאי להשתמש?

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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

תרגילים

[עריכה] לולאות - התחלה

[עריכה] כוכביות

כתבו תוכנית, קצרה ככל האפשר, המדפיסה בשורה 20 כוכביות ('*').


[עריכה] כוכביות 2

שפרו התוכנית, כך שהכוכביות יודפסו בצורת קו אלכסוני (בשורה הראשונה תודפס *, בשורה השנייה - * ולפניה רווח אחד, בשורה השנייה - * ולפניה 2 רווחים, וכן הלאה). רמז: השתמשו בלולאה כפולה.


[עריכה] מחרוזות - חזרה

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

[עריכה] היפוך

כתבו תוכנית פשוטה שתקבל מחרוזת מהמשתמש, ותהפוך אותה על פניה. כלומר: אם התקבלה המחרוזת "ding dong", תודפס המחרוזת "gnod gnid". הנחיה: השתמשו בפונקציית הספרייה charAt ובלולאה מתאימה.


[עריכה] חיפוש במחרוזת

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

הנחיות:

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


[עריכה] תנאים לקלט

[עריכה] סדרה

סדרה חשבונית היא סדרה של מספרים עם הפרש קבוע ביניהם. למשל: 1,2,3,4,5 היא סדרה חשבונית. גם 9,7,5,3,1 היא סדרה חשבונית. 1,2,4,8 היא לא סדרה חשבונית, כיוון שההפרש בין האיברים הוא לא קבוע. כתבו תוכנית המקבלת קלט שמורכב מהאיבר הראשון של הסדרה, ההפרש בין האיברים, ומספר האיברים בסדרה, ומדפיסה את הסדרה כולה. אם, לדוגמה, מקבלת התוכנית את הקלט 1 2 3 תדפיס התוכנית את הסדרה 1,3,5 (שלושה איברים, שההפרש ביניהם 2, והראשון מביניהם הוא 1). מספר האיברים שהתוכנית שלנו תסכים להדפיס הוא מוגבל: לכל הפחות, תודפס סדרה ובה איבר אחד (שהוא האיבר הראשון). לכל היותר, תדפיס התוכנית 15 איברים. דאגו לכך שאם המשתמש מכניס קלט אחר, תדפיס התוכנית הודעה מתאימה ותעצור. ניתן להשתמש בפקודה System.exit(0) כדי לעצור את פעולת התוכנית, אך לא חובה להשתמש בה.


[עריכה] הזדמנות שנייה

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

הרחבה על משתנה בוליאני, ערך null

נמצאה תבנית הקוראת לעצמה: תבנית:Java משתנה בוליאני הוא משתנה מיוחד, המסוגל לקבל ערך של "אמת" (True) או "שקר" (False) בלבד.

[עריכה] הסבר לשימוש

כאשר משתמשים בערך בוליאני, אפשר להציב בו רק ערך של אמת או שקר, שבג'אווה מיוצגים על ידי המילים השמורות true ו-false (שימו לב - אותיות קטנות).

דוגמה:

boolean t = true;
boolean f = false;

למרות מוגבלותם, משתנים בוליאניים מועילים מאוד במקרים רבים.

[עריכה] צורה של שימוש בלולאות ותנאים

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

public class bool
{
        public static void main(String[] arg)
        {
                boolean t = true;
                // t is now true
                if(t)
                {
                        System.out.print("Hello ");
                }
                // Now we set t to false
                t = false;
 
                if(t == false)
                {
                        System.out.println("world");
                }  
        }
}

הפלט של התוכנית יהיה

Hello world


יכולנו לכתוב גם כך את הקוד ולקבל תוצאה זהה:

public class bool
{
        public static void main(String[] arg)
        {
                boolean t = true;
                // t is now true
                if(t)
                {
                        System.out.print("Hello ");
                }
                // Now we set t to false
                t = false;
 
                if(!t)
                {
                        System.out.println("world");
                }  
        }
}

גם כאן הפלט יהיה

Hello world


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


[עריכה] הסבר לדוגמה

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

[עריכה] פעולות על משתנים בוליאניים

מטבע הדברים, לא ניתן לבצע פעולות חשבוניות על משתנים בוליאניים - זה לא מוגדר. מצד שני, ניתן לבצע עליהם כמה פעולות אחרות: או, וגם, או שלילה. בהנחה ש-b1, b2 ו-b3 הם משתנים בוליאניים:

  • b3 = b1 && b2 - פעולת "וגם" - b3 שווה אמת רק אם גם b1 וגם b2 הם אמת.
  • b3 = b1 || b2 - פעולת "או" - b3 שווה אמת אם לפחות אחד מהמשתנים b1 ו-b2 הם אמת.
  • b3 = !b1 - פעולת שלילה - b3 יקבל את הערך ההפוך מזה שמחזיק b1.
  • b2 |= b1 - דרך מקוצרת לכתוב b2 = b2 || b1.
  • b2 &= b1 - דרך מקוצרת לכתוב b2 = b2 && b1.

בדיוק כמו עם תנאים (או, ליתר דיוק - בתנאים, בדיוק כמו במשתנים בוליאניים) - ניתן להשתמש בכל צירוף הגיוני של הסימנים האלו, למשל: (b4 && b3) || (b2 && b1).

[עריכה] ערך null

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

[עריכה] תחביר וצורת כתיבה

ניתן לתת לאובייקט ערך null בצורה הבאה:

String s = null;



אפשר גם לבדוק אם אובייקט מסויים הוא null:

if (s == null) // Do something



כל האובייקטים, אם רק הוכרזו אך לא אותחלו - מכילים ערך null.

[עריכה] גישה

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

[עריכה] דוגמא להמחשה

נתחיל בניסוי:

String s = "Hi";
if(s == null)
{
        System.out.println("The string is null");
}
else
{
        System.out.println("The string isn't null");
}

הפלט של שורות קוד אלה יהיה

The string isn't null


לעומת זאת, אם נאתחל את המשתנה s ל-null, כלומר - נחליף את השורה הראשונה ב-String s = null; נקבל את הפלט

The string is null


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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

מערכים

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

[עריכה] שימוש במערך

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

int[] arr = new int[size];


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

String[] arr = {"This", "Is", "My", "Array"};


הגישה לתאי המערך נעשית באמצעות שם המערך, והמספר הסידורי של התא - בתוך סוגריים מרובעים. אם כך, בהנחה שהכרזנו על מערך מסויים בשם arr, התא הראשון ייקרא arr[0], התא השני - arr[1], וכן הלאה.

[עריכה] תכונות המערך בג'אווה

הדמיה של מערך בגודל 10: תאי זיכרון שמספרם 0 עד 9 מסודרים בשורה
  • מספרי התאים במערך מתחילים מ-0, ונגמרים בתא שמספרו הסידורי הוא כגודל המערך פחות אחד. לדוגמה - אם יצרנו מערך בגודל 5, מספרי התאים הזמינים הם 0, 1, 2, 3, 4. תא מספר 5 לא קיים. זוהי תכונה שקיימת בשפות תכנות אחרות רבות.
  • גישה לתא שאינו קיים תגרום לשגיאת זמן ריצה - התוכנית תעבור הידור, אך תקרוס באמצע הריצה - תוצאה בלתי רצוייה בעליל. לכן, יש לנהוג בזהירות עם הגישה למספרי התאים, ולזכור תמיד את צורת המספור כפי שתוארה בסעיף הקודם.
  • לא ניתן לשנות גודל של מערך לאחר ההכרזה עליו - מספר התאים המירבי נשאר קבוע. מבני נתונים אחרים מאפשרים להתמודד עם בעייה זו.
  • סוג המשתנים שבמערך הוא יחיד - לא ניתן לערבב משתנים מסוגים שונים במערך אחד (הערה: על ידי שימוש בפולימורפיזם, ערבוב מסויים ייתכן, אך זהו נושא שעדיין רחוק).
  • לאחר יצירת המערך, הערכים שבתאי המערך יקבלו ערך ברירת מחדל - במקרה של int, למשל, כל איברי המערך יהיו 0, מערך double יכיל 0.0, String יכיל null, וכן הלאה.

[עריכה] מערכים ולולאות

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

System.out.print(arr[0]+" ");
System.out.print(arr[1]+" ");
System.out.print(arr[2]+" ");
System.out.print(arr[3]+" ");
System.out.print(arr[4]);
System.out.println();

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

for(int i=0; i<5; i++) {
        System.out.print(arr[i]+" ");
}
System.out.println();

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

[עריכה] פעולות נפוצות

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

[עריכה] קלט

ישנן כמה דרכים להזין מידע למערך. את הדרך הראשונה כבר ראינו - להכניס מידע בזמן האתחול. דרך פשוטה אחרת היא הזנה של המידע כמו במשתנים רגילים: arr[i] = value;, כאשר arr הוא שם המערך, i הוא מספר התא, ו-value - הערך אותו אנחנו רוצים להכניס. נראה דוגמה להכנסת מידע למערך:

double[] arr = new double[30];
Scanner s = new Scanner(System.in);
for(int i=0; i<30; i++) {
        System.out.println("Enter climate data for day "+i+": ");
        arr[i]=s.nextDouble();
}

[עריכה] פלט

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

double average=0;
for(int i=0; i<30; i++) {
        average+=arr[i];
}
average=average/30;
System.out.println("Average is "+average);

[עריכה] העתקה

גם העתקה של מערך צריכה להתבצע תא אחרי תא. שימו לב: מאחר שמערך הוא אובייקט, ניתן לכתוב פקודה כמו arr2=arr; (בהנחה ששני אלו הם מערכים) - התוכנית תרוץ כשורה, ואם נבדוק את תוכן המערכים, נראה ש-arr ו-arr2 אכן זהים. עם זאת, ההעתקה אינה אמיתית - arr2 יכיל רק הפנייה למערך arr. אם נשנה ערך של תא מסויים במערך arr - הוא ישתנה ב-arr2. לכן, אין להשתמש בשיטת ההעתקה הזו. שימוש בה יכול להביא לתקלות רבות. בדוגמה הבאה אנו מעתיקים את הערכים שבמערך המקורי למערך חדש, arr2, שכל נתון בו שווה לחצי מהערך המקביל במערך המקורי.

double[] arr2 = new double[30];
for(int i=0; i<30; i++) {
        arr2[i]=arr[i]*0.5;
}

[עריכה] מערכים משוכללים יותר

הדמיה של מערך דו מימדי פשוט בגודל 5X5 - תאי הזיכרון מסודרים בטבלה ריבועית, כאשר כל מקום בטבלה מסומן במספר שורה ומספר עמודה.

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

[עריכה] מערכים של אובייקטים

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

[עריכה] מערכים דו-מימדיים ורב מימדיים

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

{{{גודל}}}

כדאי לדעת:

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


אם נעשה הקבלה לתחום המתמטיקה, ניתן להתבונן על מערך בגודל N כווקטור ממימד N, ועל מערך דו מימדי בגודל NxM - כמטריצה בגודל NxM. נראה כעת כיצד משתמשים במערכים אלה בצורה מעשית.

[עריכה] מערכים דו-מימדיים פשוטים

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

String[][] music = new String[5][13];


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

for(int i=0; i<5; i++) {
        for(int j=0; j<13; j++) {
                System.out.print(music[i][j]+"\t");
        }
        System.out.println();
}

כמו שניתן לראות, בצורה מקבילה ללולאות בהן משתמשים עם מערכים חד-מימדיים, במערך דו מימדי נוח להשתמש בשתי לולאות, אחת בתוך השנייה.

[עריכה] מערכים לא אחידים

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

String[][] music = {{"Album 1", "Song", "Another song"},
                                {"Album 2", "First Song", "Second song"},
                                {"Album 3", "First Song", "Second song", "Third song"},
                                {"Album 4"}};

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

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

אתחול:

String[][] music = new String[5][];


כעת מאתחלים את תתי המערכים שבתוכו. נאתחל את הראשון:

music[0] = new String[13];


את השני:

music[1] = new String[13];


וכנהוג במערכים, נוח הרבה יותר לעשות זאת בעזרת לולאה:

for(int i=0; i<5; i++)
        music[i] = new String[13];

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

[עריכה] עבודה עם מערכים לא אחידים

כאשר משתמשים במערכים שאינם אחידים בגודלם, קשה עד בלתי אפשרי להשתמש בלולאות כמו שראינו עד כה. לכן, כדאי להשתמש באפשרות length, שמאפשרת לדעת את גודל המערך. גודלו של מערך בשם arr יינתן לנו על ידי הפקודה arr.length. שתי הערות:

  • בניגוד לאפשרות דומה שקיימת עם משתנים מטיפוס String, כאן אין צורך בסוגריים. תזכורת: כדי לקבל את אורכה של מחרוזת בשם str, נשתמש בפקודה str.length().
  • הנתון שמוחזר הוא מספר שלם, ששווה לגודל המערך. יש לזכור שמיספור איברי המערך מתחיל ב-0, ולכן האינדקס (כלומר, המספר הסידורי) של האיבר האחרון אינו גודל המערך, אלא גודל המערך פחות אחד.

נראה דוגמה לשימוש ב-length:

for(int i=0; i<music.length; i++) {
        for(int j=0; j<music[i].length; j++) {
                System.out.print(music[i][j]+"\t");
        }
        System.out.println();
}

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

[עריכה] מערכים רב-מימדיים

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

int arr[][][][] = new int[10][9][8][7];


גם הגישה לאיברי מערך כזה היא, כפי שקל לצפות:

arr[0][0][0][0] = 1;


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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

תרגילים

[עריכה] פעולות בסיסיות

[עריכה] בנייה ואתחול של מערך

כתבו תוכנית שתיצור מערך מסוג int ובו 10 איברים, ותכניס לתאיו את הערכים 1 עד 10, בהתאמה. לאחר מכן תדפיס התוכנית את תוכן המערך.


[עריכה] מערך בגודל משתנה

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


[עריכה] חיפוש במערך

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

int[] arr = new int[100];
for(int i=0; i<arr.length; i++) 
        arr[i] = (int) (1 + Math.random()*100);

הסבר: הפונקציה Math.random יוצרת מספר אקראי מסוג double, שערכו נע בין 0.0 ל-0.999.... כדי לקבל מספר בין 0 ל-99, הכפלנו את התוצאה ב-100, וכדי לקבל ערך בין 1 ל-100 - הוספנו 1. לאחר מכן המרנו את המספר להיות מסוג int במקום מסוג double.

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



Crystal Clear app launch.png

אתגר:

האם ניתן לבנות מנגנון מהיר יותר שיבצע את אותה המשימה? האם אפשר לבנות מנגנון מהיר יותר לחיפוש במערך, כאשר יודעים כי המערך מסודר בסדר עולה או יורד?



[עריכה] מיון של מערך

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


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

[עריכה] אמנות מודרנית

כתבו תוכנית שתבנה מערך דו מימדי בגודל 5X5, תמלא אותו באופן אקראי בסימנים "*", "#", "!", או "&", ותדפיס אותו.

שנו את התוכנית כך שהמערך יכיל 10 עמודות, ושורות המערך יהיו בגודל אקראי (בין 1 ל-10).

שיטות

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

[עריכה] מבנה

כל שיטה בנוייה מכמה חלקים:

  • שם השיטה: זהו השם שמזהה את השיטה. הכללים לגבי שמות השיטות דומים לכללים המקבילים הנוגעים למשתנים. כדאי מאוד לתת לשיטות שם שמתאר את תפקידן בקצרה, כדי להקל על הבנת הקוד בעתיד. ב-Java נהוג לתת לשיטות שמות שמתחילים באות קטנה. אם שם השיטה מורכב מכמה מילים, האות הראשונה בכל מילה תהייה גדולה. דוגמה: printAllLines. באנגלית מכונה צורת כתיבה זו Camel Case.
  • משתני קלט: שיטות יכולות (אך אינן חייבות) לקבל קלט המורכב מאוסף של משתנים ואובייקטים.
  • משתנה פלט: שיטות יכולות (אך גם כאן, אינן חייבות) להחזיר ערך יחיד כלשהו. הבנה של אופן השימוש בשיטות תסביר מדוע קיימת המגבלה הזאת, של הערך היחיד, ומהן השיטות לעקוף אותה. ההחזרה מתבצעת באמצעות המילה השמורה return.
  • תוכן השיטה עצמו: אוסף הפעולות אותן מבצעת השיטה. האוסף הזה יכול להיות ארוך מאוד או קצר מאוד - גם שיטה ריקה היא חוקית! עם זאת, ראוי להימנע מכתיבת שיטות ארוכות מאוד, שעשויות להקשות על ההבנה.

[עריכה] שימוש

נציג כאן את אופן השימוש בשיטות באמצעות כמה דוגמאות. נתחיל בדוגמה לשיטה פשוטה מאוד:

public static void printHello() {
        System.out.println("Hello");
}

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

public class FirstMethod {
 
        public static void printHello() {
                System.out.println("Hello");
        }
 
        public static void main(String[] args) {
                printHello();
        }
}

כדי לקרוא לשיטה, כתבנו printHello();‎, ב-main והשיטה בוצעה. איננו חייבים לקרוא לשיטה דווקא מה-main: אפשר לקרוא לשיטה מכל שיטה אחרת, ואפילו מאותה השיטה עצמה (מה יקרה אם נוסיף את השורה printHello();‎ לשיטה printHello? נסו!). נתעכב כעת בצורה מפורטת יותר על השורה הראשונה של השיטה: תחילת השורה במילה public, שמצהירה על כך שהשיטה היא פומבית. זה עניין שנוגע לתכנות מתקדם יותר, אך בקצרה ניתן לומר שבג'אווה קיימת מערכת של הרשאות, והמילה public מאפשרת לכל אחד לגשת לשיטה זו. המילה הבאה היא static, שנוגעת לתכנות מונחה עצמים. גם לגביה, נוותר על ההסבר. המילה הבאה מעניינת אותנו הרבה יותר: המילה void היא הצהרה לגבי משתני הפלט של השיטה: המילה void, שפירושה המילולי הוא "ריק", אומרת למחשב שהשיטה לא מחזירה שום ערך שהוא. אם השיטה הייתה מחזירה ערך, את המילה void היה מחליף סוג המשתנה שהשיטה מיועדת להחזיר.

נעבור כעת לשיטה מעט מורכבת יותר, המשתמשת גם במשתני קלט ופלט:

public static int power(int x, int n) {
        if(n<=0) return 1;
        int num=1;
        for(int i=0; i<n; i++)
                num = num*x;
        return num;
}

זוהי שיטה שמטרתה לחשב חזקה: היא מקבלת שני מספרים שלמים ומחזירה את תוצאת ההעלאה בחזקה של המספר הראשון בשני. נעיר כי למען הנוחות, תוצאת העלאה בכל חזקה שלילית (או 0) נקבעה להיות 1, והשיטה מקבלת מספרים שלמים בלבד. נתבונן על השינויים בשיטה ביחס לשיטה הקודמת: השינויים הראשונים נמצאים בשורה הראשונה: את מקום המילה void החליפה המילה int, וזאת מכיוון שהשיטה הזו מחזירה ערך, והוא מטיפוס int. שינוי (משמעותי) אחר מהווים המשתנים int x ו-int n שהופיעו בתוך הסוגריים, שבשיטה הקודמת היו ריקות. משתנים אלה הם המשתנים שהשיטה מקבלת - הם מוגדרים בתוך השיטה וערכם הוא הערך שהוצב כאשר שיטה אחרת קראה לשיטה הזו. השינוי המשמעותי האחרון היא המילה return. כאשר מילה זו מופיעה - פעולת השיטה מסתיימת, והערך שנכתב אחרי המילה יוחזר. שימו לב - הערך שמוחזר חייב להיות מאותו הטיפוס שקבענו! לדוגמה, אם בשיטה power, שהוגדרה להחזיר טיפוס int, ננסה להחזיר מספר מטיפוס double - ניתקל בשגיאה. כמו שאפשר לראות, בעזרת return ניתן להחזיר משתנה או קבוע - אין הבדל, ובתנאי שהטיפוס מתאים. גם בשיטה שלא מחזירה ערך (void) אפשר להשתמש ב-return בלי כל ערך (return;‎), וזה יביא לסיום מיידי של פעולת השיטה - אמצעי שיכול להיות שימושי.

נציג כאן את התוכנית השלמה:

public class AnotherMethod {
 
        public static int power(int x, int n) {
                if(n<=0) return 1;
                int num=1;
                for(int i=0; i<n; i++)
                        num = num*x;
                return num;
        }
 
        public static void main(String[] args) {
                int i=2, j=5;
                int solution = power(i, j);
                System.out.println(i+"^"+j+"="+solution);
        }
}

באותה מידה שיכולנו לכתוב

solution=25;


או

solution=i*j;


הצבנו בו את ערך השיטה בצורה

solution=power(i,j);


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

[עריכה] תחום הגדרה

נתחיל בניסוי. העתיקו את התוכנית הבאה:

public class Testing {
 
        public static void manipulate(int a, int b) {
                a=3;
                b=4;
        }
 
        public static void main(String[] args) {
                int a=1, b=2;
                manipulate(a, b);
                System.out.println("A is: "+a+", B is: "+b);
        }
}

מה תדפיס התוכנית? נסו לנחש, ואז הריצו אותה. הניחוש היה, קרוב לוודאי, שהפלט יהיה

A is 3, B is 4


למעשה הפלט היה

A is 1, B is 2


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

[עריכה] תחום ההגדרה של משתנים מקומיים

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

[עריכה] משתנים מקומיים וקריאה לשיטות

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

שיטת עבודה זו מכונה Pass by Value (בניגוד ל-Pass by Reference).

[עריכה] משתנים גלובליים

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

static String str;



[עריכה] קבועים

קבועים הם משתנים גלובליים שאת ערכם מקבעים (בדרך כלל) בתחילת התוכנית באמצעות המילה השמורה final. לדוגמה, אם נרצה להגדיר קבוע מסוג int נכתוב

final static int a=5;


בתחילה עשויים הקבועים להיראות מיותרים - מדוע שמישהו ירצה משתנה שכזה? למעשה, מדובר בכלי שימושי וחשוב:

  • שימוש בקבועים יעזור לקוד להיות קריא יותר. אם במקום מספר או מילה מסויימת נציב קבוע ששמו הוא בעל משמעות - יהיה קל הרבה יותר להבין את מטרת הקוד.
  • שימוש בקבועים עשוי לחסוך הרבה עבודה: אם משתמשים בנתון מסויים פעמים רבות אפשר לשנות את ערכו באמצעות שינוי אחד (של ערך הקבוע) במקום שינויים במקומות רבים בקוד.
  • שימוש בקבועים מקצר לפעמים את משך העבודה. במקום לכתוב את אותו משפט ארוך\מספר עשרוני מורכב פעמים רבות - אפשר להציב את הערך בקבוע ולהשתמש בו במקום.

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

{{{גודל}}}

כדאי לדעת:

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


נציג כאן תוכנית פשוטה המשתמשת בקבועים:

import java.util.Scanner;
 
public class Testing {
 
        // Maximum pyramid's height
        final static int MAX_HEIGHT = 10;
        // Pyramid's print shape
        final static char SHAPE='#';
 
        /*
         * Prints a pyramid with a given height. If height is illegal - quits
         * with an error message.
         */
        public static void printTheShape(int height) {
                // Check legality of height
                if(height>MAX_HEIGHT || height<1) {
                        System.out.println("Illegal height!");
                        return;
                }
                // Draws the pyramid
                for(int i=1;i<=height; i++) {
                        for(int j=0; j<i; j++) 
                                System.out.print(SHAPE);
                        System.out.println();
                }
        }
 
        /*
         * Main method
         */
        public static void main(String[] args) {
                Scanner s = new Scanner(System.in);
                System.out.print("Enter pyramid's height: ");
                int h = s.nextInt();
                printTheShape(h);
        }
}

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

[עריכה] החזרה של משתנים מרובים

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

  • החזרה של מערך. המערך הוא אמנם עצם אחד, אבל מכיל בתוכו איברים רבים. נראה דוגמה לכך:
public class Methods {
 
        // Array size
        public static final int N=10;
 
        /*
         * Create and return a new array
         */
        public static int[] returnArr(int n) {
                int[] newArr = new int[n];
                for(int i=0; i<n; i++)
                        newArr[i] = i;
                return newArr;
        }
 
        /*
         * Prints an integer array
         */
        public static void printArr(int[] arr) {
                for(int i=0; i<arr.length; i++)
                        System.out.print(arr[i]+" ");
                System.out.println();
        }
 
        /*
         * Main method 
         */
        public static void main(String[] args) {
                int[] myArr = returnArr(N);
                printArr(myArr);
        }
}
  • שינוי ערכי מערך. מערך, בהיותו אובייקט, שומר על הערכים שבתוכו גם במעבר בין שיטות. ניתן להשתמש בשיטה זו כדי להשתמש במערך כמתווך, שיכיל את הערכים אותם אנחנו רוצים להעביר, וזאת בלי להשתמש כלל בפקודה return (או להשתמש בה כדי להחזיר נתון נוסף). נראה דוגמה:
public class Methods {
 
        // Array size
        public static final int N=10;
 
        /*
         * Change array values
         */
        public static void changeArr(int[] arr) {
                for(int i=0; i<arr.length; i++)
                        arr[i] = arr[i]+1;
        }
 
        /*
         * Prints an integer array
         */
        public static void printArr(int[] arr) {
                for(int i=0; i<arr.length; i++)
                        System.out.print(arr[i]+" ");
                System.out.println();
        }
 
        /*
         * Main method 
         */
        public static void main(String[] args) {
                int[] myArr = new int[N];
                for(int i=0; i<N; i++)
                        myArr[i] = i;
                System.out.print("Before changing: ");
                printArr(myArr);
                changeArr(myArr);
                System.out.print("After changing: ");
                printArr(myArr);
        }
}

[עריכה] עקרונות מנחים

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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

תרגילים

[עריכה] שיטות פשוטות

כתבו את השיטה printName(String name) המקבלת מחרוזת שמכילה שם, ומדפיסה את השם שהתקבל בצירוף הודעה מתאימה. כתבו גם main מתאים, כך שהתוכנית תוכל לרוץ.


כתבו שיטה נוספת, connectName(String first, String last) המקבלת שם פרטי ושם משפחה, ומחזירה את השם מחובר (כלומר, מחרוזת שמורכבת מהשם הפרטי ושם המשפחה, מופרדים ברווח). שנו את השיטה printName כך שתקבל שם פרטי ושם משפחה, והשתמשו בשיטה החדשה שכתבתם כדי לחבר את השם למחרוזת אחת ולהדפיסו. שנו גם את ה-main בהתאם. התוכנית לא זקוקה ל-main בן יותר משורה אחת כדי לעבוד.


[עריכה] משחק הניחושים

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

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

כעת, כתבו שיטה שמבקשת מהשחקן להכניס ניחוש, קולטת את הניחוש, ומחזירה אותו.

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

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



Crystal Clear app launch.png

אתגר:

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

רקורסיה

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

[עריכה] רקורסיה פשוטה

נתחיל בדוגמה: העתיקו והריצו את התוכנית הבאה:

public class Recursion {
        public static void printMe()
        {
                System.out.println("Printing...");
                printMe();
        }
 
        public static void main(String[] args) {
                printMe();
        }
}

חכו עד שהתוכנית תיעצר מעצמה. מה קרה?

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

public class Recursion {
        public static void printMe(String s)
        {
                System.out.println(s);
                printMe(s.substring(1));
        }
 
        public static void main(String[] args) {
                printMe("This is my string");
        }
}

גם תוכנית זו צפוייה לסיים את חייה בהתרסקות. ננסה גירסה שלישית:

public class Recursion {
        public static void printMe(String s)
        {
                if(s.length()>0)
                {
                        System.out.println(s);
                        printMe(s.substring(1));
                }
        }
 
        public static void main(String[] args) {
                printMe("This is my string");
        }
}

[עריכה] הסבר

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

Exception in thread "main" java.lang.StackOverflowError


מדוע זה נגמר, ולא נמשך עד אין סוף, כמו לולאת while אינסופית?

הדמייה של פעולת המחסנית

כדי להבין את הסיבה לכך, צריך להכיר את התהליך שנמצא מאחורי הקלעים. בכל פעם שאנו קוראים לשיטה, המחשב שומר בזכרונו את המצב האחרון בו היינו. אם, למשל, קראנו פעם אחת לשיטה "printMe" מה-main, המחשב שומר בזכרונו את המצב האחרון בו הייתה ה-main - באיזו שורה היינו, מה מצב המשתנים המקומיים שלה, וכן הלאה. אם השיטה לה קראנו קראה לשיטה נוספת - גם מצבה של זו נשמר, וכן הלאה. כל המידע הזה נשמר במבנה מיוחד הנקרא "מחסנית" (באנגלית - Stack), בו הנתון האחרון שנכנס - הוא הנתון הראשון שיוצא. כשמסתיימת פעולתה של שיטה - היא נמחקת מהמחסנית. בתוכנית שלנו, התבצעה קריאה חוזרת לאותה השיטה, ללא הפסקה. כל קריאה כזו התווספה למחסנית, עד שזו כרעה תחת הנטל, וקרסה יחד עם התוכנית.

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

[עריכה] מבנה הרקורסיה

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

[עריכה] שיטה רקורסיבית שמחזירה ערך

בשלוש הדוגמאות הקודמות השתמשנו בשיטה שקוראת לעצמה, אך לא מחזירה שום ערך. הריצו את הדוגמה הבאה. מה היא תבצע?

public class Recursion {
        public static int sum(int n)
        {
                if(n<1)
                        return 0;
                else
                {
                        return n+sum(n-1);
                }
        }
 
        public static void main(String[] args) {
                System.out.println(sum(3));
        }
}

נעקוב במפורט אחרי הפעולות שהתבצעו:

  1. ה-main קראה לשיטה sum עם הארגומנט 3.
  2. בתחילת פעולת השיטה התבצעה הבדיקה: האם הארגומנט שקיבלנו - n - קטן מ-1? מאחר והתשובה שלילית, המשיכה התוכנית הלאה.
  3. התוכנית מגיעה לפקודת return, אך צריכה להחזיר ערך שלא ידוע עדיין: הסכום של n - אותו אנחנו כבר יודעים, עם התוצאה של השיטה sum על הערך 2. ערך ההחזרה כרגע הוא 3 ועוד sum(2).
  4. מתבצעת קריאה רקורסיבית לשיטה sum, והפעם ערכו של n הוא 2. גם כאן לא ענינו על התנאי n<1, לכן ממשיכים הלאה - אל הפקודה return. במחסנית שמורה הקריאה הקודמת, בה n=3.
  5. ערך נוסף להחזיר: 2 ועוד sum(1). מתבצעת קריאה רקורסיבית נוספת, ואל המחסנית נוספת הקריאה בה n=2.
  6. הפעם ערכו של n הוא 1, ובאופן דומה למה שכבר ראינו, מתבצעת קריאה רקורסיבית נוספת, עם הערך 0. גם הקריאה הזו מצטרפת למחסנית.
  7. התוכנית נעצרת הפעם בתנאי: n הוא קטן מ-1, לכן התוכנית מחזירה 0, וחוזרת שלב אחד אחורה: הקריאה בה n=1 נשלפת מהמחסנית.
  8. החישוב ממשיך: 1 ועוד sum(0) שווה ל-1, וזה הערך של sum(1). ממשיכים לטפס: הערך עבור הקריאה בה n=1 הוא 1 (1+0), הערך עבור הקריאה בה n=2 הוא, לכן, 3 (2+1), והערך עבור הקריאה n=3 הוא 6 (3+3).
  9. סיימנו - כל הקריאות שהיו במחסנית נמחקו, ואפשר לחזור אל ה-main, שם מודפס הפלט - 6.

[עריכה] כיוון אחר

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

public class Recursion {
 
        public static void backwards(int[] arr, int n) {
                if(n>arr.length-1)
                        return;
                backwards(arr, n+1);
                System.out.println(arr[n]);
        }
 
        public static void main(String[] args) {
                int[] arr = {1, 2, 3, 4};
                backwards(arr, 0);
        }
}

התהליך כאן הוא קצת שונה. השיטה קראה לעצמה לפני ההדפסה. השיטות שנקראו החלו להיצבר על המחסנית, עד שהתוכנית הגיעה לתנאי העצירה. בשלב זה, לא התבצעה קריאה חוזרת אלא הסתיימה מיד פעולת השיטה, בעזרת הפקודה return, והקריאה הזו נמחקה מהמחסנית. התוכנית, אם כך, חזרה שיטה אחת לאחור (במחסנית), בדיוק אל המקום בו הייתה קודם: פקודת ההדפסה. פקודת ההדפסה הזו התרחשה לגבי n=4, לכן האיבר הראשון שמודפס הוא האיבר הרביעי. בשלב זה הסתיימה פעולת הקריאה הזו, ושוב נשלפה שיטה מהמחסנית - הפעם זו בה n=3, והאיבר השלישי הודפס. כך המשיכה התוכנית עד שהתרוקנו כל הקריאות מהמחסנית.

[עריכה] קריאה כפולה

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

public class Recursion {
        public static int fibo(int n)
        {
                if(n==1 || n==2)
                        return 1;
                int num1 = fibo(n-1);
                int num2 = fibo(n-2);
                return num1 + num2;
        }
 
        public static void main(String[] args) {
                int n = 7;
                System.out.println("Element number "+n+" is "+fibo(n));
        }
}

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

[עריכה] חסרונות ויתרונות

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

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


Crystal Clear app launch.png

אתגר:

נסו לחשוב על דרך למצוא את האיבר ה-n בסדרת פיבונאצ'י ללא רקורסיה.



מדוע להשתמש ברקורסיה, אם כך?

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

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

[עריכה] עוד על רקורסיה

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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

תרגילים

[עריכה] רקורסיה פשוטה

[עריכה] הדפסה רקורסיבית

כתבו פונקציה רקורסיבית שתקבל מספר שלם כלשהו (ידוע שאינו שלילי) וסימן (משתנה מטיפוס char), ותדפיס את הסימן כמספר הפעמים שהתקבלו.


[עריכה] חזקה

כתבו פונקציה רקורסיבית שתקבל שני מספרים שלמים, ותחזיר את הראשון בחזקת השני. אם מנסים להעלות מספר בחזקת אפס - הפונקציה תחזיר 1. אם מנסים להעלות בחזקה שלילית - הפונקציה תחזיר 0.


Crystal Clear app launch.png

אתגר:

האם קיימת דרך להעלות מספר בחזקה בעזרת מספר קטן יותר של פעולות? האם תוכלו לעשות זאת בעזרת שיטה רקורסיבית?



בדיקת שגיאות

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

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

תחביר התפיסות הוא כזה:


try
{
. . .
}
catch(IOException ioe)
{
. . .
}
catch(Exception e)
{
. . .
}

סיכום ותרגילים

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

[עריכה] כתיבת קוד טובה

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

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

[עריכה] תרגילים

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

[עריכה] איקס-עיגול

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

[עריכה] סלט מילים

כתבו תוכנית המקבלת קטע טקסט (מחרוזת באורך לא ידוע) ומסדרת אותו מחדש בסדר אקראי, באמצעות פירוקו למילים וכתיבת המילים בסדר חדש. מילה, לצורך העניין, מופרדת ממילה אחרת באמצעות רווח (" "), או כמה רווחים רצופים. לכן, למשל, המחרוזת "One,two" נחשבת כמילה אחת, אבל "One Two", או "One Two" הן שתי מילים. רמז: העזרו בשיטה שמקבלת מחרוזת וסופרת כמה מילים נמצאות בה, ובשיטה נוספת, שתקבל משפט ומספר המילים שנמצאות בו, ותחזיר מערך המכיל את כל המילים. דאגו לכך שהתוכנית תדע לכתוב כל מילה שמצאנו בסדר אקראי ובלי שנחזור על אותה המילה פעמיים.

[עריכה] עד 21

כתבו את המשחק "עד 21", בו מתחרים כמה שחקנים - מי יגיע ראשון ל-21? מהלך המשחק: כל שחקן מתחיל עם מספר נקודות אקראי, בין 2 ל-20. לאחר מכן, נשאל כל שחקן בתורו האם הוא רוצה להגדיל את הסכום שברשותו. אם הוא מעוניין, הסכום שלו גדל באופן אקראי במספר בין 1 ל-10. שחקן שסכומו עבר את ה-21 - מפסיד ויוצא מהמשחק. אם הוא לא מעוניין, הוא לא יוכל להגדיל את סכומו יותר. כשאף שחקן לא מעוניין להגדיל יותר את הסכום שברשותו, מנצח השחקן שברשותו הסכום הקרוב ביותר ל-21 (כולל 21). אם יש כמה בעלי אותו הסכום - מוכרז תיקו. מספר השחקנים אינו קבוע, והוא יהיה בין 2 ל-6. רמז: מכיוון שמספר השחקנים משתנה, השתמשו במערכים כדי לייצג את השחקנים ומצבי המשחק השונים, והיעזרו בלולאות.

[עריכה] ראשוניים

כתבו תוכנית, יעילה ככל האפשר, שתמצא ותשמור את כל המספרים הראשוניים שגודלם עד N (כלומר: 1, 2, 3, 5, 7, ..., עד N), כאשר N הוא מספר נתון (משתנה קבוע כלשהו). אפשר להניח שמספר הראשוניים עד N הוא קטן ממספר נתון אחר (משתנה קבוע אחר) - הבחירה לא חייבת להיות מדוייקת, אך חייבת להיות גדולה מספיק כך שתכיל את כל הראשוניים שמצאנו (מן הסתם, מספר הראשוניים עד N קטן או שווה ל-N, לכן כדאי לבחור מספר שאינו גדול מ-N). אפשר, לשם הדוגמה, לבחור את N להיות 1000, ואת הקבוע השני להיות 500. לאחר מכן, תקבל התוכנית בלולאה מספרים שלמים ותפרק אותם לגורמים ראשוניים, בעזרת המספרים הראשוניים שמצאה בשלב הראשון. למשל: אם המשתמש יכניס את המספר 10, הוא יקבל את הפלט 2*5. אם יכניס 33, הוא יקבל 11*3. אם יכניס 45, הפלט יהיה 3*3*5. התוכנית תסתיים כאשר יוכנס מספר שלילי, או אפס. רמז: הנפה של ארטוסתנס. ניתן להניח שהמשתמש לא יבקש לפרק מספרים גדולים מאוד (ואפשר גם לדאוג שלא יעשה זאת - בעזרת תנאי מתאים).

[עריכה] ומילה אחרונה לסיום

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

נמצאה תבנית הקוראת לעצמה: תבנית:Java

תכנות מתקדם ב-Java

00%.svg

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

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

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

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

[עריכה] מה צריך לדעת לפני?

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

[עריכה] הכנה

אם למדתם כבר את הספר Java, יש בידכם את כל הדרוש. אם עדיין לא התקנתם סביבת עבודה מתקדמת כמו eclipse - כדאי לעשות זאת עכשיו. במידה ועדיין לא עסקתם בג'אווה, ניתן לקרוא הוראות מפורטות בפרק ההכנה שבספר הקודם.


- גרסה להדפסה -
כלים אישיים

גרסאות שפה
מרחבי שם
פעולות
ניווט
קהילה
תיבת כלים
דף זה בשפות אחרות
הדפסה/יצוא