JavaRush /Blogue Java /Random-PT /Operadores de salto em Java

Operadores de salto em Java

Publicado no grupo Random-PT
Olá! Hoje falaremos sobre operadores de salto em Java:
  • return
  • break
  • continue
  • goto
Primeiro, vamos definir o que realmente é. Como você sabe, em uma situação normal, um programa é executado linearmente - de cima para baixo, comando por comando. O fluxo linear de um programa pode ser alterado pelas chamadas estruturas de controle: por exemplo, ramificações ( if) e loops ( for, whileetc.). Além das estruturas de controle, a execução linear de um programa pode ser modificada por instruções de salto. Eles são responsáveis ​​por redirecionar a execução do programa para um local específico, que depende do contexto e da instrução específica. Operadores de salto em Java - 1Vamos dar uma olhada mais de perto em cada um dos quatro operadores.

retornar

É com esse operador que os recém-chegados geralmente se familiarizam primeiro. A instrução returnencerra o método no qual foi chamada e a execução do programa retorna ao local de onde o método foi chamado. Possui returnduas formas:
  1. Termina imediatamente a execução do método.
  2. Finaliza imediatamente a execução do método e retorna algum valor como resultado do método.
A sintaxe para ambos os formulários é:
return;
return value; // где value — некоторое возвращаемое meaning
Os métodos que retornam um valor devem ter pelo menos um operador returncom um valor de retorno que seja garantido para ser chamado e não devem ter um operador returnsem um valor de retorno. Vejamos os exemplos abaixo:
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;
    }
}
Em métodos que não retornam um valor (methods void), é aceitável, mas não obrigatório, ter pelo menos uma instrução returnsem valor de retorno, e nem uma única instrução returncom valor de retorno. Vejamos isso com os exemplos abaixo:
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);
}

rótulos

Antes de examinar os operadores breake continue, gostaria de falar sobre rótulos em Java. Isso é importante porque, em algumas situações, os operadores breake continuesão usados ​​em conjunto com rótulos. Mas primeiro, tente responder à pergunta se este código será compilado:
public static void main(String[] args) {
    https://www.google.com/
    System.out.println("Interesting...");
}
Um rótulo é um trecho de código nomeado. A etiqueta em si não fornece nenhuma funcionalidade. Isto é algo como um marcador no código que o programador pretende usar mais tarde. Um rótulo no código é definido de forma bastante simples - por meio de um nome e dois pontos. Por exemplo:
  • labelName:
  • outerLoop:
  • printing:
  • anyWordYouLike:
E é assim que os rótulos ficam dentro do código 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();
    }
}
A saída do método mainserá a seguinte:
Таблица Умножения
   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
No exemplo acima definePrintName, loop1:e loop2:são rótulos. loop1:e loop2:“marcar” dois ciclos – externo e interno. Veremos como usar rótulos na seção abaixo. Enquanto isso, se você respondeu “não” à pergunta se este código será compilado:
public static void main(String[] args) {
      https://www.google.com/
      System.out.println("Interesting...");
  }
Tente responder novamente, usando o IDE.

quebrar

O operador breaké usado em dois casos:
  1. Para completar qualquer ramificação de execução em um bloco switch-case.
  2. Para interromper a execução de um loop.
A operadora possui dois formulários: com marcação (etiqueta) e sem. A sintaxe para ambos os formulários é:
break labelName; // Синтаксис оператора с меткой
break; // Синтаксис оператора без метки
Em blocos switch-case, o operador breaké usado sem rótulos:
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);
}
Em loops, uma instrução breaké usada para interromper iterações adicionais após certas condições serem atendidas. Muitas vezes, isso pode ser encontrado quando você precisa iterar em uma matriz ou coleção de elementos e encontrar algum elemento que satisfaça as condições necessárias. Vamos considerar este exemplo. Temos um array e precisamos determinar se o array contém elementos negativos:
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;
   }
}
Vejamos o mesmo exemplo com loops diferentes. Ciclo 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;
        }
    }
}
Ciclo 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 ++;
    }
}
Ciclo 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);
}
Outro exemplo de instrução breakem loops é interromper um loop infinito quando certas condições são atingidas. Aqui está um exemplo de programa que exibe a linha inserida pelo usuário até que ele insira a palavra “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);
    }
}
Vamos considerar o uso do operador breakjunto com um rótulo. Uma interrupção com rótulo é utilizada em casos com vários ciclos, aliás, aninhados um dentro do outro. Neste caso, um dos ciclos (ou todos os ciclos) é marcado com uma etiqueta. A seguir, o operador, breakjuntamente com a indicação da etiqueta, interrompe o ciclo desejado. Vamos considerar um exemplo em que precisamos entender se existe um elemento negativo, mas não no array, mas na matriz:
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;
               }
           }
       }
}

continuidade

A operadora continuetambém possui dois formulários - com e sem etiqueta:
continue; // форма оператора без метки
continue labelName; // форма оператора с меткой
Ao contrário do operador break, que interrompe todas as iterações restantes do loop, o operador continueinterrompe a iteração atual e faz com que a próxima seja iniciada. Operadores de salto em Java - 2Isto pode ser útil se você precisar realizar algumas operações em elementos que satisfaçam determinadas condições. Digamos que temos uma string e queremos contar o número de palavras que começam com a letra “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);
}
Após executar este código, haverá a seguinte saída no console:
Кол-во слов, начинающихся с буквы М в предложении: [Мама мыла раму] = 2
O operador continuejunto com o rótulo também é usado ao iterar sobre elementos. Vamos imaginar uma matriz na qual precisamos contar o número de linhas com elementos negativos:
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);
}
A saída deste código será:
Rows With Negative Elements Count = 3
Vale dizer que os operadores break, continuee returnpodem ser utilizados de diversas maneiras para atingir a mesma funcionalidade. Então, você pode reescrever o último exemplo e continueusar 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);
}
A diferença entre breake continuecom um rótulo é o que breakcompleta as iterações do loop em que ele está escrito. E continuecom um rótulo, pula a iteração atual do ciclo marcado com o rótulo. Em algumas situações, você pode substituir um pelo outro, e tudo na funcionalidade do programa permanecerá o mesmo. Falaremos sobre o que é melhor escolher (spoiler: legibilidade do código) abaixo. O operador breakpode ser substituído não apenas por continueum rótulo, mas também por return. Pouco antes disso você precisa mover o loop aninhado para um método separado:
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;
}
Muitas maneiras de escrever a mesma coisa. Qual escolher? Na programação industrial, essa questão é decidida pela facilidade de compreensão do código. Quanto mais simples for escrito, melhor. Quanto mais loops aninhados, mais difícil será perceber o código. Principalmente se os loops estiverem marcados com marcas diferentes, que são usadas em interrupções e continuações ( breake continue). Se for possível não usar tags, é melhor fazê-lo. Caso contrário, tente escrever da forma mais clara e bonita possível.

Vá para

Em algumas linguagens de programação existe um operador goto. Normalmente ele redireciona a execução do código para alguma parte do programa marcada com um rótulo. Mas em Java goto, pode-se dizer, é e não é. Vamos descobrir. A lista de palavras-chave em Java inclui a palavra goto. No entanto, esta declaração está marcada como não usada. O fato é que James Gosling, o criador da linguagem Java, inicialmente incluiu suporte ao operador na JVM goto. No entanto, esse recurso foi posteriormente eliminado. Uma das razões é que os blocos de código contendo o operador gotonão eram tão legíveis quanto os blocos de código que executavam as mesmas funções, mas sem goto, mas com abordagens alternativas ( break,, continuecolocando o bloco de código em métodos). Houve, de fato, outros, como:
  • dificuldade de leitura e compreensão de código que contém operadores goto;
  • complicar a otimização do código para o compilador (e às vezes até impossível);
  • aumentando a probabilidade de criar erros sutis no código.
Não é segredo para muitos que em algumas linguagens de programação o operador gotofunciona com bastante sucesso. No entanto, os programadores evitam usá-lo. Você pode ler sobre as razões para isso em um artigo no Habré . Mas por que então deixá-la gotona lista de palavras reservadas? É simples: para o futuro. Se, por exemplo, variáveis, métodos ou classes forem chamados, no código Java de desenvolvedores em todo o mundo goto, se esta instrução for retornada em uma versão futura do Java, todo o código antigo será quebrado. Para evitar tal cenário, gotoela permanece na lista de palavras-chave Java, mas não possui nenhuma funcionalidade. Talvez um dia gotoele retorne às nossas fileiras, mas a probabilidade de isso acontecer é baixa.

Resultados

Vimos vários operadores de salto em Java:
  1. return— conclusão do método, retornando um valor do método.
    • com valor de retorno: métodos que retornam valores;
    • sem valor de retorno: voidmétodos.
  2. break— interrupção de ciclos, bloqueios de caixas de comutação.
    • com tags: ciclos de vários aninhamentos;
    • sem rótulos: ramificações da caixa de comutação do bloco; interrompendo o loop em que foi chamado.
  3. continue.
    • com tags: ciclos de vários aninhamentos;
    • sem rótulos: continuação do loop em que foi chamado.
  4. goto.
    • está na lista de palavras-chave, mas não é usado.
A conclusão de tudo isso é simples: é melhor dar preferência às abordagens mais simples que facilitam a leitura do código. Tente não sobrecarregar seu código com loops de vários níveis aninhados uns dentro dos outros com uma abundância de marcas, interrupções e continuações.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION