การแปลงคำสั่ง IF


39

ดังนั้นฉันจึงเขียนโปรแกรมมาหลายปีแล้วและเพิ่งเริ่มใช้ ReSharper มากขึ้น สิ่งหนึ่งที่ ReSharper แนะนำให้ฉันเสมอคือ "กลับด้าน" ถ้า "คำสั่งเพื่อลดการซ้อน"

สมมติว่าฉันมีรหัสนี้:

foreach (someObject in someObjectList) 
{
    if(someObject != null) 
    {
        someOtherObject = someObject.SomeProperty;
    }
}

และ ReSharper จะแนะนำให้ฉันทำสิ่งนี้:

foreach (someObject in someObjectList)
{
    if(someObject == null) continue;
    someOtherObject = someObject.SomeProperty;
}

ดูเหมือนว่า ReSharper จะแนะนำให้ฉันย้อนกลับ IFs ไม่ว่าจะทำรังมากแค่ไหนก็ตาม ปัญหานี้คือฉันชอบทำรังในสถานการณ์อย่างน้อยบางครั้ง สำหรับฉันนั้นดูเหมือนง่ายต่อการอ่านและเข้าใจว่าเกิดอะไรขึ้นในบางสถานที่ นี่ไม่ใช่กรณีเสมอไป แต่ฉันรู้สึกสะดวกสบายในการทำรังในบางครั้ง

คำถามของฉันคือ: นอกเหนือจากความชอบส่วนตัวหรือความสามารถในการอ่านมีเหตุผลที่จะลดการทำรังหรือไม่? มีความแตกต่างของประสิทธิภาพการทำงานหรืออย่างอื่นที่ฉันอาจไม่ทราบหรือไม่?


1
สำเนาซ้ำที่เป็นไปได้ของKeep เยื้องระดับต่ำ
ริ้น

24
สิ่งสำคัญที่นี่คือ "Resharper แนะนำ" ดูข้อเสนอแนะถ้ามันทำให้รหัสอ่านง่ายขึ้นและสอดคล้องกันใช้มัน มันทำสิ่งเดียวกันกับ / สำหรับแต่ละลูป
Jon Raynor

โดยทั่วไปฉันลดระดับคำแนะนำผู้แก้ไขเหล่านั้นฉันไม่ได้ปฏิบัติตามเสมอดังนั้นพวกเขาจึงไม่ปรากฏในแถบด้านข้างอีกต่อไป
CodesInChaos

1
ReSharper ลบค่าลบซึ่งโดยปกติจะเป็นสิ่งที่ดี อย่างไรก็ตามมันไม่ได้แนะนำเงื่อนไขที่ประกอบไปด้วยสามซึ่งสามารถพอดีกับที่นี่ถ้าบล็อกนั้นง่ายเหมือนตัวอย่างของคุณ
dcorking

2
ReSharper ไม่แนะนำให้ย้ายเงื่อนไขไปยังแบบสอบถามหรือไม่ foreach (someObject ใน someObjectList.Where (object => object! = null)) {... }
Roman Reiner

คำตอบ:


63

มันขึ้นอยู่กับ. ในตัวอย่างของคุณที่มีifคำสั่งnon-inverted ไม่ใช่ปัญหาเพราะเนื้อความของตัวifย่อนั้นสั้นมาก อย่างไรก็ตามคุณมักจะต้องการกลับคำสั่งเมื่อร่างกายเติบโต

เราเป็นมนุษย์เท่านั้นและการเก็บหลาย ๆ อย่างในหัวของเราเป็นเรื่องยาก

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


64
ฉันชอบที่จะเห็นกระแสของความคิดเห็นของนักพัฒนาไปทางนี้ มีการทำรังมากในรหัสเพียงเพราะมีการเข้าใจผิดที่นิยมเป็นพิเศษที่break, continueและหลาย ๆreturnที่ไม่ได้มีโครงสร้าง
JimmyJames

6
ปัญหาคือการแตก ฯลฯ ยังคงมีการควบคุมการไหลที่คุณต้องเก็บไว้ในหัวของคุณ 'ไม่สามารถ x หรือมันจะออกจากลูปที่ด้านบน' อาจไม่จำเป็นต้องคิดเพิ่มเติมถ้าตรวจสอบโมฆะซึ่งจะโยนข้อยกเว้นอยู่แล้ว แต่มันก็ไม่ดีนักเมื่อมันมีความเหมาะสมยิ่งขึ้น 'รันโค้ดนี้เพียงครึ่งเดียวสำหรับสถานะนี้ในวันพฤหัสบดี'
Ewan

2
@Ewan: ความแตกต่างระหว่าง 'สิ่งนี้ไม่สามารถเป็น x หรือมันจะออกจากลูปที่ด้านบน' และ 'สิ่งนี้ไม่สามารถเป็น x หรือจะไม่ได้เข้าสู่บล็อกนี้'?
Collin

ไม่มีความซับซ้อนและความหมายของ x ซึ่งสำคัญ
Ewan

4
@Ewan: ฉันคิดว่าbreak/ continue/ returnมีข้อได้เปรียบเหนือelseบล็อก ด้วยการออกไปข้างนอกช่วงต้นมี2 ช่วงตึกคือบล็อกการออกและบล็อกการพัก กับelseมี3 บล็อก : ถ้าอื่นและสิ่งที่เกิดขึ้นหลังจากที่ (ซึ่งจะใช้สิ่งที่สาขาที่ถ่าย) ฉันชอบที่จะมีบล็อกน้อยลง
Matthieu M.

33

อย่าหลีกเลี่ยงเชิงลบ มนุษย์ดูดการแยกวิเคราะห์พวกเขาแม้ว่า CPU จะรักพวกเขา

อย่างไรก็ตามเคารพสำนวน มนุษย์เราเป็นสิ่งมีชีวิตของนิสัยดังนั้นเราจึงชอบเส้นทางที่สวมใส่เป็นอย่างดีไปยังเส้นทางตรงที่เต็มไปด้วยวัชพืช

foo != nullมีเศร้ากลายเป็นสำนวน ฉันเพิ่งสังเกตเห็นชิ้นส่วนที่แยกจากกันอีกต่อไป ฉันดูมันและคิดว่า "โอ้ปลอดภัยแล้วที่จะจุดจากfooตอนนี้"

หากคุณต้องการที่จะล้มล้าง (โอ้สักวันโปรด) คุณจำเป็นต้องมีกรณีที่แข็งแกร่งมาก คุณต้องการบางสิ่งที่จะทำให้ดวงตาของฉันหลุดออกจากมันอย่างง่ายดายและเข้าใจมันในทันที

อย่างไรก็ตามสิ่งที่คุณให้กับเราคือ:

foreach (someObject in someObjectList)
{
    if(someObject == null) continue;
    someOtherObject = someObject.SomeProperty;
}

ซึ่งไม่ได้มีโครงสร้างเหมือนกัน!

foreach (someObject in someObjectList)
{
    if(someObject == null) continue;
    someOtherObject = someObject.SomeProperty;

    if(someGlobalObject == null) continue;
    someSideEffectObject = someGlobalObject.SomeProperty;
}

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

ขออภัยบางที ReSharper มีสิทธิ์ที่จะแนะนำ 90% ของเวลานี้ แต่ในการตรวจสอบที่ว่างเปล่าฉันคิดว่าคุณได้พบกรณีมุมที่มันถูกละเว้นที่ดีที่สุด เครื่องมือไม่ดีพอที่จะสอนให้คุณรู้ว่ารหัสที่อ่านได้คืออะไร ถามมนุษย์ ทำรีวิวเพียร์ แต่อย่าสุ่มสี่สุ่มห้าติดตามเครื่องมือ


1
ถ้าคุณมีรหัสเพิ่มเติมในลูปการทำงานจะขึ้นอยู่กับว่ามันมารวมกันอย่างไร มันไม่ใช่รหัสอิสระ รหัส refactored ในคำถามนั้นถูกต้องสำหรับตัวอย่าง แต่อาจไม่ถูกต้องเมื่อไม่แยก - นั่นคือจุดที่คุณจะไปหรือไม่ (+1 สำหรับสิ่งที่ไม่ควรหลีกเลี่ยงในเชิงลบ)
Baldrickk

@Baldrickk if (foo != null){ foo.something() }ให้ฉันเพิ่มรหัสต่อไปโดยไม่สนว่าfooเป็นโมฆะ สิ่งนี้ไม่ได้ แม้ว่าฉันไม่จำเป็นต้องทำเช่นนั้นตอนนี้ฉันไม่รู้สึกมีแรงบันดาลใจที่จะไขอนาคตโดยพูดว่า "พวกเขาสามารถปรับโครงสร้างได้ถ้าพวกเขาต้องการ" Feh ซอฟต์แวร์จะอ่อนนุ่มหากเปลี่ยนง่าย
candied_orange

4
"ทำการเพิ่มรหัสโดยไม่สนใจ" รหัสควรเกี่ยวข้องกัน (ไม่เช่นนั้นควรแยกจากกัน) หรือควรมีความระมัดระวังในการทำความเข้าใจเกี่ยวกับการทำงานของฟังก์ชัน / บล็อกที่คุณกำลังปรับเปลี่ยนเนื่องจากการเพิ่มรหัสใด ๆมีแนวโน้มที่จะเปลี่ยนพฤติกรรม เกินกว่าที่ตั้งใจไว้ สำหรับกรณีง่าย ๆ เช่นนี้ฉันไม่คิดว่ามันจะเป็นอย่างใดอย่างหนึ่ง สำหรับกรณีที่ซับซ้อนมากขึ้นฉันคาดว่าจะเข้าใจโค้ดเพื่อใช้ความมั่นใจดังนั้นฉันจะเลือกวิธีที่ฉันคิดว่าชัดเจนที่สุดซึ่งอาจเป็นรูปแบบใดก็ได้
Baldrickk

ที่เกี่ยวข้องและพันไม่เหมือนกัน
candied_orange

1
อย่าหลีกเลี่ยงเชิงลบ: D
VitalyB

20

มันเป็นข้อโต้แย้งเก่า ๆ เกี่ยวกับการหยุดพักที่แย่กว่านั้น

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

โดยส่วนตัวฉันหลีกเลี่ยงการดำเนินการต่อต่อไปข้ามไป ฯลฯ แม้ว่ามันจะหมายถึงการทำรังมากขึ้น แต่ในกรณีส่วนใหญ่คุณสามารถหลีกเลี่ยงทั้งสองอย่าง

foreach (someObject in someObjectList.where(i=>i != null))
{
    someOtherObject = someObject.SomeProperty;
}

การทำรังอย่างชัดเจนทำให้ยากต่อการติดตามเมื่อคุณมีหลายเลเยอร์

foreach (someObject in someObjectList) 
{
    if(someObject != null) 
    {
        someOtherObject = someObject.SomeProperty;
        if(someObject.x > 5) 
        {
            x ++;
            if(someObject.y > 5) 
            {
                x ++;
            }
        }
    }
}

ที่เลวร้ายที่สุดคือเมื่อคุณมีทั้ง

foreach (someObject in someObjectList) 
{
    if(someObject != null) 
    {
        someOtherObject = someObject.SomeProperty;
        if(someObject.x > 5) 
        {
            x ++;
            if(someObject.y > 5) 
            {
                x ++;
                return;
            }
            continue;
        }
        someObject.z --;
        if(myFunctionWithSideEffects(someObject) > 6) break;
    }
}

11
ชอบสายนี้: foreach (subObject in someObjectList.where(i=>i != null))ไม่รู้ทำไมฉันไม่เคยคิดอย่างนั้น
Barry Franklin

@BarryFranklin ReSharper ควรมีขีดสีเขียวจุดบน foreach ด้วย "แปลงเป็น LINQ นิพจน์" เป็นคำแนะนำที่จะทำเพื่อคุณ ขึ้นอยู่กับการดำเนินการมันอาจใช้วิธีอื่นของ linq เช่น Sum หรือ Max เช่นกัน
ค่าธรรมเนียมของเควิน

@BarryFranklin อาจเป็นคำแนะนำที่คุณต้องการตั้งไว้ในระดับต่ำและใช้ดุลยพินิจเท่านั้น ในขณะที่มันทำงานได้ดีสำหรับกรณีเล็ก ๆ น้อย ๆ เช่นตัวอย่างนี้ฉันพบในรหัสที่ซับซ้อนมากขึ้นวิธีที่มันเลือกส่วนที่มีเงื่อนไขที่ซับซ้อนมากขึ้นเป็นบิตที่ Linqifiable และร่างกายที่เหลือมีแนวโน้มที่จะสร้างสิ่งต่าง ๆ ที่ยากกว่าเดิม อย่างน้อยฉันก็จะลองทำตามคำแนะนำเพราะเมื่อมันสามารถแปลงลูปทั้งหมดเป็น Linq ผลลัพธ์ก็มักจะสมเหตุสมผล แต่ผลลัพธ์ครึ่งและครึ่งมีแนวโน้มที่จะได้รับ IMO ที่รวดเร็วน่าเกลียด
Dan Neely

กระแทกแดกดันการแก้ไขโดย resharper มีระดับที่แน่นอนของการทำรังเพราะมันยังมีถ้าตามมาด้วยซับหนึ่ง
ปีเตอร์

เฮ้ไม่มีวงเล็บปีกกา! ซึ่งเห็นได้ชัดว่าได้รับอนุญาต: /
Ewan

6

ปัญหาที่เกิดขึ้นcontinueคือถ้าคุณเพิ่มบรรทัดเพิ่มเติมลงในโค้ดตรรกะจะซับซ้อนและมีแนวโน้มที่จะมีข้อบกพร่อง เช่น

foreach (someObject in someObjectList)
{
    if(someObject == null) continue;
    someOtherObject = someObject.SomeProperty;

    ...  imagine that there is some code here ...

    // added later by a Junior Developer
    doSomeOtherFunction(someObject);
}

คุณต้องการที่จะเรียกdoSomeOtherFunction()สำหรับทุก someObject หรือเฉพาะถ้าไม่ใช่ null? ด้วยรหัสต้นฉบับคุณมีตัวเลือกและชัดเจนยิ่งขึ้น ด้วยสิ่งcontinueหนึ่งอาจลืม "โอ้ใช่กลับไปที่นั่นเราข้ามโมฆะ" และคุณไม่มีแม้แต่ตัวเลือกที่จะเรียกมันสำหรับบาง Object ทั้งหมดเว้นแต่คุณจะวางสายนั้นในตอนเริ่มต้นของวิธีการซึ่งอาจไม่ถูกต้องหรือไม่ถูกต้อง ด้วยเหตุผลอื่น

ใช่การทำรังจำนวนมากน่าเกลียดและอาจสับสน แต่ในกรณีนี้ฉันจะใช้รูปแบบดั้งเดิม

คำถามโบนัส: เหตุใดจึงมีโมฆะในรายการที่จะเริ่มต้นด้วย มันจะเป็นการดีกว่าถ้าคุณไม่เพิ่ม null ในครั้งแรกซึ่งในกรณีนี้ตรรกะการประมวลผลจะง่ายกว่ามาก


12
ไม่ควรมีรหัสเพียงพอในลูปที่คุณไม่สามารถดูโมฆะตรวจสอบที่ด้านบนของมันโดยไม่ต้องเลื่อน
Bryan Boettcher

@Bryan Boettcher เห็นด้วย แต่ไม่ใช่รหัสทั้งหมดที่เขียนได้ดี และแม้กระทั่งรหัสที่ซับซ้อนหลายบรรทัดก็อาจทำให้ลืมได้ ในทางปฏิบัติฉันโอเคกับreturnสาเหตุที่ทำให้พวกเขา "สะอาดหมดจด" แต่ IMO breakและcontinueนำไปสู่ความสับสนและในกรณีส่วนใหญ่จะหลีกเลี่ยงได้ดีที่สุด
user949300

4
@ user949300 หลังจากสิบปีของการพัฒนาฉันไม่เคยพบว่ามีการหยุดพักหรือทำให้เกิดความสับสน ฉันให้พวกเขามีส่วนร่วมในความสับสน แต่พวกเขาไม่เคยมีสาเหตุ โดยปกติแล้วการตัดสินใจที่ไม่ดีของผู้พัฒนานั้นเป็นสาเหตุและพวกเขาอาจทำให้เกิดความสับสนไม่ว่าพวกเขาจะใช้อาวุธอะไร
corsiKa

1
@corsiKa ข้อผิดพลาดของ Apple SSLเป็นข้อผิดพลาดแบบข้ามไปจริง ๆ อย่างไรก็ตามรหัสนั้นแย่มาก ...
user949300

3
@BryanBoettcher ปัญหาดูเหมือนว่าฉันว่า devs เดียวกันที่คิดว่าดำเนินการต่อหรือผลตอบแทนหลายรายการก็โอเคยังคิดว่าการฝังพวกเขาในร่างกายวิธีการที่มีขนาดใหญ่ก็โอเค ดังนั้นทุกประสบการณ์ที่ฉันได้รับจากการดำเนินการต่อ / การส่งคืนหลายครั้งอยู่ในความยุ่งเหยิงของรหัส
Andy

3

ความคิดคือผลตอบแทนต้น ในช่วงต้นในวงกลายเป็นต้นreturncontinue

คำตอบที่ดีมากมายสำหรับคำถามนี้: ฉันควรกลับจากฟังก์ชันก่อนหน้าหรือใช้คำสั่ง if?

ขอให้สังเกตว่าในขณะที่คำถามถูกปิดตามความคิดเห็นคะแนน 430+ อยู่ในความโปรดปรานของผลตอบแทนก่อน ~ ~ 50 คะแนนเป็น "มันขึ้นอยู่กับ" และ 8 เป็นต่อต้านผลตอบแทนก่อน ดังนั้นจึงมีฉันทามติที่แข็งแกร่งเป็นพิเศษ (ไม่เช่นนั้นหรือฉันแย่ในการนับซึ่งน่าเชื่อถือ)

โดยส่วนตัวถ้าตัวลูปจะต้องอยู่ในช่วงต้นของการเริ่มต้นต่อเนื่องและนานพอสำหรับสสาร (3-4 บรรทัด) ฉันมักจะแยกลูปบอดี้เข้าสู่ฟังก์ชั่นที่ฉันใช้การกลับมาเร็วแทนการเริ่มต้นต่อ


2

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

เรามักจะกลับifsไปทำงานของฉันและจ้างแฟนทอมคนอื่น มันค่อนข้างบ่อยครั้งที่ในขณะที่รีวิว PR ฉันสามารถชี้ให้เห็นว่าเพื่อนร่วมงานของฉันสามารถลบการทำรังสามระดับได้อย่างไร มันเกิดขึ้นได้ไม่บ่อยนักเนื่องจากเราแผ่ออกไอเอฟเอของเรา

นี่คือตัวอย่างของเล่นของสิ่งที่สามารถรีดได้

function foobar(x, y, z) {
    if (x > 0) {
        if (z != null && isGamma(y)) {
            // ~10 lines of code
            // return something
        }
        else {
           return y
        }
    }
    else {
      return y + z
    }
}

รหัสเช่นนี้ซึ่งมีกรณีที่น่าสนใจหนึ่งกรณี (ที่เหลือเป็นเพียงการส่งคืนหรือบล็อกคำสั่งขนาดเล็ก) เป็นเรื่องธรรมดา มันเป็นเรื่องเล็กน้อยที่จะเขียนใหม่ข้างต้นเป็น

function foobar(x, y, z) {
    if (x <=0) {
        return y + z
    }
    if (z == null || !isGamma(y) {
       return y
    }
    // ~ 10 lines of code
    // return something
}

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


ในการตอบสนองต่อตัวอย่างรหัสของ OP ฉันเห็นด้วยว่านั่นคือการยุบ overeager โดยเฉพาะอย่างยิ่งตั้งแต่ใน 1TB สไตล์ที่ฉันใช้การกลับรายการทำให้โค้ดมีขนาดเพิ่มขึ้น


0

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

ทุกสิ่งอื่น ๆ ที่เท่าเทียมกันการทำรังน้อยกว่าจึงเป็นที่นิยมกว่าซึ่งเป็นเหตุผลที่ ReSharper จะแนะนำการเปลี่ยนแปลงที่ลดการทำรัง แต่สิ่งอื่น ๆ ทั้งหมดไม่เท่ากัน: ในกรณีนี้การแปลงจำเป็นต้องมีการเปิดตัว a continueซึ่งหมายความว่ารหัสที่ได้นั้นเป็นเรื่องยากที่จะติดตาม

ในบางกรณีการแลกเปลี่ยนระดับของการซ้อนสำหรับ a continue อาจเป็นการปรับปรุง แต่ขึ้นอยู่กับความหมายของรหัสที่เป็นปัญหาซึ่งอยู่นอกเหนือความเข้าใจในกฎทางกลของ ReSharpers

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


0

ฉันคิดว่าจุดที่ใหญ่กว่าที่นี่คือจุดประสงค์ของลูปจะกำหนดวิธีที่ดีที่สุดในการจัดระเบียบโฟลว์ภายในลูป หากคุณกำลังกรององค์ประกอบบางอย่างก่อนที่คุณจะวนซ้ำส่วนที่เหลือการcontinueออกไปก่อนกำหนดนั้นสมเหตุสมผลแล้ว อย่างไรก็ตามหากคุณกำลังทำการประมวลผลที่แตกต่างกันภายในลูปมันอาจสมเหตุสมผลมากกว่าที่จะทำให้ifเห็นได้ชัดเจนเช่น:

for(obj in objectList) {
    if(obj == null) continue;
    if(obj.getColour().equals(Color.BLUE)) {
        // Handle blue objects
    } else {
        // Handle non-blue objects
    }
}

โปรดทราบว่าใน Java Streams หรือสำนวนการทำงานอื่น ๆ คุณสามารถแยกการกรองออกจากการวนซ้ำโดยใช้:

items.stream()
    .filter(i -> (i != null))
    .filter(i -> i.getColour().equals(Color.BLUE))
    .forEach(i -> {
        // Process blue objects
    });

อนึ่งนี่เป็นหนึ่งในสิ่งที่ฉันชอบเกี่ยวกับการกลับหัวของ Perl ถ้า ( unless) นำไปใช้กับคำสั่งเดียวซึ่งช่วยให้รหัสประเภทต่อไปนี้ซึ่งฉันอ่านง่ายมาก:

foreach my $item (@items) {
    next unless defined $item;
    carp "Only blue items are supported! Failed on item $item" 
       unless ($item->get_colour() eq 'blue');
    ...
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.