פונקציות (Methods)

מה זו פונקציה?

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

ב-Java, כל פונקציה חייבת להיות בתוך מחלקה.

למה צריך פונקציות?

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

מבנה בסיסי

[modifier] returnType methodName(parameters) {
    // הגוף
    return value;
}

דוגמה פשוטה:

public static int add(int a, int b) {
    return a + b;
}

פירוק

  • public - נגישות (public, private, protected, ברירת מחדל)
  • static - שייך למחלקה, לא לאובייקט
  • int - הטיפוס שהפונקציה מחזירה
  • add - שם הפונקציה
  • (int a, int b) - פרמטרים
  • return a + b - הערך המוחזר

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

public class Main {
    public static void main(String[] args) {
        int result = add(5, 3);
        System.out.println(result);   // 8
    }

    public static int add(int a, int b) {
        return a + b;
    }
}

פונקציה ללא החזרה - void

כשהפונקציה לא מחזירה ערך:

public static void greet(String name) {
    System.out.println("שלום " + name);
}

// שימוש
greet("נפתלי");

void אומר "לא מחזיר כלום".

פונקציה בלי פרמטרים

public static void printLine() {
    System.out.println("----------");
}

// שימוש
printLine();

חתימת פונקציה (Signature)

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

// חתימה: add(int, int)
public static int add(int a, int b) { return a + b; }

// חתימה שונה: add(double, double) - מותר!
public static double add(double a, double b) { return a + b; }

זה נקרא העמסה (overloading) - ראו בהמשך.

העמסה (Overloading)

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

public static int max(int a, int b) {
    return (a > b) ? a : b;
}

public static double max(double a, double b) {
    return (a > b) ? a : b;
}

public static int max(int a, int b, int c) {
    return max(max(a, b), c);
}

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

max(5, 10);           // int גרסת
max(5.5, 10.2);       // double גרסת
max(1, 2, 3);         // גרסה של שלושה פרמטרים

העברת פרמטרים - by value

ב-Java, פרמטרים מועברים תמיד by value - כלומר עותק של הערך.

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

public static void changeNumber(int x) {
    x = 100;
}

public static void main(String[] args) {
    int n = 5;
    changeNumber(n);
    System.out.println(n);   // עדיין 5!
}

עבור אובייקטים

עבור אובייקטים (כולל מערכים ו-List), מועבר עותק של ההפנייה. לכן השינויים באובייקט עצמו כן נראים:

public static void changeArray(int[] arr) {
    arr[0] = 100;
}

public static void main(String[] args) {
    int[] numbers = {1, 2, 3};
    changeArray(numbers);
    System.out.println(numbers[0]);   // 100!
}

אבל אם תציב הפנייה חדשה בתוך הפונקציה - זה לא ישפיע:

public static void replaceArray(int[] arr) {
    arr = new int[]{99, 99, 99};   // רק משנה את העותק של ההפנייה
}

פרמטרים בכמות משתנה - varargs

כשלא יודעים מראש כמה פרמטרים:

public static int sum(int... numbers) {
    int total = 0;
    for (int n : numbers) {
        total += n;
    }
    return total;
}

// שימוש
sum(1, 2, 3);              // 6
sum(1, 2, 3, 4, 5);        // 15
sum();                      // 0

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

מתודה רקורסיבית

פונקציה שקוראת לעצמה - נלמד על זה בשיעור 20: רקורסיה.

public static int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

נקודות לזכור

  • פונקציית main היא רק פונקציה רגילה - רק שה-JVM מחפש אותה
  • החתימה חייבת להיות ייחודית
  • return יוצא מהפונקציה מיד
  • פונקציה עם void לא חייבת return, אבל יכולה להשתמש בו ליציאה מוקדמת:
public static void printIfPositive(int n) {
    if (n < 0) return;
    System.out.println(n);
}

דוגמה מלאה

public class MathUtils {

    public static void main(String[] args) {
        System.out.println(factorial(5));        // 120
        System.out.println(isPrime(7));          // true
        System.out.println(power(2, 10));        // 1024
    }

    public static int factorial(int n) {
        int result = 1;
        for (int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }

    public static boolean isPrime(int n) {
        if (n < 2) return false;
        for (int i = 2; i * i <= n; i++) {
            if (n % i == 0) return false;
        }
        return true;
    }

    public static long power(int base, int exp) {
        long result = 1;
        for (int i = 0; i < exp; i++) {
            result *= base;
        }
        return result;
    }
}

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה זה העמסה (overloading)?

    1. מתודה שקוראת לעצמה
    2. מתודה שמחזירה כמה ערכים
    3. מתודה עם יותר מדי קוד
    4. כמה מתודות עם אותו שם ופרמטרים שונים
    הצגת התשובה

    תשובה ד. Java בוחרת איזו גרסה להפעיל לפי מספר וסוג הארגומנטים.

  2. מה משמעות void בחתימה?

    1. המתודה לא מחזירה ערך
    2. המתודה ריקה
    3. המתודה סטטית
    4. המתודה פרטית
    הצגת התשובה

    תשובה א. void אומר שאין ערך מוחזר.