สวัสดี! วันนี้เราจะพูดถึง Jump Operators ใน Java:
เรามาดูรายละเอียดของโอเปอเรเตอร์ทั้งสี่รายกันดีกว่า
สิ่งนี้มีประโยชน์หากคุณต้องการดำเนินการบางอย่างกับองค์ประกอบที่ตรงตามเงื่อนไขบางประการ สมมติว่าเรามีสตริงและเราต้องการนับจำนวนคำที่ขึ้นต้นด้วยตัวอักษร "m":
return
break
continue
goto
if
) และลูป ( for
, while
ฯลฯ) นอกเหนือจากโครงสร้างการควบคุมแล้ว การดำเนินการเชิงเส้นของโปรแกรมยังสามารถแก้ไขได้ด้วยคำสั่ง Jump พวกเขามีหน้าที่รับผิดชอบในการเปลี่ยนเส้นทางการทำงานของโปรแกรมไปยังตำแหน่งเฉพาะ ซึ่งขึ้นอยู่กับบริบทและคำสั่งเฉพาะ กลับ
เป็นผู้ดำเนินการรายนี้ที่ผู้มาใหม่มักคุ้นเคยเป็นอันดับแรก คำสั่งreturn
ยุติวิธีการที่ถูกเรียก และการทำงานของโปรแกรมจะกลับไปยังตำแหน่งที่เรียกใช้เมธอดนั้น มันreturn
มีสองรูปแบบ:
- สิ้นสุดการดำเนินการของวิธีการทันที
- สิ้นสุดการดำเนินการของเมธอดทันทีและส่งกลับค่าบางส่วนซึ่งเป็นผลลัพธ์ของเมธอด
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);
}
ฉลาก
ก่อนที่จะดู ตัวดำเนินการbreak
and continue
ฉันอยากจะพูดถึงป้ายกำกับใน Java ก่อน นี่เป็นสิ่งสำคัญเนื่องจากในบางสถานการณ์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
ถูกใช้ในสองกรณี:
- เพื่อดำเนินการสาขาการดำเนินการใด ๆ ในบล็อกสวิตช์เคสให้เสร็จสมบูรณ์
- เพื่อขัดจังหวะการทำงานของลูป
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
จะขัดจังหวะการวนซ้ำปัจจุบันและทำให้การวนซ้ำครั้งถัดไปเริ่มต้นขึ้น 
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
เตอร์ โดยทั่วไปแล้วจะเปลี่ยนเส้นทางการเรียกใช้โค้ดไปยังบางส่วนของโปรแกรมที่มีป้ายกำกับ แต่ใน Java goto
อาจมีคนบอกว่ามันเป็นและไม่ใช่ ลองคิดดูสิ รายการคำหลักใน Javaมีคำว่าgoto
. อย่างไรก็ตาม ข้อความนี้ถูกทำเครื่องหมายว่าไม่ได้ใช้ ความจริงก็คือ James Gosling ผู้สร้างภาษา Java ได้รวมการสนับสนุนโอเปอเรเตอร์ไว้ใน JVM ในตอนgoto
แรก อย่างไรก็ตาม คุณลักษณะนี้ถูกตัดออกในภายหลัง สาเหตุหนึ่งก็คือ บล็อกของโค้ดที่มีโอเปอเรเตอร์goto
ไม่สามารถอ่านได้เท่ากับบล็อกของโค้ดที่ทำหน้าที่เดียวกันแต่ไม่มีgoto
แต่ใช้วิธีอื่น ( break
, continue
วางบล็อกโค้ดในวิธีการ) จริงๆ แล้วยังมีคนอื่นๆ อีก เช่น:
goto
ความยากในการอ่านและทำความ เข้าใจโค้ดที่มีตัวดำเนินการ- การเพิ่มประสิทธิภาพโค้ดที่ซับซ้อนสำหรับคอมไพเลอร์ (และบางครั้งก็เป็นไปไม่ได้ด้วยซ้ำ)
- เพิ่มโอกาสในการสร้างข้อผิดพลาดเล็กๆ น้อยๆ ในโค้ด
goto
การทำงานได้ค่อนข้างสำเร็จ อย่างไรก็ตามโปรแกรมเมอร์หลีกเลี่ยงการใช้มัน คุณสามารถอ่านเหตุผลนี้ได้ในบทความเรื่องHabré แต่ทำไมถึงทิ้งมันไว้goto
ในรายการคำสงวนล่ะ? ง่ายมาก: เพื่ออนาคต ตัวอย่างเช่น หากตัวแปร วิธีการ หรือคลาสถูกเรียก ในโค้ด Java ของนักพัฒนาทั่วโลกgoto
หากคำสั่งนี้ถูกส่งคืนใน Java เวอร์ชันอนาคต โค้ดเก่าทั้งหมดจะใช้งานไม่ได้ เพื่อหลีกเลี่ยงสถานการณ์ดังกล่าว คำสำคัญgoto
จะยังคงอยู่ในรายการคีย์เวิร์ด Java แต่ไม่มีฟังก์ชันการทำงานใดๆ บางทีสักวันหนึ่งgoto
เขาจะกลับคืนสู่ตำแหน่งของเรา แต่โอกาสที่จะเป็นเช่นนั้นมีน้อย
ผลลัพธ์
เราได้ดูตัวดำเนินการกระโดดต่างๆ ใน Java:return
— เสร็จสิ้นเมธอด โดยส่งคืนค่าจากเมธอด- ด้วยค่าส่งคืน: วิธีการที่ส่งคืนค่า;
- ไม่มีค่าส่งคืน:
void
วิธีการ
break
- การหยุดชะงักของวงจร บล็อกเคสสวิตช์- มีแท็ก: วงจรของการทำรังต่างๆ
- ไม่มีป้ายกำกับ: สาขาสวิตช์เคสของบล็อก; ขัดจังหวะวงที่มันถูกเรียก
continue
.- มีแท็ก: วงจรของการทำรังต่างๆ
- ไม่มีป้ายกำกับ: ความต่อเนื่องของลูปที่ถูกเรียก
goto
.- อยู่ในรายการคำหลัก แต่ไม่ได้ใช้
GO TO FULL VERSION