JavaRush /وبلاگ جاوا /Random-FA /Jump Operators در جاوا

Jump Operators در جاوا

در گروه منتشر شد
سلام! امروز در مورد عملگرهای پرش در جاوا صحبت خواهیم کرد:
  • return
  • break
  • continue
  • goto
ابتدا اجازه دهید تعریف کنیم که در واقع چیست. همانطور که می دانید، در یک وضعیت عادی، یک برنامه به صورت خطی اجرا می شود - از بالا به پایین، دستور با دستور. جریان خطی یک برنامه را می توان با ساختارهای به اصطلاح کنترلی تغییر داد: به عنوان مثال، شاخه ها ( if) و حلقه ها ( forو whileغیره). علاوه بر ساختارهای کنترلی، اجرای خطی یک برنامه را می توان با دستورات پرش تغییر داد. آنها مسئول هدایت مجدد اجرای برنامه به یک مکان خاص هستند که بستگی به زمینه و عبارت خاص دارد. Jump Operators در جاوا - 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، می‌خواهم در مورد برچسب‌ها در جاوا صحبت کنم. این مهم است زیرا در برخی شرایط، breakعملگرها continueهمراه با برچسب ها استفاده می شوند. اما ابتدا سعی کنید به این سوال پاسخ دهید که آیا این کد کامپایل می شود:
public static void main(String[] args) {
    https://www.google.com/
    System.out.println("Interesting...");
}
برچسب یک قطعه کد نامگذاری شده است. خود برچسب هیچ عملکردی را ارائه نمی دهد. این چیزی شبیه یک نشانک در کد است که برنامه نویس قصد دارد بعداً از آن استفاده کند. یک برچسب در کد کاملاً ساده تعریف می شود - از طریق یک نام و یک دو نقطه. مثلا:
  • labelName:
  • outerLoop:
  • printing:
  • anyWordYouLike:
و این چیزی است که برچسب ها در داخل کد جاوا به نظر می رسند:
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در حلقه ها قطع کردن یک حلقه نامتناهی در صورت تحقق شرایط خاص است. در اینجا نمونه ای از برنامه ای است که خط وارد شده توسط کاربر را تا زمانی که کاربر کلمه "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تکرار فعلی را قطع می کند و باعث می شود که تکرار بعدی شروع شود. Jump Operators در جاوا - 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و با آن چیزی است که تکرارهای حلقه ای را که در آن نوشته شده است کامل می کند. و با یک برچسب، از تکرار فعلی چرخه مشخص شده با برچسب صرفنظر می کند. در برخی شرایط، می توانید یکی را با دیگری جایگزین کنید، و همه چیز در عملکرد برنامه ثابت می ماند. ما در مورد بهترین انتخاب (اسپویلر: خوانایی کد) در زیر صحبت خواهیم کرد. اپراتور را می توان نه تنها با یک برچسب، بلکه با . درست قبل از این، باید حلقه تودرتو را به یک روش جداگانه منتقل کنید: 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;
}
راه های زیادی برای نوشتن یک چیز. کدام را انتخاب کنیم؟ در برنامه نویسی صنعتی، این موضوع با سهولت درک کد حل می شود. هر چه ساده تر نوشته شود بهتر است. هرچه حلقه های تو در تو بیشتر باشد، درک کد دشوارتر می شود. به خصوص اگر حلقه ها با برچسب های مختلفی مشخص شده باشند که در وقفه ها و ادامه ها ( breakو continue) استفاده می شود. اگر امکان عدم استفاده از تگ وجود دارد، بهتر است این کار را انجام دهید. در غیر این صورت سعی کنید تا حد امکان واضح و زیبا بنویسید.

رفتن به

در برخی از زبان های برنامه نویسی یک عملگر وجود دارد goto. به طور معمول اجرای کد را به بخشی از برنامه که با برچسب مشخص شده است هدایت می کند. اما در جاوا goto، می توان گفت، این است و نیست. بیایید آن را بفهمیم. لیست کلمات کلیدی در جاوا شامل کلمه goto. با این حال، این عبارت به عنوان استفاده نشده علامت گذاری شده است. واقعیت این است که جیمز گاسلینگ، خالق زبان جاوا، در ابتدا پشتیبانی از اپراتور را در JVM گنجاند goto. با این حال، این ویژگی بعدا قطع شد. یکی از دلایل این است که بلوک‌های کد حاوی عملگر gotoبه اندازه بلوک‌های کدی که عملکردهای مشابهی را انجام می‌دهند اما بدون goto، اما با رویکردهای جایگزین ( break، continueقرار دادن بلوک کد در روش‌ها) قابل خواندن نیستند. در واقع موارد دیگری نیز وجود داشت، مانند:
  • مشکل در خواندن و درک کدهای حاوی عملگرها goto.
  • پیچیده بهینه سازی کد برای کامپایلر (و گاهی اوقات حتی غیرممکن)؛
  • افزایش احتمال ایجاد خطاهای ظریف در کد.
برای بسیاری راز نیست که در برخی از زبان های برنامه نویسی اپراتور gotoکاملاً موفقیت آمیز عمل می کند. با این حال، برنامه نویسان از استفاده از آن اجتناب می کنند. دلایل این امر را می توانید در یک مقاله در Habré بخوانید . اما چرا آن را gotoدر لیست کلمات رزرو شده رها کنید؟ ساده است: برای آینده. برای مثال، اگر متغیرها، متدها یا کلاس‌ها در کد جاوای توسعه‌دهندگان در سراسر جهان نامیده شوند goto، اگر این عبارت در نسخه بعدی جاوا برگردانده شود، همه کدهای قدیمی خراب می‌شوند. برای جلوگیری از چنین سناریویی، gotoدر لیست کلمات کلیدی جاوا باقی می ماند، اما هیچ عملکردی ندارد. شاید روزی gotoاو به جمع ما بازگردد، اما احتمال آن کم است.

نتایج

ما به عملگرهای مختلف پرش در جاوا نگاه کرده ایم:
  1. return- تکمیل متد، برگرداندن مقداری از متد.
    • با مقدار بازگشتی: روش هایی که مقادیر را برمی گرداند.
    • بدون مقدار بازگشتی: voidروش ها.
  2. break- قطع چرخه ها، بلوک های سوئیچ.
    • با برچسب ها: چرخه های مختلف تودرتو.
    • بدون برچسب: شاخه های جعبه سوئیچ بلوک. قطع کردن حلقه ای که در آن فراخوانی شده است.
  3. continue.
    • با برچسب ها: چرخه های مختلف تودرتو.
    • بدون برچسب: ادامه حلقه ای که در آن فراخوانی شده است.
  4. goto.
    • در لیست کلمات کلیدی قرار دارد، اما استفاده نمی شود.
نتیجه گیری از همه اینها ساده است: بهتر است به ساده ترین رویکردهایی که خواندن کد را آسان تر می کند ترجیح دهید. سعی کنید کد خود را با حلقه های چند سطحی که در داخل یکدیگر قرار گرفته اند با تعداد زیادی علامت، وقفه و ادامه بارگذاری نکنید.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION