ראשי » SEO_Java@Java Coding Tips

    מלאו פרטים לקבלת ייעוץ





    אני מאשר קבלת מבצעים ועדכונים מחברת RT-GROUP בכפוף לprivacy

    [honeypot Email id:email class:email]

    סקירת טיפים ודגשים לכתיבת קוד יעיל בשפת פיתוח JAVA

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

    python

    !Let's Learn Java

    שרשור מחרוזות Java

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

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

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

    נתבונן בקטע הקוד הבא:

    
    
    String text = "ABC";
    text += "123";
    text += "XYZ";
    
    

    הפעולות שנעשות בזיכרון עבור תכנית זאת היא כדלהלן:
    1) בזיכרון עבור "ABC", "123", ו- "XYZ" יוקצו בד"כ לזיכרון בתהליך שנקרא interning
    2) בשורה הראשונה text מקבל הפנייה ל-"ABC"
    3) בשורה השנייה נוצר אובייקט מחרוזת חדש בזיכרון שמעתיק את התוכן של "ABC" ושל -"123" (העתקה של 6 תוים) ומתקבלת המחרוזת "ABC123".
    4) בשורה השלישית נוצר אובייקט מחרוזת חדש בזיכרון שמעתיק את התוכן של "ABC123" ושל "XYZ" (העתקה של 9 תוים)
    5) כיוון שהמחרוזת "ABC123" נותרת ללא הפניה, ה-garbage collector ינקה אותה מהזיכרון כאשר יבצע סקירה.

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

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

    
    Scanner in = new Scanner(System.in);
    String s = "";
    
    for (int i=0; i<100; i++) {
        s += in.nextLine();
    }
    
    System.out.println("result:")
    System.out println(s)
    
    
    

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

    תמונת אווירה

    הפיתרון: StringBuilder

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

    נתבונן בתכנית מעודכנת

    
    
    Scanner in = new Scanner(System.in);
    StringBuilder sb = StringBuilder();
    
    for (int i=0; i<100; i++) {
        sb.append(in.nextLine());
    }
    
    System.out.println("result:")
    System.out println(s.toString())
    
    
    
    

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

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

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

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

    
        String s = "ABC123XYZ";
    
    
    
    String s = "ABC"
             + "123"
             + "XYZ";
    
    

    שימוש בטיפוסים פרימיטיביים

    כאשר נרצה להשתמש בערכים בסיסיים כגון מספרים או ערכי true ו-false נעדיף להשתמש בטיפוסים פרימיטיביים (int, short, long, float double, boolean, char) טיפוסים אלה אינם אובייקטים וכתוצאה מכך תופסים פחות מקום באופן משמעותי (בית אחד עד 8 בתים עבור פרימיטיביים לעומת 16 בתים או יותר עבור אובייקטים). כמו-כן הגישה למידע נעשה בצורה ישירה יותר כיוון שפרימיטיביים נשמרים על גב המחסנית לעומת אובייקטים בג'אווה שנשמרים תמיד על ה-heap והגישה אליהם היא באמצעות הפנייה.

    שימוש ב-switch case

    כאשר נרצה לכתוב קוד שבודק את ערכו של ביטוי בודד נעדיף להשתמש ב-switch case לעומת if else.
    למשל נתבונן בקטע הקוד הבא:

    
    
    Scanner in = new Scanner(System.in);
    int x = in.nextInt();
    
    if (x == 1) System.out.println("Option 1");
    else if (x == 2) System.out.println("Option 2");
    else if (x == 3) System.out.println("Option 3");
    else if (x == 4) System.out.println("Option 4");
    
    
    

    כדי להגיע לאפשרות 4, המחשב צריך לבצע 4 תנאים אילו היה מדובר ב-100 אפשרויות המחשב היה צריך לבצע 100 תנאים עבור התנאי ה-100 ו-99 תנאים עבור התנאי ה-99 וכו'. ז"א שהסיבוכיות היא (O(n.

    לעומת זאת:

    
    
    
    Scanner in = new Scanner(System.in);
    int x = in.nextInt();
    
    Switch(x){
    case 1:
        System.out.println("Option 1");
    case 2:
        System.out.println("Option 2");
    case 3:
        System.out.println("Option 3");
    case 4:
        System.out.println("Option 4");
    }
    
    
    

    במקרה זה, Java מייצרת טבלת קפיצה (lookupswitch או tableswitch) שלוקחת את הערך המושווה ומחפשת אותו בטבלה (תהליך בסיבוכיות של (1)O עבור tableswitch ובסיבוכיות של (O(log n עבור lookupswitch) ובהתאם אליו מואצת לאיזה אזור בקוד יש לקפוץ ואז מבצעת קפיצה נוספת.

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

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

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

    מדוע כדאי ללמוד Java
    תרגילים ופתרונות שפת Java