ฟังก์ชันทางเลือกสำหรับคีย์เวิร์ดgotoใน Java คืออะไร?
เนื่องจาก Java ไม่มี goto
ฟังก์ชันทางเลือกสำหรับคีย์เวิร์ดgotoใน Java คืออะไร?
เนื่องจาก Java ไม่มี goto
คำตอบ:
คุณสามารถใช้คำสั่งBREAK ที่มีป้ายกำกับ:
search:
for (i = 0; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length; j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
break search;
}
}
}
อย่างไรก็ตามในโค้ดที่ออกแบบมาอย่างเหมาะสมคุณไม่จำเป็นต้องใช้ฟังก์ชัน GOTO
ไม่มีgoto
แนวคิดใดเทียบเท่าโดยตรงกับแนวคิดใน Java มีโครงสร้างไม่กี่คนที่ช่วยให้คุณสามารถทำบางgoto
สิ่งที่คุณสามารถทำอะไรกับคลาสสิก
break
และcontinue
งบช่วยให้คุณสามารถกระโดดออกจากบล็อกในวงหรือสวิทช์คำสั่งbreak <label>
อนุญาตให้คุณกระโดดออกจากคำสั่งผสมตามอำเภอใจไปยังระดับใดก็ได้ภายในวิธีการที่กำหนด (หรือบล็อกตัวเริ่มต้น)continue <label>
ดำเนินการวนซ้ำรอบนอกถัดไปจากวงในreturn
และแน่นอนมีโครงสร้าง Java เหล่านี้ไม่อนุญาตให้คุณแตกแขนงไปข้างหลังหรือไปยังจุดหนึ่งในโค้ดที่ระดับเดียวกับการซ้อนกันเป็นคำสั่งปัจจุบัน พวกเขาทั้งหมดกระโดดออกจากระดับการซ้อน (ขอบเขต) หนึ่งระดับขึ้นไปและพวกเขาทั้งหมด (นอกเหนือจากcontinue
) กระโดดลงไปข้างล่าง ข้อ จำกัด นี้จะช่วยให้หลีกเลี่ยงการข้ามไป "รหัสปาเก็ตตี้" กลุ่มอาการของโรคอยู่ในตัวเก่าพื้นฐาน FORTRAN และ COBOL รหัส2
1- ส่วนที่แพงที่สุดของข้อยกเว้นคือการสร้างวัตถุข้อยกเว้นและ stacktrace หากคุณจำเป็นต้องใช้การจัดการข้อยกเว้นสำหรับการควบคุมโฟลว์ "ปกติ" จริงๆคุณสามารถจัดสรร / ใช้อ็อบเจ็กต์ข้อยกเว้นล่วงหน้าหรือสร้างคลาสข้อยกเว้นแบบกำหนดเองที่แทนที่fillInStackTrace()
เมธอด ข้อเสียคือprintStackTrace()
วิธีการของข้อยกเว้นจะไม่ให้ข้อมูลที่เป็นประโยชน์แก่คุณ ... หากคุณจำเป็นต้องโทรหาพวกเขา
2 - กลุ่มอาการของ spaghetti code ทำให้เกิดแนวทางการเขียนโปรแกรมแบบมีโครงสร้างซึ่งคุณ จำกัด การใช้โครงสร้างภาษาที่มีอยู่ สิ่งนี้สามารถนำไปใช้กับBASIC , FortranและCOBOLได้ แต่ต้องมีการดูแลและมีระเบียบวินัย การกำจัดทิ้งgoto
ทั้งหมดเป็นวิธีแก้ปัญหาที่ดีกว่าในทางปฏิบัติ หากคุณเก็บไว้เป็นภาษาก็มักจะมีตัวตลกบางคนที่จะใช้ในทางที่ผิด
เพื่อความสนุกสนานนี่คือการใช้งาน GOTO ใน Java
ตัวอย่าง:
1 public class GotoDemo { 2 public static void main(String[] args) { 3 int i = 3; 4 System.out.println(i); 5 i = i - 1; 6 if (i >= 0) { 7 GotoFactory.getSharedInstance().getGoto().go(4); 8 } 9 10 try { 11 System.out.print("Hell"); 12 if (Math.random() > 0) throw new Exception(); 13 System.out.println("World!"); 14 } catch (Exception e) { 15 System.out.print("o "); 16 GotoFactory.getSharedInstance().getGoto().go(13); 17 } 18 } 19 }
เรียกใช้:
$ java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo 3 2 1 0 Hello World!
ต้องเพิ่มคำว่า "ไม่ใช้!" หรือไม่?
Math.random()
สามารถคืนค่า 0 ได้มันควรจะเป็น> =
HellWorld!o World!
ต้องตะลึง #AllBugsAreFeatures
ในขณะที่ผู้แสดงความคิดเห็นและผู้ลงคะแนนบางคนโต้แย้งว่านี่ไม่ใช่gotoแต่ bytecode ที่สร้างขึ้นจากคำสั่ง Java ด้านล่างนี้แสดงให้เห็นว่าข้อความเหล่านี้แสดงความหมายแบบgotoจริงๆ
โดยเฉพาะอย่างยิ่งdo {...} while(true);
ลูปในตัวอย่างที่สองได้รับการปรับให้เหมาะสมโดยคอมไพเลอร์ Java เพื่อไม่ให้ประเมินเงื่อนไขการวนซ้ำ
label: {
// do stuff
if (check) break label;
// do more stuff
}
ใน bytecode:
2 iload_1 [check]
3 ifeq 6 // Jumping forward
6 ..
label: do {
// do stuff
if (check) continue label;
// do more stuff
break label;
} while(true);
ใน bytecode:
2 iload_1 [check]
3 ifeq 9
6 goto 2 // Jumping backward
9 ..
continue label
กระโดดถอยหลัง
// do stuff
และ// do more stuff
เป็นข้อความที่น่าสนใจcontinue label
"มีผล"ของการกระโดดถอยหลัง (เนื่องจากwhile(true)
คำแถลงแน่นอน) ฉันไม่รู้ว่านี่เป็นคำถามที่แม่นยำ แต่ ...
while(true)
ถูกแปลโดยรวบรวมเป็นgoto
ดำเนินการ bytecode ในฐานะที่true
เป็นตัวอักษรคงที่คอมไพเลอร์สามารถทำเพิ่มประสิทธิภาพนี้และไม่ได้มีการประเมินอะไร ตัวอย่างของฉันคือโกโตกระโดดถอยหลัง ...
หากคุณต้องการบางอย่างเช่นประโยค goto คุณสามารถลองทำลายบล็อกที่มีชื่อได้ตลอดเวลา
คุณต้องอยู่ในขอบเขตของบล็อกเพื่อทำลายป้ายกำกับ:
namedBlock: {
if (j==2) {
// this will take you to the label above
break namedBlock;
}
}
ฉันจะไม่บรรยายคุณว่าทำไมคุณควรหลีกเลี่ยง goto - ฉันถือว่าคุณรู้คำตอบแล้ว
public class TestLabel {
enum Label{LABEL1, LABEL2, LABEL3, LABEL4}
/**
* @param args
*/
public static void main(String[] args) {
Label label = Label.LABEL1;
while(true) {
switch(label){
case LABEL1:
print(label);
case LABEL2:
print(label);
label = Label.LABEL4;
continue;
case LABEL3:
print(label);
label = Label.LABEL1;
break;
case LABEL4:
print(label);
label = Label.LABEL3;
continue;
}
break;
}
}
public final static void print(Label label){
System.out.println(label);
}
StephenC เขียน:
มีโครงสร้างสองแบบที่ช่วยให้คุณทำบางสิ่งที่คุณสามารถทำได้ด้วย goto แบบคลาสสิก
อีกหนึ่ง...
Matt Wolfe เขียน:
คนมักพูดถึงว่าไม่เคยใช้ goto แต่ฉันคิดว่ามีกรณีการใช้งานในโลกแห่งความเป็นจริงที่ดีจริงๆซึ่งเป็นที่รู้จักและใช้กันดีอยู่แล้ว .. นั่นคือต้องแน่ใจว่าได้รันโค้ดก่อนที่จะกลับมาจากฟังก์ชัน .. ล็อคหรืออะไรไม่ได้ แต่ในกรณีของฉันฉันชอบที่จะสามารถข้ามไปยังจุดพักได้ก่อนกลับเพื่อที่ฉันจะได้ทำการล้างข้อมูลที่จำเป็น
try {
// do stuff
return result; // or break, etc.
}
finally {
// clean up before actually returning, even though the order looks wrong.
}
http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html
สุดท้ายบล็อกจะดำเนินการเสมอเมื่อบล็อกการลองออก สิ่งนี้ช่วยให้มั่นใจได้ว่าสุดท้ายจะดำเนินการบล็อกแม้ว่าจะมีข้อยกเว้นที่ไม่คาดคิดเกิดขึ้นก็ตาม แต่ในที่สุดก็มีประโยชน์สำหรับการจัดการข้อยกเว้น - ช่วยให้โปรแกรมเมอร์หลีกเลี่ยงการข้ามรหัสโดยไม่ได้ตั้งใจโดยการส่งคืนดำเนินการต่อหรือทำลาย การใส่รหัสล้างข้อมูลลงในบล็อกสุดท้ายเป็นแนวทางปฏิบัติที่ดีแม้ว่าจะไม่มีข้อยกเว้นใด ๆ ก็ตาม
คำถามสัมภาษณ์โง่ ๆ ที่เกี่ยวข้องในที่สุดก็คือ: หากคุณกลับมาจากการลอง {} บล็อก แต่มีผลตอบแทนในที่สุด {} ด้วยเช่นกันค่าใดจะถูกส่งกลับ
return
ในfinally
บล็อกเป็นความคิดที่ไม่ดี (และแม้ว่าความรู้จะไม่จำเป็นอย่างยิ่ง แต่ฉันก็กังวลกับโปรแกรมเมอร์ที่ไม่มีความอยากรู้อยากเห็น ... )
ง่ายที่สุดคือ:
int label = 0;
loop:while(true) {
switch(state) {
case 0:
// Some code
state = 5;
break;
case 2:
// Some code
state = 4;
break;
...
default:
break loop;
}
}
ลองใช้รหัสด้านล่าง มันใช้ได้กับฉัน
for (int iTaksa = 1; iTaksa <=8; iTaksa++) { // 'Count 8 Loop is 8 Taksa
strTaksaStringStar[iCountTaksa] = strTaksaStringCount[iTaksa];
LabelEndTaksa_Exit : {
if (iCountTaksa == 1) { //If count is 6 then next it's 2
iCountTaksa = 2;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 2) { //If count is 2 then next it's 3
iCountTaksa = 3;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 3) { //If count is 3 then next it's 4
iCountTaksa = 4;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 4) { //If count is 4 then next it's 7
iCountTaksa = 7;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 7) { //If count is 7 then next it's 5
iCountTaksa = 5;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 5) { //If count is 5 then next it's 8
iCountTaksa = 8;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 8) { //If count is 8 then next it's 6
iCountTaksa = 6;
break LabelEndTaksa_Exit;
}
if (iCountTaksa == 6) { //If count is 6 then loop 1 as 1 2 3 4 7 5 8 6 --> 1
iCountTaksa = 1;
break LabelEndTaksa_Exit;
}
} //LabelEndTaksa_Exit : {
} // "for (int iTaksa = 1; iTaksa <=8; iTaksa++) {"
Java ไม่มีgoto
เนื่องจากทำให้โค้ดไม่มีโครงสร้างและอ่านไม่ชัดเจน อย่างไรก็ตามคุณสามารถใช้break
และcontinue
เป็นอารยะรูปแบบของการข้ามไปได้โดยไม่มีปัญหาของมัน
ahead: {
System.out.println("Before break");
break ahead;
System.out.println("After Break"); // This won't execute
}
// After a line break ahead, the code flow starts from here, after the ahead block
System.out.println("After ahead");
เอาท์พุต :
Before Break
After ahead
before: {
System.out.println("Continue");
continue before;
}
ซึ่งจะส่งผลในวง จำกัดเป็นทุกครั้งที่สายcontinue before
จะถูกดำเนินการไหลของรหัสจะเริ่มต้นอีกครั้งจากbefore
goto
มีอยู่ใน Java ได้หรือไม่? ฉันคิดว่าในนั้นเป็นปัญหาที่สำคัญกว่า