Collections.emptyList () กับอินสแตนซ์ใหม่


241

ในทางปฏิบัติมันเป็นดีกว่าที่จะกลับรายการที่ว่างเปล่าเช่นนี้ :

return Collections.emptyList();

หรือชอบนี้ :

return new ArrayList<Foo>();

หรือสิ่งนี้ขึ้นอยู่กับสิ่งที่คุณจะทำกับรายการที่ส่งคืน?

คำตอบ:


300

ความแตกต่างที่สำคัญคือการCollections.emptyList()ส่งคืนรายการที่ไม่เปลี่ยนรูปนั่นคือรายการที่คุณไม่สามารถเพิ่มองค์ประกอบ (เช่นเดียวกับที่List.of()แนะนำใน Java 9)

ในกรณีที่หายากที่คุณไม่ต้องการปรับเปลี่ยนรายการกลับCollections.emptyList()และList.of()จึงไม่ได้ทางเลือกที่ดี

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


นอกจากนี้emptyList() อาจไม่สร้างวัตถุใหม่ด้วยการโทรแต่ละครั้ง

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

การดำเนินการตามemptyListลักษณะดังต่อไปนี้:

public static final <T> List<T> emptyList() {
    return (List<T>) EMPTY_LIST;
}

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


4
ดังนั้นจะCollections.emptyList()เหมาะกว่าสำหรับสมมติว่าตรวจสอบข้อผิดพลาดและชอบ?
MRE

1
ลูกค้า API จะไม่ได้รับNullPointerExceptionโดยการกลับแทนCollections.emptyList() null
realPK

@PK_J ให้ความสำคัญ Collections.emptyList()สามารถทำซ้ำได้และส่งคืนความยาวดังนั้นจึงสามารถใช้ในการวนซ้ำได้โดยไม่มีข้อยกเว้น
ndm13

สิ่งที่เกี่ยวกับการใช้งานList.of()?

4
@AJW ใช่ แต่เมื่อเทียบกับnew ArrayList<>()มันทำให้การตัดสินใจออกแบบชัดเจนขึ้น องค์ประกอบจะไม่ถูกเพิ่มลงในรายการนี้
aioobe

51

เริ่มต้นด้วย Java 5.0 คุณสามารถระบุประเภทขององค์ประกอบในคอนเทนเนอร์:

Collections.<Foo>emptyList()

ฉันเห็นด้วยกับคำตอบอื่น ๆ ที่สำหรับกรณีที่คุณต้องการส่งคืนรายการว่างที่ยังคงว่างเปล่าคุณควรใช้วิธีนี้


38
เริ่มต้นด้วย Java 7 คุณสามารถให้คอมไพเลอร์อนุมานพารามิเตอร์ type ของการเรียกใช้เมธอดทั่วไปจากประเภทเป้าหมาย:List<Foo> list = Collections.emptyList()
Paul Jackson

28

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

กลับจะสร้างตัวอย่างใหม่ของวัตถุจึงมีค่าใช้จ่ายเพิ่มเติมเล็กน้อยมากที่เกี่ยวข้องกับมันซึ่งอาจทำให้คุณมีเหตุผลที่จะใช้งานnew ArrayList<Foo> Collections.emptyListฉันชอบที่จะใช้emptyListเพราะอ่านได้มากกว่า


14

ระวังให้ดี หากคุณกลับมาCollections.emptyList()แล้วลองทำการเปลี่ยนแปลงบางอย่างกับมันเช่นadd()หรือ smth เช่นนั้นคุณจะมีUnsupportedOperationException()เพราะCollections.emptyList()ส่งกลับวัตถุที่ไม่เปลี่ยนรูป


7

ฉันจะไปด้วยCollections.emptyList()หากรายการที่ส่งคืนไม่ได้ถูกแก้ไขในทางใดทางหนึ่ง (เนื่องจากรายการไม่เปลี่ยนรูป) มิฉะนั้นฉันจะไปกับตัวเลือก 2

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


3

ใช้ Collections.emptyList () ถ้าคุณต้องการตรวจสอบให้แน่ใจว่ารายการที่ส่งคืนจะไม่ถูกแก้ไข นี่คือสิ่งที่ส่งคืนเมื่อเรียก emptyList ():

/**
 * The empty list (immutable). 
 */
public static final List EMPTY_LIST = new EmptyList();

ฉันมาถึงที่นี่เพื่อค้นหาว่าการโทรCollections.emptyList()มีต้นทุนการก่อสร้าง การดูรายละเอียดการใช้งาน (แม้ว่าอาจจะไม่เหมือนกันใน JVM ทั้งหมด) ยืนยันว่าไม่เป็นเช่นนั้น @Atul ซึ่ง JVM มาจากไหน
wjl

2

คำตอบที่ได้รับเน้นความจริงที่ว่าemptyList()ผลตอบแทนที่ไม่เปลี่ยนรูปListแต่ไม่ได้ให้ทางเลือก ตัวสร้างArrayList(int initialCapacity)กรณีพิเศษ0ดังนั้นการส่งคืนnew ArrayList<>(0)แทนที่จะnew ArrayList<>()เป็นโซลูชันที่ทำงานได้:

/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

[ ... ]

/**
 * Constructs an empty list with the specified initial capacity.
 *
 * @param  initialCapacity  the initial capacity of the list
 * @throws IllegalArgumentException if the specified initial capacity
 *         is negative
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

(แหล่งที่มาจาก Java 1.8.0_72)


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

1
ในขณะที่ฉันพยายามเน้นข้อความของฉัน ( อาจเป็นไปได้ ): ทุกอย่างขึ้นอยู่กับกรณีการใช้งานของคุณ ฉันจะโดยทั่วไปทั้งสองกลับไม่แน่นอนหรือคอลเลกชัน unmutable ไม่ผสมขึ้นอยู่กับสภาพอากาศที่พวกเขาจะว่างหรือไม่ และเพื่อตอบโต้ "การเรียกร้องช้าลงมาก": นี่คือการดำเนินการในปัจจุบัน
René

โอ้มนุษย์ดูฉันที่อ้างถึงรุ่นใหญ่ของ JDK 2 ล้าสมัย ดังนั้น java8 หลีกเลี่ยงปัญหาคอขวดทั้งหมดโดยการกระโดดไปที่ความจุเริ่มต้นจากขนาดเริ่มต้นที่ 0 ขออภัยฉันผิด
Patrick M
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.