JavaRush /Java Blog /Random-JA /Java のジャンプ演算子

Java のジャンプ演算子

Random-JA グループに公開済み
こんにちは!今日は Java のジャンプ演算子について説明します。
  • return
  • break
  • continue
  • goto
まず、それが実際に何であるかを定義しましょう。ご存知のとおり、通常の状況では、プログラムは上から下へ、コマンドごとに直線的に実行されます。プログラムの直線的な流れは、いわゆる制御構造、たとえば分岐 ( if) やループ (forなどwhile) によって変更できます。制御構造に加えて、プログラムの線形実行はジャンプ ステートメントによって変更できます。これらは、コンテキストと特定のステートメントに応じて、プログラムの実行を特定の場所にリダイレクトする役割を果たします。Java のジャンプ演算子 - 14 つの演算子をそれぞれ詳しく見てみましょう。

戻る

初心者が最初に慣れるのは、この演算子です。このステートメントはreturn、それが呼び出されたメソッドを終了し、プログラムの実行はメソッドが呼び出された場所に戻ります。これにはreturn2 つの形式があります。
  1. メソッドの実行を直ちに終了します。
  2. メソッドの実行を直ちに終了し、メソッドの結果として何らかの値を返します。
両方の形式の構文は次のとおりです。
return;
return value; // где value — некоторое возвращаемое meaning
return値を返すメソッドには、呼び出されることが保証されている戻り値を持つ 演算子が少なくとも 1 つ必要であり、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) では、戻り値のないステートメントが少なくとも 1 つあり、戻り値のあるステートメントが 1 つもvoid存在しないことが許容されますが、必須ではありません。以下の例でこれを見てみましょう。 returnreturn
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
上の例ではdefinePrintNameloop1:と はloop2:ラベルです。 loop1:そして、loop2:外部と内部の 2 つのサイクルを「マーク」します。以下のセクションでラベルの使用について見ていきます。それまでの間、このコードがコンパイルされるかどうかの質問に「いいえ」と答えた場合は、次のようになります。
public static void main(String[] args) {
      https://www.google.com/
      System.out.println("Interesting...");
  }
IDE を使用して、もう一度回答してみてください。

壊す

演算子はbreak次の 2 つの場合に使用されます。
  1. switch-case ブロック内の実行分岐を完了するため。
  2. ループの実行を中断します。
オペレータには、マーキング (ラベル) ありとなしの 2 つの形式があります。両方の形式の構文は次のとおりです。
break labelName; // Синтаксис оператора с меткой
break; // Синтаксис оператора без метки
switch-case ブロックでは、演算子は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特定の条件が満たされたときに無限ループを中断することです。ユーザーが「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演算子をラベルと一緒に 使用することを考えてみましょう。ラベル付き割り込みは、複数のサイクルがあり、さらにサイクルがサイクル内にネストされている場合に使用されます。この場合、サイクルの 1 つ (またはすべてのサイクル) がラベルでマークされます。次に、オペレータは、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は、ラベル付きとラベルなしの 2 つの形式もあります。
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とラベル付き の違いは、それが書き込まれるループの反復を完了するものです。ラベルを使用すると、そのラベルでマークされたサイクルの現在の反復をスキップします。場合によっては、一方を他方に置き換えても、プログラムの機能はすべて同じままになります。何を選択するのが最適か (ネタバレ: コードの可読性) については以下で説明します。演算子はラベルだけでなく、 にも置き換えることができます。この直前に、ネストされたループを別のメソッドに移動する必要があります。 continuebreakcontinuebreakcontinuereturn
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。ただし、この機能は後に削除されました。理由の 1 つは、演算子を含むコード ブロックが、goto同じ機能を実行するが、 を使用せずgoto、別のアプローチ ( breakcontinue、メソッド内にコード ブロックを配置する) を使用して実行するコード ブロックほど読みにくくなったためです。実際には他にも次のようなものがありました。
  • 演算子を含むコードを読んで理解するのが難しいgoto
  • コンパイラのコードの最適化が複雑になる(場合によっては不可能になることもあります)。
  • コード内に微妙なエラーが発生する可能性が高くなります。
一部のプログラミング言語では、演算子が非常にうまく機能することは多くの人にとって秘密ではありませんgoto。ただし、プログラマーはそれを使用することを避けます。この理由については、Habré に関する 1 つの記事で読むことができます。しかし、なぜそれをgoto予約語のリストに残しておくのでしょうか? それは簡単です。未来のために。たとえば、世界中の開発者の Java コードで変数、メソッド、またはクラスが呼び出された場合goto、このステートメントが Java の将来のバージョンで返されると、古いコードはすべて壊れてしまいます。このようなシナリオを回避するために、gotoJava キーワードのリストには残りますが、機能はありません。おそらくいつかgoto彼は私たちの隊列に戻るでしょうが、その可能性は低いです。

結果

Java のさまざまなジャンプ演算子を調べてきました。
  1. return— メソッドの完了。メソッドから値を返します。
    • 戻り値付き: 値を返すメソッド。
    • 戻り値なし: voidメソッド。
  2. break— サイクルの中断、スイッチケースブロック。
    • タグ付き: さまざまなネストのサイクル。
    • ラベルなし: ブロックのスイッチケース分岐。呼び出されたループを中断します。
  3. continue
    • タグ付き: さまざまなネストのサイクル。
    • ラベルなし: 呼び出されたループの継続。
  4. goto
    • はキーワードのリストにありますが、使用されていません。
これらすべてからの結論は単純です。コードを読みやすくする最も単純なアプローチを優先する方がよいということです。大量のマーク、中断、継続を含む複数レベルのループが相互にネストされてコードが過負荷にならないようにしてください。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION