ไม่มีคำสั่ง return ในคอมไพล์ที่ไม่ใช่ช่องว่าง


189

ฉันพบสถานการณ์ที่ไม่มีวิธีการที่เป็นโมฆะไม่มีคำสั่งการส่งคืนและรหัสยังคงรวบรวม ฉันรู้ว่างบหลังจากห่วงขณะที่ไม่สามารถเข้าถึงได้ (รหัสตาย) และจะไม่ถูกดำเนินการ แต่ทำไมคอมไพเลอร์ถึงไม่เตือนเรื่องการคืนบางอย่าง หรือทำไมภาษาถึงยอมให้เรามีวิธีที่ไม่เป็นโมฆะที่มีการวนซ้ำไม่สิ้นสุดและไม่ส่งคืนอะไรเลย?

public int doNotReturnAnything() {
    while(true) {
        //do something
    }
    //no return statement
}

ถ้าฉันเพิ่มคำสั่ง break (แม้แต่เงื่อนไขที่มีเงื่อนไข) ใน while loop คอมไพเลอร์จะบ่นถึงข้อผิดพลาดที่น่าอับอาย: Method does not return a valueใน Eclipse และNot all code paths return a valueใน Visual Studio

public int doNotReturnAnything() {
    while(true) {
        if(mustReturn) break;
        //do something
    }
    //no return statement
}

สิ่งนี้เป็นจริงทั้ง Java และ C #


3
เป็นคำถามที่ดี ฉันสนใจเหตุผลนี้
Erik Schierboom

18
การเดา: มันเป็นลูปไม่สิ้นสุดดังนั้นโฟลว์การควบคุมการส่งคืนจึงไม่เกี่ยวข้อง?
Lews Therin

5
"ทำไมภาษาจะอนุญาตให้เรามีวิธีการที่ไม่เป็นโมฆะมีวนรอบไม่สิ้นสุดและไม่กลับอะไร?" <- ในขณะที่โง่ดูเหมือนคำถามอาจกลับรายการได้: ทำไมจึงไม่อนุญาตให้ทำเช่นนี้ นี่คือรหัสที่แท้จริงใช่ไหม?
fge

3
สำหรับ Java คุณสามารถหาคำอธิบายที่ดีในคำตอบนี้
Keppil

4
เหมือนที่คนอื่น ๆ อธิบายนั่นเป็นเพราะคอมไพเลอร์ฉลาดพอที่จะรู้ว่าลูปนั้นไม่มีที่สิ้นสุด โปรดทราบว่าคอมไพเลอร์ไม่เพียง แต่อนุญาตให้ส่งคืนหายไปมันบังคับใช้เพราะรู้อะไรหลังจากลูปเข้าไม่ถึง อย่างน้อยใน Netbeans มันจะบ่นอย่างแท้จริงunreachable statementหากมีอะไรหลังจากลูป
Supr

คำตอบ:


240

ทำไมภาษาที่ทำให้เรามีวิธีการที่ไม่เป็นโมฆะมีวนรอบไม่สิ้นสุดและไม่กลับอะไร?

กฎสำหรับเมธอดที่ไม่เป็นโมฆะคือทุกพา ธ โค้ดที่ส่งคืนต้องส่งคืนค่าและกฎนั้นเป็นที่พอใจในโปรแกรมของคุณ: ศูนย์ไม่มีพา ธ โค้ดที่ไม่มีศูนย์ที่ส่งคืนจะส่งคืนค่า กฎไม่ใช่ "ทุกวิธีที่ไม่ใช่โมฆะต้องมีเส้นทางรหัสที่ส่งกลับ"

สิ่งนี้ทำให้คุณสามารถเขียนวิธีการสตับ:

IEnumerator IEnumerable.GetEnumerator() 
{ 
    throw new NotImplementedException(); 
}

นั่นเป็นวิธีที่ไม่เป็นโมฆะ มันมีเป็นวิธีการที่ไม่เป็นโมฆะเพื่อตอบสนองอินเตอร์เฟซ แต่ดูเหมือนว่าโง่ที่จะทำให้การดำเนินการนี้ผิดกฎหมายเพราะไม่ได้คืนสิ่งใด

วิธีการของคุณมีจุดสิ้นสุดที่ไม่สามารถเข้าถึงได้เพราะgoto(โปรดจำไว้ว่า a while(true)เป็นวิธีที่น่าพอใจมากกว่าในการเขียนgoto) แทนที่จะเป็นthrow(ซึ่งเป็นรูปแบบอื่นgoto) ไม่เกี่ยวข้อง

ทำไมคอมไพเลอร์ถึงไม่เตือนเรื่องการคืนบางอย่าง

เพราะคอมไพเลอร์ไม่มีหลักฐานที่ดีว่ารหัสผิด ใครบางคนเขียนwhile(true)และมันดูเหมือนว่าคนที่ไม่ว่ารู้ว่าสิ่งที่พวกเขากำลังทำ

ฉันจะอ่านเพิ่มเติมเกี่ยวกับการวิเคราะห์การเข้าถึงได้ใน C # ได้ที่ไหน

ดูบทความของฉันในเรื่องที่นี่:

ATBG: พฤตินัยและการเข้าถึงทางนิตินัย

และคุณอาจพิจารณาอ่านข้อกำหนด C #


ดังนั้นสาเหตุที่รหัสนี้ทำให้เกิดข้อผิดพลาดเวลาในการคอมไพล์: public int doNotReturnAnything() { boolean flag = true; while (flag) { //Do something } //no return } รหัสนี้ยังไม่มีจุดพัก ดังนั้นตอนนี้คอมไพเลอร์รู้รหัสผิด
Sandeep Poonia

@SandeepPoonia: คุณอาจต้องการอ่านคำตอบอื่น ๆ ที่นี่ ... ผู้แปลสามารถตรวจพบเงื่อนไขบางอย่างเท่านั้น
Daniel Hilgarth

9
@SandeepPoonia: สามารถเปลี่ยนสถานะบูลีนได้ในขณะรันไทม์เนื่องจากไม่ใช่ const ดังนั้นลูปจึงไม่จำเป็นต้องวนซ้ำ
Schmuli

9
@SandeepPoonia: ใน C # เปคกล่าวว่าif, while, for, switchฯลฯ โครงสร้างแตกแขนงที่ทำงานบนคงที่จะถือว่าเป็นสาขาที่ไม่มีเงื่อนไขโดยรวบรวม คำจำกัดความที่แน่นอนของการแสดงออกคงที่อยู่ในสเป็ค คำตอบสำหรับคำถามของคุณอยู่ในข้อกำหนด คำแนะนำของฉันคือคุณอ่าน
Eric Lippert

1
Every code path that returns must return a valueคำตอบที่ดีที่สุด ตอบคำถามทั้งสองอย่างชัดเจน ขอบคุณ
cPu1

38

คอมไพเลอร์ Java ฉลาดพอที่จะค้นหารหัสที่ไม่สามารถเข้าถึงได้ (โค้ดหลังจากwhileวนซ้ำ)

และเนื่องจากมันไม่สามารถเข้าถึงได้ , มีจุดในการเพิ่มreturnคำสั่งมี (หลังจากwhileปลาย)

กันไปกับเงื่อนไข if

public int get() {
   if(someBoolean) {   
     return 10;
   }
   else {
     return 5;
   }
   // there is no need of say, return 11 here;
}

เนื่องจากเงื่อนไขบูลีนsomeBooleanสามารถประเมินได้เพียงอย่างใดอย่างหนึ่งtrueหรือfalseไม่จำเป็นต้องระบุreturn อย่างชัดเจนหลังจากif-elseนั้นเนื่องจากรหัสนั้นไม่สามารถเข้าถึงได้และ Java ไม่ได้บ่นเกี่ยวกับมัน


4
ฉันไม่คิดว่ามันจะตอบคำถามจริงๆ คำตอบนี้ทำไมคุณไม่ต้องการreturnคำสั่งในรหัสที่ไม่สามารถเข้าถึงได้ แต่ไม่มีอะไรเกี่ยวข้องกับสาเหตุที่คุณไม่ต้องการคำสั่งใด ๆ returnในรหัสของ OP
Bobson

หากคอมไพเลอร์ Java ฉลาดพอที่จะค้นหาโค้ดที่ไม่สามารถเข้าถึงได้ (โค้ดหลังจากในขณะที่ลูป) ดังนั้นทำไมโค้ดด้านล่างเหล่านี้จึงคอมไพล์รหัสทั้งคู่มีโค้ดที่ไม่สามารถเข้าถึงได้ แต่วิธีการถ้าต้องการคำสั่ง return public int doNotReturnAnything() { if(true){ System.exit(1); } return 11; } public int doNotReturnAnything() { while(true){ System.exit(1); } return 11;// Compiler error: unreachable code }
Sandeep Poonia

@SandeepPoonia: เพราะคอมไพเลอร์ไม่ทราบว่าSystem.exit(1)จะฆ่าโปรแกรม มันสามารถตรวจจับโค้ดที่เข้าไม่ถึงบางประเภทเท่านั้น
Daniel Hilgarth

@ Daniel Hilgarth: คอมไพเลอร์ตกลงไม่ทราบว่าSystem.exit(1)จะฆ่าโปรแกรมที่เราสามารถใช้ใด ๆตอนนี้คอมไพเลอร์ตระหนักถึงreturn statement return statementsและพฤติกรรมเหมือนกันกลับต้องใช้สำหรับการแต่ไม่ได้สำหรับif condition while
Sandeep Poonia

1
การสาธิตที่ดีของส่วนที่ไม่สามารถเข้าถึงได้โดยไม่ใช้กรณีพิเศษเช่นwhile(true)
Matthew

17

คอมไพเลอร์รู้ว่าการwhileวนซ้ำจะไม่หยุดดำเนินการดังนั้นวิธีการจะไม่จบดังนั้นจึงreturnไม่จำเป็นต้องมีคำสั่ง


13

เมื่อวนซ้ำของคุณกำลังดำเนินการกับค่าคงที่คอมไพเลอร์รู้ว่ามันเป็นลูปที่ไม่สิ้นสุด

หากคุณใช้ตัวแปรคอมไพเลอร์จะบังคับใช้กฎ:

สิ่งนี้จะไม่รวบรวม:

// Define other methods and classes here
public int doNotReturnAnything() {
    var x = true;

    while(x == true) {
        //do something
    }
    //no return statement - won't compile
}

แต่ถ้า "ทำอะไรบางอย่าง" ไม่เกี่ยวข้องกับการแก้ไข x ในทางใดทางหนึ่งคอมไพเลอร์ไม่ใช่สมาร์ทที่จะเข้าใจมัน Bum :(
Lews Therin

Nope - ดูไม่เหมือน
Dave Bish

@Lews หากคุณมีวิธีการที่ถูกทำเครื่องหมายว่าคืนค่า int แต่ในความเป็นจริงกลับไม่เป็นเช่นนั้นคุณควรจะดีใจที่คอมไพเลอร์ตั้งค่าสถานะนี้ดังนั้นคุณสามารถทำเครื่องหมายวิธีเป็นโมฆะหรือแก้ไขได้หากคุณไม่ได้ตั้งใจ พฤติกรรม.
MikeFHay

@MikeFHay ใช่ไม่ได้โต้แย้งว่า
Lews Therin

1
ฉันอาจจะผิด แต่ debuggers บางคนอนุญาตให้ปรับเปลี่ยนตัวแปร ที่นี่ในขณะที่ x ไม่ได้ถูกแก้ไขด้วยรหัสและมันจะถูกปรับให้เหมาะสมโดย JIT หนึ่งอาจแก้ไข x เป็นเท็จและวิธีการควรกลับบางสิ่งบางอย่าง (ถ้าสิ่งดังกล่าวได้รับอนุญาตจาก C # ดีบักเกอร์)
Maciej Piechotka

11

ข้อกำหนด Java Unreachable statementsกำหนดแนวคิดที่เรียกว่า คุณไม่ได้รับอนุญาตให้มีคำสั่งที่ไม่สามารถเข้าถึงได้ในรหัสของคุณ (เป็นข้อผิดพลาดในการรวบรวมเวลา) คุณไม่ได้รับอนุญาตให้มีข้อความสั่งคืนสินค้าหลังจากผ่านไประยะหนึ่ง (จริง); คำสั่งใน Java while(true);คำสั่งทำให้งบดังต่อไปนี้ไม่สามารถเข้าถึงได้โดยความหมายดังนั้นคุณไม่จำเป็นต้องมีreturnคำสั่ง

โปรดทราบว่าในขณะที่ปัญหาการหยุดชะงักไม่สามารถตัดสินใจได้ในกรณีทั่วไปคำจำกัดความของคำสั่งที่ไม่สามารถเข้าถึงได้นั้นเข้มงวดกว่าการหยุดเพียงแค่ กำลังตัดสินใจเลือกกรณีที่เฉพาะเจาะจงซึ่งโปรแกรมไม่ได้หยุดอย่างแน่นอน คอมไพเลอร์นั้นในทางทฤษฎีไม่สามารถตรวจจับลูปที่ไม่มีที่สิ้นสุดและคำสั่งที่ไม่สามารถเข้าถึงได้ แต่จะต้องตรวจสอบกรณีเฉพาะที่กำหนดไว้ในข้อมูลจำเพาะ (ตัวอย่างเช่นwhile(true)กรณี)


7

คอมไพเลอร์ฉลาดพอที่จะรู้ว่าwhileลูปของคุณไม่มีที่สิ้นสุด

ดังนั้นคอมไพเลอร์ไม่สามารถคิดได้สำหรับคุณ ไม่สามารถเดาได้ว่าทำไมคุณถึงเขียนรหัสนั้น เดียวกันหมายถึงค่าตอบแทนของวิธีการ Java จะไม่บ่นถ้าคุณไม่ทำอะไรกับค่าส่งคืนของวิธีการ

ดังนั้นเพื่อตอบคำถามของคุณ:

คอมไพเลอร์วิเคราะห์รหัสของคุณและหลังจากพบว่าไม่มีเส้นทางการดำเนินการที่จะนำไปสู่การล้มลงในตอนท้ายของฟังก์ชั่นมันเสร็จสิ้นด้วยตกลง

อาจมีเหตุผลที่ถูกต้องสำหรับการวนซ้ำไม่สิ้นสุด ตัวอย่างเช่นแอพจำนวนมากใช้ลูปหลักที่ไม่สิ้นสุด อีกตัวอย่างหนึ่งคือเว็บเซิร์ฟเวอร์ซึ่งอาจรอการร้องขอโดยไม่มีกำหนด


7

ในทฤษฎีประเภทมีสิ่งที่เรียกว่าประเภทด้านล่างซึ่งเป็นประเภทย่อยของทุกประเภทอื่น ๆ (!) และใช้ในการระบุไม่สิ้นสุดในสิ่งอื่น ๆ (ข้อยกเว้นสามารถนับเป็นประเภทที่ไม่ใช่การเลิกจ้าง - คุณไม่ได้ยกเลิกผ่านเส้นทางปกติ)

ดังนั้นจากมุมมองทางทฤษฎีข้อความเหล่านี้ที่ไม่สิ้นสุดสามารถถูกพิจารณาเพื่อส่งคืนบางสิ่งบางอย่างของ Bottom type ซึ่งเป็นชนิดย่อยของ int ดังนั้นคุณ (ชนิด) รับค่าตอบแทนของคุณหลังจากทั้งหมดจากมุมมองประเภท และมันก็โอเคอย่างสมบูรณ์แบบที่มันไม่มีความหมายใด ๆ ที่ประเภทหนึ่งสามารถเป็นคลาสย่อยของทุกอย่างรวมถึง int ได้เพราะคุณไม่ได้ส่งคืนจริง

ไม่ว่าในกรณีใด ๆ โดยผ่านทฤษฎีประเภทที่ชัดเจนหรือไม่คอมไพเลอร์ (ผู้เขียนคอมไพเลอร์) รับรู้ว่าการขอคืนค่าหลังจากคำสั่งที่ไม่สิ้นสุดนั้นเป็นเรื่องที่โง่เง่า: ไม่มีกรณีที่เป็นไปได้ที่คุณอาจต้องการค่านั้น (มันเป็นการดีถ้าให้คอมไพเลอร์เตือนคุณเมื่อรู้ว่าบางอย่างจะไม่ยุติลง แต่ดูเหมือนว่าคุณต้องการให้ส่งคืนบางอย่าง แต่นั่นดีกว่าสำหรับผู้ตรวจสอบสไตล์ la lint เนื่องจากบางทีคุณอาจต้องการลายเซ็นประเภทที่ วิธีอื่น ๆ ด้วยเหตุผลบางอย่าง (เช่นคลาสย่อย) แต่คุณต้องการไม่สิ้นสุดจริงๆ)


6

ไม่มีสถานการณ์ที่ฟังก์ชันสามารถถึงจุดสิ้นสุดโดยไม่ส่งคืนค่าที่เหมาะสม ดังนั้นจึงไม่มีอะไรให้คอมไพเลอร์บ่น


5

Visual studio มีเอ็นจิ้นอัจฉริยะในการตรวจสอบว่าคุณได้พิมพ์ return type หรือไม่นั้นควรมี statement คืนด้วยใน function / method

เช่นเดียวกับใน PHP ประเภทการคืนสินค้าของคุณเป็นจริงถ้าคุณยังไม่ได้ส่งคืนอะไร คอมไพเลอร์รับ 1 ถ้าไม่มีอะไรส่งคืน

ณ วันนี้

public int doNotReturnAnything() {
    while(true) {
        //do something
    }
    //no return statement
}

คอมไพเลอร์รู้ว่าในขณะที่คำสั่งตัวเองมีลักษณะ infinte ดังนั้นจึงไม่ควรพิจารณา และคอมไพเลอร์ PHP จะได้รับจริงโดยอัตโนมัติหากคุณเขียนเงื่อนไขในการแสดงออกของในขณะที่

แต่ไม่ใช่ในกรณีของ VS มันจะส่งคืนข้อผิดพลาดในสแต็ก


4

วงวนของคุณจะวิ่งไปตลอดกาลและด้วยเหตุนี้จะไม่ออกมาข้างนอกในขณะที่; มันจะดำเนินการต่อไป ดังนั้นส่วนภายนอกของ while {} ไม่สามารถเข้าถึงได้และไม่มีจุดในการเขียนส่งคืนหรือไม่ คอมไพเลอร์นั้นฉลาดพอที่จะเข้าใจว่าส่วนใดที่เข้าถึงได้และส่วนใดไม่ได้

ตัวอย่าง:

public int xyz(){
    boolean x=true;

    while(x==true){
        // do something  
    }

    // no return statement
}

โค้ดด้านบนจะไม่คอมไพล์เนื่องจากอาจมีกรณีที่ค่าของตัวแปร x ถูกแก้ไขภายในเนื้อความของ while loop ดังนั้นนี่ทำให้ส่วนนอกของขณะที่ลูปเข้าถึงได้! และด้วยเหตุนี้คอมไพเลอร์จะโยนข้อผิดพลาด 'ไม่พบคำสั่งคืนสินค้า'

คอมไพเลอร์ไม่ฉลาดพอ (หรือค่อนข้างขี้เกียจ;)) เพื่อค้นหาว่าค่าของ x จะถูกแก้ไขหรือไม่ หวังว่านี้จะล้างทุกอย่าง


7
ในความเป็นจริงแล้วในกรณีนี้ไม่ใช่คำถามของคอมไพเลอร์ที่ฉลาดพอ ใน C # 2.0 คอมไพเลอร์สมาร์ทก็มากพอที่จะรู้ว่าint x = 1; while(x * 0 == 0) { ... }เป็นห่วงอนันต์ แต่สเปคบอกว่าคอมไพเลอร์เท่านั้นที่ควรจะทำให้การหักเงินการควบคุมการไหลเมื่อแสดงออกห่วงเป็นอย่างต่อเนื่องและสเปคกำหนดแสดงออกคงเป็นที่มีตัวแปรไม่มี คอมไพเลอร์จึงเป็นสมาร์ทมากเกินไป ใน C # 3 ฉันสร้างคอมไพเลอร์ให้ตรงกับสเปคและหลังจากนั้นมันก็ฉลาดน้อยลงเกี่ยวกับการแสดงออกประเภทนี้
Eric Lippert

4

"ทำไมคอมไพเลอร์ถึงไม่เตือนเรื่องการส่งคืนบางอย่างหรือทำไมภาษาจะทำให้เรามีวิธีการที่ไม่เป็นโมฆะที่มีการวนซ้ำไม่สิ้นสุดและไม่ส่งคืนสิ่งใด"

รหัสนี้ใช้ได้ในภาษาอื่นทุกภาษาด้วยเช่นกัน (อาจยกเว้น Haskell!) เพราะข้อสันนิษฐานแรกคือเรา "ตั้งใจ" เขียนโค้ดบางส่วน

และมีบางสถานการณ์ที่รหัสนี้สามารถใช้งานได้อย่างสมบูรณ์ถ้าคุณจะใช้มันเป็นเธรด หรือถ้ามันส่งคืน a Task<int>คุณสามารถทำการตรวจสอบข้อผิดพลาดบางอย่างตามค่า int ที่ส่งคืน - ซึ่งไม่ควรส่งคืน


3

ฉันอาจจะผิด แต่ debuggers บางคนอนุญาตให้แก้ไขตัวแปรได้ ที่นี่ในขณะที่ x ไม่ได้ถูกแก้ไขด้วยรหัสและมันจะถูกปรับให้เหมาะสมโดย JIT หนึ่งอาจแก้ไข x เป็นเท็จและวิธีการควรกลับบางสิ่งบางอย่าง (ถ้าสิ่งดังกล่าวได้รับอนุญาตจาก C # ดีบักเกอร์)


1

เฉพาะกรณีของ Java สำหรับกรณีนี้ (ซึ่งอาจคล้ายกับกรณี C #) จะทำอย่างไรกับวิธีการที่คอมไพเลอร์ Java กำหนดว่าวิธีการที่จะกลับมา

โดยเฉพาะกฎระเบียบที่มีว่าวิธีการที่มีชนิดกลับต้องไม่สามารถที่จะเสร็จสมบูรณ์ตามปกติและจะต้องแทนเสมอเสร็จสมบูรณ์ทันที (ทันทีที่นี่แสดงให้เห็นผ่านทางคำสั่งกลับหรือข้อยกเว้น) ต่อJLS 8.4.7

หากมีการประกาศให้เมธอดมีชนิดส่งคืนข้อผิดพลาดเวลาคอมไพล์จะเกิดขึ้นหากเนื้อความของเมธอดสามารถดำเนินการตามปกติ กล่าวอีกนัยหนึ่งวิธีการที่มีประเภทผลตอบแทนจะต้องกลับมาโดยใช้คำสั่งส่งคืนที่ให้ผลตอบแทนมูลค่า; มันจะไม่ได้รับอนุญาตให้ "วางปิดท้ายของลำตัว"

คอมไพเลอร์ดูเหมือนว่าการเลิกจ้างตามปกตินั้นเป็นไปได้หรือไม่ขึ้นอยู่กับกฎที่กำหนดในJLS 14.21 ประโยคที่ไม่สามารถเข้าถึงได้เนื่องจากมันจะกำหนดกฎสำหรับการทำให้สมบูรณ์ตามปกติ

โดยเฉพาะกฎสำหรับคำสั่งที่ไม่สามารถเข้าถึงได้สร้างเคสพิเศษสำหรับลูปที่มีtrueนิพจน์คงที่ที่กำหนดไว้:

คำสั่ง while สามารถทำให้สมบูรณ์โดยปกติ iff อย่างน้อยหนึ่งอย่างต่อไปนี้เป็นจริง:

  • คำสั่ง while สามารถเข้าถึงได้และนิพจน์เงื่อนไขไม่ใช่นิพจน์คงที่ (§15.28) ที่มีค่าเป็นจริง

  • มีคำสั่ง break ที่เข้าถึงได้ซึ่งออกจากคำสั่ง while

ดังนั้นหากwhileคำสั่งสามารถดำเนินการตามปกติแล้วคำสั่งส่งคืนด้านล่างมันเป็นสิ่งจำเป็นเนื่องจากรหัสจะถือว่าสามารถเข้าถึงได้และwhileวงใด ๆ ที่ไม่มีคำสั่งทำลายที่สามารถเข้าถึงได้หรือtrueการแสดงออกคงที่ถือว่าสามารถทำได้ตามปกติ

กฎเหล่านี้หมายความว่าคุณwhileคำสั่งด้วยการแสดงออกที่แท้จริงอย่างต่อเนื่องและโดยไม่ต้องbreakมีการไม่เคยคิดว่าจะเสร็จสมบูรณ์ตามปกติและเพื่อให้รหัสใด ๆ ดังต่อไปนี้มันจะไม่เคยคิดว่าจะสามารถเข้าถึงได้ ในตอนท้ายของวิธีการที่อยู่ด้านล่างห่วงและเนื่องจากทุกอย่างด้านล่างห่วงไม่สามารถเข้าถึงเพื่อให้เป็นจุดสิ้นสุดของวิธีการและทำให้วิธีการที่ไม่อาจเสร็จสมบูรณ์ตามปกติ (ซึ่งเป็นสิ่งที่มีลักษณะเรียบเรียงสำหรับ)

if ในทางกลับกันไม่มีข้อยกเว้นพิเศษเกี่ยวกับนิพจน์คงที่ที่สามารถวนซ้ำได้

เปรียบเทียบ:

// I have a compiler error!
public boolean testReturn()
{
    final boolean condition = true;

    if (condition) return true;
}

ด้วย:

// I compile just fine!
public boolean testReturn()
{
    final boolean condition = true;

    while (condition)
    {
        return true;
    }
}

เหตุผลของความแตกต่างนั้นค่อนข้างน่าสนใจและเกิดจากความต้องการอนุญาตให้ใช้แฟล็กการรวบรวมแบบมีเงื่อนไขซึ่งไม่ทำให้เกิดข้อผิดพลาดของคอมไพเลอร์ (จาก JLS):

อาจคาดหวังว่าคำสั่ง if จะได้รับการจัดการในลักษณะดังต่อไปนี้:

  • คำสั่ง if-then สามารถดำเนินการตามปกติ iff อย่างน้อยหนึ่งอย่างต่อไปนี้เป็นจริง:

    • คำสั่ง if-then สามารถเข้าถึงได้และนิพจน์เงื่อนไขไม่ใช่นิพจน์คงที่ซึ่งมีค่าเป็นจริง

    • คำสั่งนั้นสามารถดำเนินการตามปกติ

    คำสั่ง if-then สามารถเข้าถึงได้ถ้า if คำสั่ง if-then สามารถเข้าถึงได้และนิพจน์เงื่อนไขไม่ใช่นิพจน์คงที่ซึ่งค่าเป็นเท็จ

  • คำสั่ง if-then-else สามารถดำเนินการตามปกติ iff คำสั่ง if-then สามารถดำเนินการตามปกติหรือคำสั่ง else สามารถดำเนินการตามปกติ

    • if-then-else สามารถเข้าถึงได้และการแสดงออกของเงื่อนไขไม่ใช่นิพจน์คงที่ซึ่งค่าเป็นเท็จ

    • คำสั่ง else-statement สามารถเข้าถึงได้ถ้า if คำสั่ง if-then-else สามารถเข้าถึงได้และนิพจน์เงื่อนไขไม่ใช่นิพจน์คงที่ซึ่งค่าเป็นจริง

วิธีการนี้จะสอดคล้องกับการรักษาโครงสร้างการควบคุมอื่น ๆ อย่างไรก็ตามเพื่อให้สามารถใช้คำสั่ง if เพื่อความสะดวกในการ "รวบรวมเงื่อนไข" เพื่อวัตถุประสงค์ที่แท้จริงจะแตกต่างกันไป

ตัวอย่างเช่นคำสั่งต่อไปนี้ส่งผลให้เกิดข้อผิดพลาดในการคอมไพล์เวลา:

while (false) { x=3; }เพราะคำสั่งx=3;ไม่สามารถเข้าถึงได้; แต่กรณีที่คล้ายกันตื้น ๆ :

if (false) { x=3; }ไม่ส่งผลให้เกิดข้อผิดพลาดในเวลารวบรวม คอมไพเลอร์การปรับให้เหมาะสมอาจตระหนักว่าคำสั่งx=3;จะไม่ถูกดำเนินการและอาจเลือกที่จะละเว้นรหัสสำหรับคำสั่งนั้นจากไฟล์คลาสที่สร้างขึ้น แต่คำสั่งx=3;นั้นไม่ถือว่า "ไม่สามารถเข้าถึงได้" ในแง่เทคนิคที่ระบุไว้ที่นี่

เหตุผลสำหรับการรักษาที่แตกต่างนี้คือการอนุญาตให้โปรแกรมเมอร์กำหนด "ตัวแปรธง" เช่น:

static final boolean DEBUG = false; แล้วเขียนรหัสเช่น:

if (DEBUG) { x=3; } แนวคิดคือควรจะสามารถเปลี่ยนค่าของ DEBUG จากเท็จเป็นจริงหรือจากจริงเป็นเท็จแล้วรวบรวมรหัสอย่างถูกต้องโดยไม่มีการเปลี่ยนแปลงอื่น ๆ ในข้อความของโปรแกรม

ทำไมคำสั่ง break แบบมีเงื่อนไขส่งผลให้เกิดข้อผิดพลาดของคอมไพเลอร์?

ตามที่ยกมาในกฎการเข้าถึงได้ของลูปห่วงในขณะที่ยังสามารถดำเนินการตามปกติถ้ามันมีคำสั่งหยุดพัก เนื่องจากกฎระเบียบสำหรับการเชื่อมของนั้นifงบแล้วประโยคไม่ได้ใช้เงื่อนไขของการที่ifเข้าสู่การพิจารณาที่ทุกคนเช่นเงื่อนไขifคำสั่งที่แล้วประโยคถือว่าเสมอสามารถเข้าถึงได้

หากbreakสามารถเข้าถึงได้รหัสหลังจากลูปจะถือว่าสามารถเข้าถึงได้อีกครั้ง เนื่องจากไม่มีรหัสที่สามารถเข้าถึงได้ซึ่งส่งผลให้เกิดการยกเลิกอย่างกะทันหันหลังจากวนรอบวิธีการนี้จึงถือว่าสามารถดำเนินการตามปกติได้ดังนั้นคอมไพเลอร์จึงแจ้งว่าเป็นข้อผิดพลาด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.