Collections.emptyList () vs. instance baru


241

Dalam praktiknya, apakah lebih baik mengembalikan daftar kosong seperti ini :

return Collections.emptyList();

Atau seperti ini :

return new ArrayList<Foo>();

Atau apakah ini sepenuhnya tergantung pada apa yang akan Anda lakukan dengan daftar yang dikembalikan?

Jawaban:


300

Perbedaan utama adalah bahwa Collections.emptyList()mengembalikan daftar yang tidak dapat diubah , yaitu daftar yang Anda tidak dapat menambahkan elemen. (Hal yang sama berlaku untuk yang List.of()diperkenalkan di Jawa 9.)

Dalam kasus yang jarang terjadi di mana Anda tidak ingin mengubah daftar kembali, Collections.emptyList()dan List.of()dengan demikian tidak seorang pilihan yang baik.

Saya akan mengatakan bahwa mengembalikan daftar yang tidak dapat diubah adalah baik-baik saja (dan bahkan cara yang disukai) selama kontrak (dokumentasi) tidak secara eksplisit menyatakan berbeda.


Selain itu, emptyList() mungkin tidak membuat objek baru dengan setiap panggilan.

Implementasi metode ini tidak perlu membuat objek Daftar terpisah untuk setiap panggilan. Menggunakan metode ini cenderung memiliki biaya yang sebanding dengan menggunakan bidang seperti-bernama. (Tidak seperti metode ini, bidang tidak menyediakan keamanan tipe.)

Implementasi emptyListtampilannya sebagai berikut:

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

Jadi jika metode Anda (yang mengembalikan daftar kosong) disebut sangat sering, pendekatan ini bahkan dapat memberi Anda kinerja yang sedikit lebih baik baik dari segi CPU dan memori.


4
Jadi, akan Collections.emptyList()lebih cocok untuk katakanlah, pengecekan error dan sejenisnya?
mre

1
Klien API tidak akan mendapatkannya NullPointerExceptiondengan kembali Collections.emptyList()sebagai gantinya null.
realPK

@PK_J membuat poin penting. Collections.emptyList()iterable dan mengembalikan panjang, sehingga dapat digunakan untuk loop tanpa kecuali dilemparkan.
ndm13

bagaimana dengan menggunakan List.of()?

4
@ AJW, ya. Tetapi dibandingkan dengan, katakanlah, new ArrayList<>()itu juga membuat keputusan desain jelas; elemen tidak akan ditambahkan ke daftar ini.
aioobe

51

Dimulai dengan Java 5.0 Anda dapat menentukan jenis elemen dalam wadah:

Collections.<Foo>emptyList()

Saya setuju dengan tanggapan lain bahwa untuk kasus di mana Anda ingin mengembalikan daftar kosong yang tetap kosong, Anda harus menggunakan pendekatan ini.


38
Dimulai dengan Java 7, Anda dapat membiarkan kompiler menyimpulkan parameter tipe dari pemanggilan metode generik dari tipe target:List<Foo> list = Collections.emptyList()
Paul Jackson

28

Collections.emptyList tidak berubah sehingga ada perbedaan antara kedua versi sehingga Anda harus mempertimbangkan pengguna dari nilai yang dikembalikan.

Kembali new ArrayList<Foo>selalu menciptakan contoh baru objek sehingga memiliki biaya tambahan yang sangat sedikit yang terkait dengannya yang dapat memberi Anda alasan untuk menggunakannya Collections.emptyList. Saya suka menggunakan emptyListhanya karena lebih mudah dibaca.


14

Berhati-hatilah. Jika Anda kembali Collections.emptyList()dan kemudian mencoba melakukan beberapa perubahan dengan suka add()atau pertengkaran seperti itu, Anda akan memiliki UnsupportedOperationException()karena Collections.emptyList()mengembalikan objek yang tidak dapat diubah.


7

Saya akan pergi dengan Collections.emptyList()jika daftar yang dikembalikan tidak diubah dengan cara apa pun (karena daftar tidak berubah), kalau tidak saya akan pergi dengan opsi 2.

Manfaatnya Collections.emptyList()adalah bahwa instance statis yang sama dikembalikan setiap kali dan sehingga tidak ada pembuatan instance yang terjadi untuk setiap panggilan.


3

Gunakan Collections.emptyList () jika Anda ingin memastikan bahwa daftar yang dikembalikan tidak pernah dimodifikasi. Inilah yang dikembalikan saat memanggil blankList ():

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

Saya tiba di sini mencoba mencari tahu apakah menelepon Collections.emptyList()memiliki biaya konstruksi. Melihat detail implementasi (walaupun mungkin tidak sama pada semua JVM) mengkonfirmasi bahwa itu tidak. @ Amul, dari mana JVM ini?
wjl

2

Jawaban yang diberikan menekankan fakta bahwa emptyList()mengembalikan yang kekal Listtetapi tidak memberikan alternatif. Kasus ArrayList(int initialCapacity)khusus Constructor 0jadi kembali dan new ArrayList<>(0)bukan new ArrayList<>()juga bisa menjadi solusi yang layak:

/**
 * 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);
    }
}

(sumber dari Java 1.8.0_72)


Saya tidak setuju dengan pendekatan Anda. Anda menghemat sedikit memori dan CPU pada inisialisasi, tetapi jika daftar yang Anda kembalikan pernah dimodifikasi, Anda kehilangan waktu ketika daftar tersebut mengalokasikan kembali array baru. Jika banyak elemen ditambahkan ke daftar dari waktu ke waktu, ini dapat menumpuk menjadi lebih banyak hambatan kinerja karena tingkat pertumbuhan yang jauh lebih lambat . Saya lebih suka berpegang pada konvensi daftar kosong yang tidak dapat dimodifikasi atau daftar yang dapat digunakan dan dimodifikasi.
Patrick M

1
Ketika saya mencoba untuk menekankan dengan kata-kata saya ( mungkin layak ): itu semua tergantung pada kasus penggunaan Anda. Saya biasanya akan baik kembali bisa berubah atau unmutable Koleksi, bukan campuran tergantung pada cuaca mereka kosong atau tidak. Dan untuk melawan "klaim jauh lebih lambat": ini adalah implementasi saat ini.
René

Oh man, lihat aku mengutip JDK 2 versi utama ketinggalan zaman. Jadi java8 menghindari bottleneck sepenuhnya dengan melompat ke kapasitas default dari ukuran awal 0. Maaf saya sangat salah.
Patrick M
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.