ในอดีตฉันได้กล่าวว่าการคัดลอกคอลเลกชันอย่างปลอดภัยทำบางสิ่งเช่น:
public static void doThing(List<String> strs) {
List<String> newStrs = new ArrayList<>(strs);
หรือ
public static void doThing(NavigableSet<String> strs) {
NavigableSet<String> newStrs = new TreeSet<>(strs);
แต่ตัวสร้าง "สำเนา" เหล่านี้มีวิธีการสร้างและสตรีมแบบสแตติกที่คล้ายกันปลอดภัยจริงๆและมีการระบุกฎไว้ที่ไหนบ้าง โดยความปลอดภัยฉันหมายถึงการรับประกันความสมบูรณ์แบบพื้นฐานทางความหมายของภาษาจาวาและคอลเลกชันที่บังคับใช้กับผู้โทรที่เป็นอันตรายโดยสมมติว่าได้รับการสนับสนุนจากเหตุผลที่สมเหตุสมผลSecurityManager
และไม่มีข้อบกพร่องใด ๆ
ฉันมีความสุขด้วยวิธีการขว้างปาConcurrentModificationException
, NullPointerException
, IllegalArgumentException
, ClassCastException
ฯลฯ หรือบางทีอาจจะแขวน
ฉันได้เลือกString
เป็นตัวอย่างของการโต้แย้งประเภทไม่เปลี่ยนรูป สำหรับคำถามนี้ฉันไม่สนใจสำเนาชุดลึกสำหรับคอลเล็กชั่นที่ไม่แน่นอนซึ่งมี gotchas ของตัวเอง
(เพื่อความชัดเจนฉันได้ดูซอร์สโค้ด OpenJDK และมีคำตอบบางอย่างสำหรับArrayList
และTreeSet
.)
NavigableSet
และComparable
คอลเลกชันอื่น ๆ ที่ใช้ในบางครั้งสามารถตรวจพบว่าชั้นเรียนไม่ได้ดำเนินการcompareTo()
อย่างถูกต้องและโยนข้อยกเว้น มันค่อนข้างชัดเจนว่าคุณหมายถึงอะไรจากข้อโต้แย้งที่ไม่น่าเชื่อถือ คุณหมายถึงงานฝีมือของคนชั่วในการสะสมของ Strings ที่ไม่ดีและเมื่อคุณคัดลอกมันไปยังคอลเล็กชั่นของคุณ ไม่กรอบของคอลเลกชันนั้นค่อนข้างมั่นคงมาตั้งแต่ 1.2
HashSet
(และทุกคอลเลกชันคร่ำเครียดอื่น ๆ ทั่วไป) อาศัยอยู่กับความถูกต้อง / ความสมบูรณ์ของhashCode
การดำเนินงานขององค์ประกอบTreeSet
และPriorityQueue
ขึ้นอยู่กับComparator
(และคุณไม่สามารถแม้แต่จะ สร้างสำเนาที่เทียบเท่าโดยไม่ยอมรับตัวเปรียบเทียบที่กำหนดเองหากมี) ให้EnumSet
เชื่อมั่นในความสมบูรณ์ของenum
ประเภทเฉพาะที่ไม่เคยตรวจสอบหลังจากคอมไพล์ดังนั้นไฟล์คลาสที่ไม่ได้สร้างjavac
หรือทำด้วยมือสามารถล้มล้างได้
new TreeSet<>(strs)
ที่เป็นstrs
NavigableSet
นี่ไม่ใช่สำเนาจำนวนมากเนื่องจากผลลัพธ์TreeSet
จะใช้ตัวเปรียบเทียบของแหล่งที่มาซึ่งจำเป็นต้องมีเพื่อเก็บความหมายไว้ หากคุณพอใจกับการประมวลผลองค์ประกอบที่toArray()
มีอยู่เป็นวิธีที่จะไป มันจะรักษาลำดับการวนซ้ำ เมื่อคุณพอใจกับ“ รับองค์ประกอบตรวจสอบองค์ประกอบใช้องค์ประกอบ” คุณไม่จำเป็นต้องทำสำเนา ปัญหาเริ่มต้นเมื่อคุณต้องการตรวจสอบองค์ประกอบทั้งหมดตามด้วยการใช้องค์ประกอบทั้งหมด จากนั้นคุณไม่สามารถเชื่อถือTreeSet
สำเนาเปรียบเทียบที่กำหนดเองได้
checkcast
สำหรับแต่ละองค์ประกอบนั้นขึ้นอยู่toArray
กับประเภทเฉพาะ เรามักจะจบลงที่มัน คอลเลกชันทั่วไปไม่รู้จักประเภทองค์ประกอบจริงดังนั้นตัวสร้างสำเนาของพวกเขาจึงไม่สามารถใช้ฟังก์ชันการทำงานที่คล้ายกันได้ แน่นอนคุณสามารถเลื่อนการตรวจสอบใด ๆ ไปก่อนการใช้งานได้ แต่จากนั้นฉันไม่รู้ว่าคำถามของคุณมีจุดประสงค์อะไร คุณไม่ต้องการ "semantic integrity" เมื่อคุณตรวจสอบและล้มเหลวทันทีก่อนใช้องค์ประกอบ