JavaRush /בלוג Java /Random-HE /מפעילי Jump ב-Java

מפעילי Jump ב-Java

פורסם בקבוצה
שלום! היום נדבר על מפעילי קפיצה ב-Java:
  • return
  • break
  • continue
  • goto
ראשית, בואו נגדיר מה זה בעצם. כידוע, במצב רגיל, תוכנית מבוצעת באופן ליניארי - מלמעלה למטה, פקודה אחר פקודה. ניתן לשנות את הזרימה הליניארית של תוכנית על ידי מה שנקרא מבני בקרה: למשל, ענפים ( if) ולולאות ( forוכו while'). בנוסף למבני בקרה, ניתן לשנות את הביצוע הליניארי של תוכנית על ידי הצהרות קפיצה. הם אחראים להפנות מחדש את ביצוע התוכנית למיקום מסוים, שתלוי בהקשר ובהצהרה הספציפית. מפעילי Jump ב-Java - 1בואו נסתכל מקרוב על כל אחד מארבעת המפעילים.

לַחֲזוֹר

זה המפעיל הזה שהמצטרפים החדשים לרוב מתוודעים אליו קודם. ההצהרה returnמסיימת את השיטה שבה היא נקראה, וביצוע התוכנית חוזר למיקום שממנו נקראה השיטה. יש לו returnשתי צורות:
  1. מסיים מיד את ביצוע השיטה.
  2. מסיים מיד את ביצוע השיטה ומחזיר ערך כלשהו כתוצאה מהשיטה.
התחביר עבור שתי הצורות הוא:
return;
return value; // где value — некоторое возвращаемое meaning
שיטות המחזירות ערך חייבות להיות לפחות אופרטור אחד returnעם ערך החזרה שמובטח להיקרא, ואסור שיהיה אופרטור returnללא ערך החזרה. בואו נסתכל על הדוגמאות שלהלן:
public int sum(int a, int b) {
    return a + b;
}

public String getGreetings(String name) {
    return "Hello " + name;
}

public int max(int x, int y) {
    if (x > y) {
        return x;
    } else {
        return y;
    }
}
בשיטות שאינן מחזירות ערך (שיטות void), מקובל, אך לא חובה, לפחות משפט אחד returnללא ערך החזרה, ולא משפט אחד returnעם ערך החזרה. בואו נסתכל על זה עם הדוגמאות שלהלן:
public void print(String s) {
    // наличие return в void методах не обязательно
    System.out.println(s);
}

//Метод выведет в консоль число, если оно нечетное
public void printIfOdd(int number) {
    if (number % 2 == 0) {
        // Если число четное, метод завершит свою работу
        // Наличие return в void методах опционально
        return;
    }

    System.out.println(number);
}

// Метод выведет в консоль наибольшее meaning из массива
private void printMaxInArray(int[] array) {
    if (array == null || array.length == 0) {
        /*
         Если массив пуст, метод завершит свою работу.
         Иногда полезно проверять подобным образом аргументы метода вначале и прерывать выполнение метода, если аргументы не подходят для дальнейшей корректной работы
        */
        System.out.println("Empty array");
        return;
    }

    int max = array[1];
    for (int i = 1; i < array.length; i++) {
        if (array[i] > max) {
            max = array[i];
        }
    }
    System.out.println(max);
}

תוויות

לפני שאני מסתכל על אופרטורים breakו continue, ​​אני רוצה לדבר על תוויות ב-Java. זה חשוב מכיוון שבמצבים מסוימים, breakואופרטורים continueמשמשים בשילוב עם תוויות. אבל תחילה, נסה לענות על השאלה האם הקוד הזה יתבצע קומפילציה:
public static void main(String[] args) {
    https://www.google.com/
    System.out.println("Interesting...");
}
תווית היא קטע קוד בעל שם. התווית עצמה אינה מספקת פונקציונליות כלשהי. זה משהו כמו סימניה בקוד שהמתכנת מתכוון להשתמש בו מאוחר יותר. תווית בקוד מוגדרת בצורה פשוטה למדי - באמצעות שם ונקודתיים. לדוגמה:
  • labelName:
  • outerLoop:
  • printing:
  • anyWordYouLike:
וכך נראות התוויות בתוך קוד ה-Java:
public static void main(String[] args) {
    definePrintName:
    System.out.println("Таблица Умножения");

    loop1:
    for (int i = 1; i <= 10; i++) {
        loop2:
        for (int j = 1; j <= 10; j++) {
            System.out.printf("%4d", i * j);
        }
        System.out.println();
    }
}
הפלט של השיטה mainיהיה כדלקמן:
Таблица Умножения
   1   2   3   4   5   6   7   8   9   10
   2   4   6   8   10  12  14  16  18  20
   3   6   9   12  15  18  21  24  27  30
   4   8   12  16  20  24  28  32  36  40
   5   10  15  20  25  30  35  40  45  50
   6   12  18  24  30  36  42  48  54  60
   7   14  21  28  35  42  49  56  63  70
   8   16  24  32  40  48  56  64  72  80
   9   18  27  36  45  54  63  72  81  90
  10  20  30  40  50  60  70  80  90  100

Process finished with exit code 0
בדוגמה למעלה definePrintName, loop1:והן loop2:תוויות. loop1:ו"סמן loop2:" שני מחזורים - חיצוני ופנימי. נבחן את השימוש בתוויות בסעיף שלהלן. בינתיים, אם עניתם "לא" לשאלה האם הקוד הזה יקמפל:
public static void main(String[] args) {
      https://www.google.com/
      System.out.println("Interesting...");
  }
נסה לענות שוב, באמצעות ה-IDE.

לשבור

המפעיל breakמשמש בשני מקרים:
  1. להשלמת כל ענף ביצוע בבלוק מתג-מקרה.
  2. כדי להפריע לביצוע של לולאה.
למפעיל יש שתי צורות: עם סימונים (תווית) ובלי. התחביר עבור שתי הצורות הוא:
break labelName; // Синтаксис оператора с меткой
break; // Синтаксис оператора без метки
בבלוק-מקרה מתג, המפעיל breakמשמש ללא תוויות:
public static void main(String[] args) {
    int dayOfWeekInt = 4;
    String dayOfWeek;
    switch (dayOfWeekInt) {
        case 1:
            dayOfWeek = "Monday";
            break;
        case 2:
            dayOfWeek = "Tuesday";
            break;
        case 3:
            dayOfWeek = "Wednesday";
            break;
        case 4:
            dayOfWeek = "Thursday";
            break;
        case 5:
            dayOfWeek = "Friday";
            break;
        case 6:
            dayOfWeek = "Saturday";
            break;
        case 7:
            dayOfWeek = "Sunday";
            break;
        default:
            dayOfWeek = "Неизвестный день";
            break;
    }

    System.out.println("Сегодня " + dayOfWeek);
}
בלולאות, הצהרה breakמשמשת כדי לקטוע איטרציות נוספות לאחר התקיימות תנאים מסוימים. לעתים קרובות ניתן למצוא את זה כאשר אתה צריך לחזור על מערך או אוסף של אלמנטים ולמצוא בו אלמנט כלשהו שעומד בתנאים הדרושים. הבה נשקול את הדוגמה הזו. יש לנו מערך ואנחנו צריכים לקבוע אם המערך מכיל אלמנטים שליליים:
int a[] = {1,2,234,-123,12,-2,312,0,412,433};
boolean arrayHasNegativeElements = false;

for (int i = 0; i < a.length; i++) {
   if (a[i] < 0) {
       /*
        Как только найдется
        хотя бы один отрицательный элемент,
        мы прервем цикл с помощью
        оператора break, потому что
        мы выяснor то, что нас интересовало,
        и дальнейший перебор элементов не имеет смысла.
        */
       arrayHasNegativeElements = true;
       break;
   }
}
בואו נסתכל על אותה דוגמה עם לולאות שונות. מחזור for-each:
public static void main(String[] args) {
    int a[] = {1,2,234,-123,12,-2,312,0,412,433};
    boolean arrayHasNegativeElements = false;

    for (int number : a) {
        if (number < 0) {
            arrayHasNegativeElements = true;
            break;
        }
    }
}
מחזור while:
public static void main(String[] args) {
    int a[] = {1,2,234,-123,12,-2,312,0,412,433};
    boolean arrayHasNegativeElements = false;

    int counter = 0;
    while (counter < a.length) {
        if (a[counter] < 0) {
            arrayHasNegativeElements = true;
            break;
        }
        counter ++;
    }
}
מחזור do-while:
public static void main(String[] args) {
    int a[] = {1,2,234,-123,12,-2,312,0,412,433};
    boolean arrayHasNegativeElements = false;

    int counter = 0;
    do {
        if (a[counter] < 0) {
            arrayHasNegativeElements = true;
            break;
        }
        counter ++;
    } while (counter < a.length);
}
דוגמה נוספת להצהרה breakבלולאות היא לקטוע לולאה אינסופית כאשר מגיעים לתנאים מסוימים. הנה דוגמה לתוכנית המציגה את השורה שהזין המשתמש עד שהמשתמש יזין את המילה "עצור":
public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    String line;

    while (true) {
        line = scanner.nextLine();
        if ("stop".equals(line)){
            /*
             Прерываем бесконечный цикл,
             при достижении
             определенного условия
             */
            break;
        }
        System.out.println("Пользователь ввел: " + line);
    }
}
בואו נשקול להשתמש באופרטור breakיחד עם תווית. פסיקה עם תווית משמשת במקרים עם מספר מחזורים, יתר על כן, מקוננים אחד בתוך השני. במקרה זה, אחד המחזורים (או כל המחזורים) מסומן בתווית. לאחר מכן, המפעיל, breakיחד עם ציון התווית, קוטע את המחזור הרצוי. הבה נבחן דוגמה שבה עלינו להבין אם יש אלמנט שלילי, אבל לא במערך, אלא במטריצה:
public static void main(String[] args) {
   int[][] a = {
           {1, 2, 3},
           {-412, 12, 0},
           {1223, 474, -54}
   };

   boolean hasNegative = false;

   searchNegative:
       for (int i = 0; i < a.length; i++) {
           for (int j = 0; j < a[i].length; j++) {
               if (a[i][j] < 0) {
                   /*
                       Если использовать break без метки,
                       тогда прервется вложенный цикл for,
                       но внешний продолжит выполнять свои итерации
                       и поиск продолжится.

                       Поэтому мы "помечаем" внешний цикл меткой `searchNegative`
                       и прерываем внешний цикл оператором break совместно с нужной меткой.
                    */
                   hasNegative = true;
                   break searchNegative;
               }
           }
       }
}

הֶמשֵׁכִיוּת

למפעיל continueיש גם שתי צורות - עם ובלי תווית:
continue; // форма оператора без метки
continue labelName; // форма оператора с меткой
בניגוד לאופרטור break, שקוטע את כל האיטרציות הנותרות של הלולאה, האופרטור continueקוטע את האיטרציה הנוכחית וגורם לאיטרציה הבאה להתחיל. מפעילי Jump ב-Java - 2זה יכול להיות שימושי אם אתה צריך לבצע כמה פעולות על אלמנטים העומדים בתנאים מסוימים. נניח שיש לנו מחרוזת ואנו רוצים לספור את מספר המילים שמתחילות באות "m":
public static void main(String[] args) {
    String sentence = "Мама мыла раму";
    String[] words = sentence.split(" ");

    int mWordsCount = 0;

    for (int i = 0; i < words.length; i++) {
        if ( ! words[i].toLowerCase().startsWith("м")) {
            /*
             Если слово не начинается с буквы м,
             то текущая итерация прервется и цикл
             ПРОДОЛЖИТ выполнение со следующей итерации
             */
            continue;
        }

        mWordsCount ++;
    }

    System.out.println("Кол-во слов, начинающихся с буквы М в предложении: " + "[" + sentence + "] = " + mWordsCount);
}
לאחר ביצוע קוד זה יהיה הפלט הבא במסוף:
Кол-во слов, начинающихся с буквы М в предложении: [Мама мыла раму] = 2
האופרטור continueיחד עם התווית משמש גם בעת איטרציה על אלמנטים. בואו נדמיין מטריצה ​​שבה אנחנו צריכים לספור את מספר השורות עם אלמנטים שליליים:
public static void main(String[] args) {
    int[][] a = {
            {1, 23, -1, 23, -12},
            {21, 21, 0, 23, 123, 45},
            {123, 3},
            {123, -5, 4, -3},
            {-1, -2, -3}
    };

    int rowsWithNegativeElementsCount = 0;

    rowsLoop:
    // Проходим по каждой строке
        for (int[] arr : a) {
            for (int number : arr) {
                if (number < 0) {
                    /*
                     Если в текущей строке найдется
                     хотя бы 1 отрицательный элемент,
                     тогда мы увеличим переменную счетчик,
                     и с помощью оператора continue rowsLoop
                     прервем текущую итерацию внешнего цикла и
                     принудительно начнем следующую
                     */
                    rowsWithNegativeElementsCount ++;
                    continue rowsLoop;
                }
            }
        }

    System.out.println("Rows With Negative Elements Count = " + rowsWithNegativeElementsCount);
}
הפלט של קוד זה יהיה:
Rows With Negative Elements Count = 3
ראוי לומר כי המפעילים break, continueוניתן returnלהשתמש בהם בדרכים שונות כדי להשיג את אותה פונקציונליות. אז, אתה יכול לשכתב את הדוגמה האחרונה ולהשתמש continueב break:
public static void main(String[] args) {
    int[][] a = {
            {1, 23, -1, 23, -12},
            {21, 21, 0, 23, 123, 45},
            {123, 3},
            {123, -5, 4, -3},
            {-1, -2, -3}
    };

    int rowsWithNegativeElementsCount = 0;

    for (int[] arr : a) {
        for (int number : arr) {
            if (number < 0) {
                rowsWithNegativeElementsCount ++;
                break;
            }
        }
    }

    System.out.println("Rows With Negative Elements Count = " + rowsWithNegativeElementsCount);
}
ההבדל בין תווית breakלבין continueתווית הוא מה breakשמשלים את האיטרציות של הלולאה שבה היא כתובה. ועם continueתווית, מדלג על האיטרציה הנוכחית של המחזור המסומן בתווית. במצבים מסוימים, אתה יכול להחליף אחד בשני, והכל בפונקציונליות של התוכנית יישאר זהה. נדבר על מה הכי טוב לבחור (ספוילר: קריאת קוד) להלן. breakניתן להחליף את המפעיל לא רק עם continueתווית, אלא גם עם return. רגע לפני זה אתה צריך להעביר את הלולאה המקוננת לשיטה נפרדת:
public static void main(String[] args) {
    int[][] a = {
            {1, 23, -1, 23, -12},
            {21, 21, 0, 23, 123, 45},
            {123, 3},
            {123, -5, 4, -3},
            {-1, -2, -3}
    };

    int rowsWithNegativeElementsCount = 0;

    for (int[] arr : a) {
        if (arrayHasNegativeElements(arr)) {
            rowsWithNegativeElementsCount ++;
        }
    }

    System.out.println("Rows With Negative Elements Count = " + rowsWithNegativeElementsCount);
}

static boolean arrayHasNegativeElements(int[] array) {
    for (int number : array) {
        if (number < 0) {
            return true;
        }
    }

    return false;
}
הרבה דרכים לכתוב את אותו הדבר. איזה מהם לבחור? בתכנות תעשייתי, נושא זה מוכרע על ידי קלות ההבנה של הקוד. ככל שזה כתוב יותר פשוט כך ייטב. ככל שלולאות מקוננות יותר, כך קשה יותר לתפוס את הקוד. במיוחד אם הלולאות מסומנות בסימנים שונים, המשמשים בהפסקות והמשכים ( breakו continue). אם אפשר לא להשתמש בתגיות, עדיף לעשות זאת. אחרת, נסו לכתוב בצורה ברורה ויפה ככל האפשר.

לך ל

בשפות תכנות מסוימות יש אופרטור goto. בדרך כלל זה מפנה מחדש את ביצוע הקוד לחלק כלשהו של התוכנית המסומן בתווית. אבל בג'אווה goto, אפשר לומר, זה כן וזה לא. בוא נבין את זה. רשימת מילות המפתח ב-Java כוללת את המילה goto. עם זאת, הצהרה זו מסומנת כלא בשימוש. העובדה היא שג'יימס גוסלינג, היוצר של שפת ג'אווה, כלל בתחילה תמיכה במפעיל ב-JVM goto. עם זאת, תכונה זו הופסקה מאוחר יותר. אחת הסיבות היא שבלוקים של קוד המכילים את האופרטור gotoלא היו קריאים כמו בלוקים של קוד שביצעו את אותן פונקציות אך ללא goto, אלא עם גישות חלופיות ( break, continue, הצבת בלוק הקוד בשיטות). היו, למעשה, אחרים, כגון:
  • קושי בקריאה והבנת קוד המכיל אופרטורים goto;
  • מסבך אופטימיזציה של קוד עבור המהדר (ולפעמים אפילו בלתי אפשרי);
  • הגדלת הסבירות ליצירת שגיאות עדינות בקוד.
זה לא סוד לרבים שבכמה שפות תכנות המפעיל gotoמתפקד בצורה מוצלחת למדי. עם זאת, מתכנתים נמנעים משימוש בו. אתה יכול לקרוא על הסיבות לכך במאמר אחד על Habré . אבל למה אם כן להשאיר אותו gotoברשימת המילים השמורות? זה פשוט: לעתיד. אם, למשל, משתנים, מתודות או מחלקות נקראים , בקוד Java של מפתחים בכל העולם goto, אם ההצהרה הזו תוחזר בגרסה עתידית של Java, כל הקוד הישן ישבר. כדי להימנע מתרחיש כזה, gotoהוא נשאר ברשימת מילות המפתח של Java, אך אינו נושא פונקציונליות כלשהי. אולי מתישהו gotoהוא יחזור לשורותינו, אבל הסבירות לכך נמוכה.

תוצאות

בדקנו מפעילי קפיצה שונים ב-Java:
  1. return- השלמת השיטה, החזרת ערך מהשיטה.
    • עם ערך החזרה: שיטות המחזירות ערכים;
    • אין ערך החזרה: voidשיטות.
  2. break- הפרעה של מחזורים, בלוקים של מתגים.
    • עם תגיות: מחזורי קינון שונים;
    • ללא תוויות: ענפי מתג של הבלוק; קוטע את הלולאה שבה נקראה.
  3. continue.
    • עם תגיות: מחזורי קינון שונים;
    • ללא תוויות: המשך הלולאה שבה היא נקראה.
  4. goto.
    • נמצא ברשימת מילות המפתח, אך אינו בשימוש.
המסקנה מכל זה פשוטה: עדיף לתת עדיפות לגישות הפשוטות ביותר המקלות את הקוד לקריאה. נסו לא להעמיס את הקוד שלכם בלולאות רב-רמות המקוננות זו בזו עם שפע של סימנים, הפרעות והמשכים.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION