Bộ sưu tập.emptyList () so với phiên bản mới


241

Trong thực tế, tốt hơn là trả về một danh sách trống như thế này :

return Collections.emptyList();

Hoặc như thế này :

return new ArrayList<Foo>();

Hay điều này hoàn toàn phụ thuộc vào những gì bạn sẽ làm với danh sách được trả về?

Câu trả lời:


300

Sự khác biệt chính là Collections.emptyList()trả về một danh sách bất biến , tức là một danh sách mà bạn không thể thêm các phần tử. (Áp dụng tương tự với phần được List.of()giới thiệu trong Java 9.)

Trong trường hợp hiếm hoi, nơi bạn làm muốn thay đổi danh sách trở về, Collections.emptyList()List.of()được như vậy, không một sự lựa chọn tốt.

Tôi muốn nói rằng việc trả lại một danh sách bất biến là hoàn toàn tốt (và thậm chí là cách ưa thích) miễn là hợp đồng (tài liệu) không nêu rõ ràng khác nhau.


Ngoài ra, emptyList() có thể không tạo đối tượng mới với mỗi cuộc gọi.

Việc triển khai phương thức này không cần tạo một đối tượng List riêng cho mỗi cuộc gọi. Sử dụng phương pháp này có thể có chi phí tương đương với việc sử dụng trường cùng tên. (Không giống như phương pháp này, trường không cung cấp loại an toàn.)

Việc thực hiện emptyListngoại hình như sau:

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

Vì vậy, nếu phương thức của bạn (trả về một danh sách trống) được gọi rất thường xuyên, phương pháp này thậm chí có thể mang lại cho bạn hiệu năng tốt hơn một chút cả về CPU và bộ nhớ.


4
Vì vậy, sẽ Collections.emptyList()phù hợp hơn cho giả sử, kiểm tra lỗi và tương tự?
MRE

1
Các khách hàng API sẽ không nhận được NullPointerExceptionbằng cách quay lại Collections.emptyList()thay vì null.
realPK

@PK_J làm cho một điểm quan trọng. Collections.emptyList()có thể lặp lại và trả về độ dài, vì vậy nó có thể được sử dụng cho các vòng lặp mà không có ngoại lệ được ném ra.
ndm13

Còn việc sử dụng List.of()thì sao?

4
@AJW, vâng. Nhưng so với, nói, new ArrayList<>()nó cũng làm cho quyết định thiết kế rõ ràng; các yếu tố sẽ không được thêm vào danh sách này.
aioobe

51

Bắt đầu với Java 5.0, bạn có thể chỉ định loại phần tử trong vùng chứa:

Collections.<Foo>emptyList()

Tôi đồng tình với các phản hồi khác rằng trong trường hợp bạn muốn trả về một danh sách trống mà vẫn trống, bạn nên sử dụng phương pháp này.


38
Bắt đầu với Java 7, bạn có thể cho phép trình biên dịch suy ra tham số loại của lời gọi phương thức chung từ loại mục tiêu:List<Foo> list = Collections.emptyList()
Paul Jackson

28

Collections.emptyList là bất biến nên có sự khác biệt giữa hai phiên bản nên bạn phải xem xét người dùng về giá trị được trả về.

Việc trả về new ArrayList<Foo>luôn tạo ra một thể hiện mới của đối tượng để nó có thêm một chi phí rất nhỏ liên quan đến nó có thể cho bạn một lý do để sử dụng Collections.emptyList. Tôi thích sử dụng emptyListchỉ vì nó dễ đọc hơn.


14

Hãy cẩn thận mặc dù. Nếu bạn quay lại Collections.emptyList()và sau đó cố gắng thực hiện một số thay đổi với nó như thế add()hoặc smth như thế, bạn sẽ có một UnsupportedOperationException()Collections.emptyList()trả về một đối tượng bất biến.


7

Tôi sẽ đi cùng Collections.emptyList()nếu danh sách trả về không bị sửa đổi theo bất kỳ cách nào (vì danh sách này là bất biến), nếu không tôi sẽ đi với tùy chọn 2.

Lợi ích của việc Collections.emptyList()là cùng một thể hiện tĩnh được trả về mỗi lần và do đó không có việc tạo cá thể xảy ra cho mỗi cuộc gọi.


3

Sử dụng Collections.emptyList () nếu bạn muốn đảm bảo rằng danh sách trả về không bao giờ được sửa đổi. Đây là những gì được trả về khi gọi blankList ():

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

Tôi đến đây cố gắng tìm hiểu xem cuộc gọi Collections.emptyList()có chi phí xây dựng không. Xem chi tiết triển khai (mặc dù có lẽ không giống nhau trên tất cả các JVM) xác nhận rằng nó không. @Atul, JVM này là từ đâu?
wjl

2

Các câu trả lời đưa ra nhấn mạnh thực tế là emptyList()trả về một bất biến Listnhưng không đưa ra giải pháp thay thế. Các ArrayList(int initialCapacity)trường hợp đặc biệt của Trình xây dựng 0để quay lại new ArrayList<>(0)thay vì new ArrayList<>()cũng có thể là một giải pháp khả thi:

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

(nguồn từ Java 1.8.0_72)


Tôi không đồng ý với cách tiếp cận của bạn. Bạn tiết kiệm một chút bộ nhớ và CPU khi khởi tạo, nhưng nếu danh sách bạn trả về đã bị sửa đổi, bạn sẽ mất thời gian đó khi danh sách phân bổ lại một mảng mới. Nếu nhiều yếu tố được thêm vào danh sách theo thời gian, điều này có thể chồng chất thêm vào một nút cổ chai hiệu suất do tốc độ tăng trưởng chậm hơn nhiều . Tôi rất thích tuân theo quy ước của một danh sách trống không thể thay đổi hoặc một danh sách có thể sử dụng, có thể sửa đổi.
Patrick M

1
Như tôi đã cố gắng nhấn mạnh với từ ngữ của tôi ( có thể khả thi ): tất cả phụ thuộc vào trường hợp sử dụng của bạn. Tôi sẽ thường hoặc trở lại có thể thay đổi hoặc unmutable Collections, không phải là một hỗn hợp phụ thuộc vào thời tiết họ trống rỗng hay không. Và để chống lại "yêu cầu chậm hơn nhiều": đây là triển khai hiện tại.
René

Ôi trời, nhìn tôi trích dẫn JDK 2 phiên bản chính đã lỗi thời. Vì vậy, java8 đã tránh được nút cổ chai hoàn toàn bằng cách nhảy lên dung lượng mặc định từ kích thước ban đầu là 0. Xin lỗi tôi đã sai.
Patrick M
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.