มันเป็นสิ่งที่มีเหตุผลหรือไม่ที่จะส่งคืนสตรีมทุกครั้งที่เราจะคืนคอลเล็คชั่น?


19

ในขณะที่การพัฒนา API ของฉันที่ไม่ได้เชื่อมโยงกับรหัสดั้งเดิมใด ๆ ฉันมักจะพบว่าตัวเองเขียนวิธีการที่ Streams หมดจดไปป์ไลน์โดยการรวบรวมผลลัพธ์ ชอบสิ่งนี้:

ImmutableSet<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfThing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey)
        .collect(MyCustomCollectors.toImmutableSet());
}

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

Stream<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfthing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey);
        // No collect
}

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

มีบางสิ่งที่ไม่ดีที่อาจเกิดขึ้นได้หรือไม่หากฉันตัดสินใจคืนสตรีมในที่ใดก็ตามที่ตัวเอง pre-Java-8 จะส่งคืนคอลเลกชัน? หรือฉันอาจจะทำสิ่งที่เป็นปฏิปักษ์กับสิ่งที่มาจากรัฐเอกชนหรือไม่?

คำตอบ:


14

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

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

นี้เกิดขึ้นจริงก่อนที่จะ Java 7 substringเมื่อโทร Oracle ตัดสินใจว่าประสิทธิภาพการประหยัดที่อาจเกิดขึ้นจากการไม่คัดลอกซับสตริงทุกครั้งไม่คุ้มที่จะทำให้ผู้ใช้โดยเฉลี่ยมีหน่วยความจำมากเกินไปในบางครั้ง ไม่ได้หมายความว่าไม่มีกรณีการใช้งานจริงสำหรับพฤติกรรมเก่า (เช่น parsers) แต่บ่อยครั้งที่การรวบรวมผลลัพธ์มีความรวดเร็วพอและเมื่อเป็นเช่นนั้นคุณก็ไม่มีข้อดีและข้อเสียที่เป็นไปได้

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


4

สิ่งที่สำคัญที่สุดที่ต้องพิจารณา: Streams สามารถทำซ้ำได้เพียงครั้งเดียวในขณะที่คุณมีความยืดหยุ่นมากกว่า a Collection: คุณสามารถสร้างStreams เพิ่มเติมหรือIteratorทำต่อไปเพื่อทำการประมวลผลเพิ่มเติมซ้ำ ๆ

Collectionดังนั้นหากคุณไม่แน่ใจว่าผู้ที่โทรเข้าของวิธีการที่จะใช้ผลการค้นหาในครั้งเดียวและเพียงครั้งเดียวจะดีกว่าที่จะส่งกลับ


ตัวอย่างรหัสของคุณมีข้อผิดพลาดอย่างใดอย่างหนึ่งที่เห็นได้ชัด: ทำไมจะSocialStatusมีแนวความคิดของคนที่he?


3

ในมุมมองของฉันไม่ สิ่งที่คุณสามารถทำได้กับสตรีมนั้นเป็นสิ่งที่เกินความจริงของสิ่งที่คุณสามารถทำได้กับคอลเล็กชั่นและบ่อยครั้งที่มันสามารถทำให้มีประสิทธิภาพมากขึ้นดังนั้นจึงไม่มีเหตุผลที่จะไม่ใช้มันยกเว้นว่าไม่คุ้นเคย "การแสดงออกของแลมบ์ดาเป็นยาประตูสู่ Java 8 แต่ลำธารเป็นสิ่งเสพติดที่แท้จริง" (Venkat Subramaniam, การเขียนโปรแกรมฟังก์ชั่นใน Java )

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