Collections.emptyMap () เทียบกับ HashMap ใหม่ ()


143

มีสถานการณ์อะไรบ้างที่ฉันสามารถใช้ได้ Collections.emptyMap() ? เอกสารอธิบายว่าฉันสามารถใช้วิธีนี้ถ้าฉันต้องการให้คอลเลกชันของฉันจะไม่เปลี่ยนรูป

ทำไมฉันถึงต้องการคอลเลคชันที่ไม่เปลี่ยนรูป ประเด็นคืออะไร?


12
+1 กับคำถามเพราะฉันไม่เคยเห็นวิธีแบบคงที่มาก่อน
ทิมเบนเดอร์

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

1
มันเหมือนกับ Objective-C's [NSArray array]แต่จะคืนค่าวัตถุที่แม้ว่าจะไม่สามารถใช้งานได้ แต่มีอยู่จริง ดังนั้นคุณสามารถเล่นกับมันเหมือนวัตถุปกติและไม่ได้รับข้อผิดพลาด
Shane Hsu

คำตอบ:


144

จากการที่มีประสิทธิภาพ Java , Item # 43 - "Return empty arrays or collections, not null"แสดงให้เห็นถึงการกลับมาคอลเลกชันที่ว่างเปล่าและบางทีอาจจะแสดงให้เห็นถึงการใช้เหล่านี้emptyList(), emptySet()และemptyMap()วิธีการในชั้นคอลเลกชันที่จะได้รับคอลเลกชันที่ว่างเปล่าที่ยังมีประโยชน์เพิ่มเติมของการเปลี่ยนรูป จาก Item "Minimize Mutability"#

จากCollections-emptySet-Collections-emptyList-Collections

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

หมายเหตุ:โค้ดด้านล่างเป็นเพียงตัวอย่าง (เปลี่ยนตามกรณีการใช้งานของคุณ):

private Set myset = Collections.emptySet();

void initSet() {
   myset = new HashSet();
}
void deleteSet() {
   myset = Collections.emptySet();
}

วิธีการเหล่านี้มีข้อดีสองสามข้อ:

  1. มันกระชับมากขึ้นเพราะคุณไม่จำเป็นต้องพิมพ์ประเภททั่วไปของคอลเลกชันอย่างชัดเจน - โดยทั่วไปจะอนุมานจากบริบทของการเรียกเมธอด

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


15
+1 สำหรับการอ้างอิง Java ที่มีประสิทธิภาพ หนึ่งนิดหน่อย: ฉันขอแนะนำให้ปรับพารามิเตอร์SetและHashSetในตัวอย่างของคุณเนื่องจากจุดทั้งหมดของemptySet()วิธีการและเพื่อน (ตรงข้ามกับค่าคงที่Collections.EMPTY_SETเป็นต้น) ก็คือพวกเขาเล่นกับยาชื่อสามัญ นอกจากนี้การใช้คุณสมบัติ (ประเภทดิบ) ที่เลิกใช้แล้วเนื่องจาก Java 5 ไม่ใช่เครื่องช่วยสอนที่ดี
Daniel Pryden

4
ฉันยังไม่มั่นใจ ... จุดที่ใช้Collectionแทนnullการหลีกเลี่ยงExceptionsการถูกดำเนินการต่อไปนี้ทั้งหมดไม่ใช่หรือ? การใช้คอลเลกชันที่ไม่เปลี่ยนรูปก็จะส่งผลให้เกิดข้อยกเว้นประเภทอื่นที่ฉันจินตนาการ nullแน่นอนว่าการมอบหมายนั้นไม่ได้มีประสิทธิภาพน้อยกว่าการกำหนดค่าคงที่ที่ไม่เปลี่ยนรูปแบบ
fgysin คืนสถานะโมนิก้า

14
@fgysin: หากคุณมี API ที่ลูกค้าคาดว่าจะปรับเปลี่ยนการเก็บรวบรวมแล้วใช่มันไม่เหมาะสมที่จะส่งกลับคอลเลกชันที่ไม่เปลี่ยนรูป แต่ถ้าคุณมี API ที่คุณส่งคืนคอลเลกชันที่ลูกค้าต้องไม่แก้ไขและควรทำซ้ำดังนั้นการส่งคืนมุมมองไปยังคอลเลกชันพื้นฐานนั้นเหมาะสมอย่างยิ่งเพื่อให้แน่ใจว่าไคลเอนต์ "ไม่ดี" ไม่ได้แก้ไขคอลเลกชันโดยบังเอิญ โดยคุณ. การส่งคืนคอลเล็กชันว่างเปล่าแทน null หมายความว่าไคลเอ็นต์ของคุณไม่จำเป็นต้องทำการตรวจสอบ null ก่อนที่จะใช้คอลเล็กชันทำให้รหัสไคลเอ็นต์ชัดเจนยิ่งขึ้น
Jean Hominal

4
public boolean setExists() { return !myset.equals(Collections.emptySet()); }
assylias

5
ในตัวอย่างของคุณคุณกำลังตรวจสอบอย่างชัดเจนสำหรับชุดที่ว่างเปล่าและใช้มันเป็นค่าแมวมองและชั้นของคุณไม่แน่นอน ตัวอย่างเล็ก ๆ ของคุณใช้รักษาการณ์และความไม่แน่นอนซึ่งเป็นสิ่งที่ Collections.emptySet () พยายามป้องกัน
Marc O'Morain

33

ในประสบการณ์ส่วนตัวของฉันเป็นที่ยอมรับว่ามีประโยชน์มากในกรณีที่ API ต้องการชุดของพารามิเตอร์ แต่คุณไม่มีอะไรจะให้ ตัวอย่างเช่นคุณอาจมี API ที่มีลักษณะเช่นนี้และไม่อนุญาตการอ้างอิงที่เป็นโมฆะ:

public ResultSet executeQuery(String query, Map<String, Object> queryParameters);

หากคุณมีแบบสอบถามที่ไม่ใช้พารามิเตอร์ใด ๆ แน่นอนว่ามันค่อนข้างสิ้นเปลืองในการสร้าง HashMap ซึ่งเกี่ยวข้องกับการจัดสรรอาเรย์เมื่อคุณสามารถส่งผ่าน 'Empty Map' ซึ่งมีค่าคงที่ได้อย่างมีประสิทธิภาพ ในjava.util.Collections.


22

ทำไมฉันถึงต้องการคอลเลคชันที่ไม่เปลี่ยนรูป ประเด็นคืออะไร?

มีสองแนวคิดที่แตกต่างกันที่นี่ซึ่งดูแปลกเมื่อมองด้วยกัน มันสมเหตุสมผลมากกว่าเมื่อคุณปฏิบัติกับแนวคิดทั้งสองแยกจากกัน

  • ประการแรกคุณควรเลือกใช้คอลเล็กชันที่ไม่เปลี่ยนรูปแทนการใช้คอลเล็กชั่นที่เปลี่ยนแปลงไม่ได้เมื่อใดก็ตามที่เป็นไปได้ ประโยชน์ของการ immuablity เป็นอย่างดีเอกสารอื่น ๆ

  • ประการที่สองคุณควรใช้คอลเล็กชันที่ว่างเปล่าแทนที่จะใช้ null เป็น Sentinel นี่เป็นคำอธิบายที่ดี หมายความว่าคุณจะมีรหัสที่สะอาดและเข้าใจได้ง่ายขึ้นและมีที่สำหรับซ่อนแมลงน้อยลง

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


8

มีสองสามกรณีที่คุณต้องการใช้แผนที่ที่ไม่เปลี่ยนรูปแบบรายการชุดหรือคอลเลกชันประเภทอื่น ๆ

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

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

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

ฉันคิดว่ามันเป็น"ผ่านค่า"การประชุม

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

ในฐานะที่เป็นผลข้างเคียงที่เป็นประโยชน์อย่างมากจากสิ่งนี้คือการเพิ่มความปลอดภัยและความปลอดภัยของเธรดของโมดูล / บริการของคุณ

อีกเหตุผลที่ดีในการใช้Collections.empty*()วิธีการคือการขาดความชัดเจน ในยุคก่อน Java7 ถ้าคุณมีคอลเลกชันทั่วไปคุณต้องโรยคำอธิบายประกอบประเภททั่วไปทั่วสถานที่

เพียงเปรียบเทียบการประกาศทั้งสองนี้:

Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();

เมื่อเทียบกับ:

Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();

หลังอย่างชัดเจนชนะมือในการอ่านในสองวิธีสำคัญ

  1. ในการประกาศครั้งแรกการสร้างอินสแตนซ์ทั้งหมดของแผนที่ที่ว่างเปล่านั้นถูกฝังอยู่ในเสียงของการประกาศประเภททั่วไป
  2. นอกเหนือจากการไม่มีคำอธิบายประกอบแบบทั่วไปทางด้านขวารุ่นที่สองระบุไว้อย่างชัดเจนว่าแผนที่จะเริ่มต้นเป็นแผนที่ว่าง นอกจากนี้การรู้ว่าวิธีนี้จะส่งคืนแผนที่ที่ไม่เปลี่ยนรูปได้ในขณะนี้ฉันสามารถหาได้ง่ายกว่าที่ไหนfooBarMapถูกกำหนดค่าที่ไม่ว่าง/fooBarMap =/เปล่าอีกเพียงแค่การค้นหา

5

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

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


3

มันจะมีประโยชน์เมื่อคุณมีฟังก์ชั่นที่คืนค่าimmutable collectionและในบางสถานการณ์ไม่มีข้อมูลที่จะส่งคืนดังนั้นแทนที่จะส่งคืนnullคุณสามารถส่งคืนได้emptyMap()

มันทำให้รหัสของคุณง่ายขึ้นและป้องกัน NullPointerException


3

ส่วนใหญ่เวลาที่เราจะใช้ในการสร้างใหม่constructor empty mapแต่Collections methodsข้อเสนอสองสามข้อได้เปรียบในการสร้างการempty mapใช้งานstatic method java.util.Collections.emptyMap()

  1. มันกระชับมากขึ้นเพราะคุณไม่จำเป็นต้องพิมพ์ประเภททั่วไปของคอลเลกชันอย่างชัดเจน - โดยทั่วไปจะอนุมานจากบริบทของการเรียกเมธอด

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


2

ทำไมฉันถึงต้องการคอลเลคชันที่ไม่เปลี่ยนรูป ประเด็นคืออะไร?

ด้วยเหตุผลเดียวกันกับที่คุณจะใช้Collections.unmodifiableMap()ในบางจุด คุณต้องการส่งคืนอินสแตนซ์แผนที่ที่ส่งข้อยกเว้นหากผู้ใช้พยายามแก้ไข มันเป็นเพียงกรณีพิเศษ: แผนที่ว่างเปล่า


1

ทำไมฉันถึงต้องการคอลเลคชันที่ไม่เปลี่ยนรูป ประเด็นคืออะไร?

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

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