JavaRush /Java Blog /Random-TW /Java 中的跳躍運算符

Java 中的跳躍運算符

在 Random-TW 群組發布
你好!今天我們來談談Java中的跳躍運算子:
  • return
  • break
  • continue
  • goto
首先,讓我們定義它實際上是什麼。如您所知,在正常情況下,程式是線性執行的 - 從上到下,逐條命令。程式的線性流程可以透過所謂的控制結構來改變:例如,分支(if)和循環(forwhile)。除了控制結構之外,程式的線性執行還可以透過跳躍語句來修改。它們負責將程式執行重定向到特定位置,這取決於上下文和特定語句。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;
    }
}
在不傳回值的方法 (methods 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);
}

標籤

在討論breakand運算子之前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
在上面的範例中definePrintNameloop1:loop2:是標籤。 loop1:loop2:「標記」兩個週期—外部和內部。我們將在下面的部分中討論如何使用標籤。同時,如果您對該程式碼是否可以編譯的問題回答“否”:
public static void main(String[] args) {
      https://www.google.com/
      System.out.println("Interesting...");
  }
嘗試使用 IDE 再次回答該問題。

休息

此運算符break在兩種情況下使用:
  1. 完成 switch-case 區塊中的任何執行分支。
  2. 中斷循環的執行。
操作符有兩種形式:帶標記(標籤)和不帶標記。兩種形式的語法都是:
break labelName; // Синтаксис оператора с меткой
break; // Синтаксис оператора без метки
break在 switch-case 區塊中,使用的 運算子不帶標籤:
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是當滿足某些條件時中斷無限迴圈。下面是一個程式範例,它顯示使用者輸入的行,直到使用者輸入單字「stop」:
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會中斷當前迭代並導致下一個迭代開始。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,continuereturn可以透過不同的方式使用來實現相同的功能。因此,您可以重寫最後一個範例並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;
}
寫同樣的東西有很多種方法。選擇哪一個?在工業程式設計中,這個問題是由程式碼的難易度決定的。寫越簡單越好。嵌套循環越多,感知程式碼就越困難。特別是如果循環標有不同的標記,這些標記用於中斷和繼續(breakcontinue)。如果可以不使用標籤,最好還是使用。否則,盡量寫得清楚、漂亮。

在某些程式語言中存在運算符goto。通常,它將程式碼執行重定向到標有標籤的程式的某個部分。但在 Java 中goto,有人可能會說,它是,但又不是。讓我們弄清楚一下。 Java 中的關鍵字清單包括單字goto。然而,該語句被標記為未使用。事實上,Java 語言的創建者 James Gosling 最初在 JVM 中包含了對運算子的支援goto。不過這個功能後來被刪掉了。原因之一是包含運算子的程式碼區塊的goto可讀性不如執行相同功能但沒有goto,但採用替代方法(breakcontinue,將程式碼區塊放置在方法中)的程式碼區塊。事實上,還有其他一些,例如:
  • 難以閱讀和理解包含運算符的程式碼goto
  • 使編譯器的程式碼最佳化變得複雜(有時甚至是不可能的);
  • 增加在程式碼中產生細微錯誤的可能性。
對許多人來說,在某些程式語言中,運算子的goto功能相當成功,這已不是什麼秘密。然而,程式設計師避免使用它。您可以在Habré 的一篇文章中了解原因。但為什麼要把它留goto在保留字清單中呢?很簡單:為了未來。例如,如果在世界各地開發人員的 Java 程式碼中呼叫變數、方法或類goto,如果在 Java 的未來版本中傳回此語句,則所有舊程式碼都會崩潰。為了避免這種情況,goto它保留在 Java 關鍵字清單中,但不帶有任何功能。也許有一天goto他會回到我們的隊伍中,但這種可能性很低。

結果

我們已經研究了 Java 中的各種跳躍運算子:
  1. return— 方法完成,從方法傳回一個值。
    • 有回傳值:有傳回值的方法;
    • 無回傳值: void方法。
  2. break— 循環中斷、開關盒塊。
    • 帶標籤:各種嵌套的循環;
    • 沒有標籤:區塊的 switch-case 分支;中斷呼叫它的循環。
  3. continue
    • 帶標籤:各種嵌套的循環;
    • 沒有標籤:呼叫它的循環的繼續。
  4. goto
    • 位於關鍵字清單中,但未使用。
所有這一切的結論很簡單:最好優先選擇最簡單的方法,讓程式碼更易於閱讀。盡量不要使用具有大量標記、中斷和延續的相互嵌套的多層循環來使程式碼過載。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION