Bộ sưu tập.emptyMap () so với HashMap mới ()


143

Một số tình huống mà tôi có thể sử dụng là Collections.emptyMap()gì? Tài liệu nói rằng tôi có thể sử dụng phương pháp này nếu tôi muốn bộ sưu tập của mình là bất biến.

Tại sao tôi muốn có một bộ sưu tập trống bất biến? Điểm là gì?


12
+1 cho câu hỏi vì tôi chưa bao giờ thấy phương pháp tĩnh đó trước đây
Tim Bender

bạn cũng có thể có một cái nhìn về ống kính scala ống kính google scala . Bản đồ trống và Bản đồ bất biến có thể được sử dụng để tạo các đối tượng, là bất biến. blankMap là điểm ban đầu. Mỗi khi một yếu tố được thêm vào, bản đồ sẽ được thay thế bằng một bản đồ chứa thành phần cũ và các yếu tố mới. Vấn đề là, truy cập vào đối tượng là an toàn.
michael_s

1
Giống như Objective-C [NSArray array], nó trả về một đối tượng mặc dù không thể sử dụng được nhưng tồn tại. Vì vậy, bạn có thể chơi với nó như một đối tượng bình thường và không gặp lỗi.
Shane Hsu

Câu trả lời:


144

Từ hiệu quả Java , Item # 43 - "Return empty arrays or collections, not null"chứng tỏ trả lại một bộ sưu tập sản phẩm nào và thậm chí chứng tỏ sử dụng các emptyList(), emptySet()emptyMap()các phương pháp trên lớp Collections để có được một bộ sưu tập sản phẩm nào đó cũng có lợi ích bổ sung là không thay đổi. Từ mục số 15 "Minimize Mutability" .

Từ Bộ sưu tập-blankset-Bộ sưu tập-blankList-Bộ sưu tập

Đó là một loại thành ngữ lập trình. Điều này là dành cho những người không muốn biến null. Vì vậy, trước khi tập hợp được khởi tạo, họ có thể sử dụng tập hợp trống.

Lưu ý: Mã bên dưới chỉ là một ví dụ (thay đổi theo trường hợp sử dụng của bạn):

private Set myset = Collections.emptySet();

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

Những phương pháp này cung cấp một vài lợi thế:

  1. Chúng ngắn gọn hơn bởi vì bạn không cần phải loại ra một cách rõ ràng loại chung của bộ sưu tập - nó thường chỉ được suy ra từ ngữ cảnh của lệnh gọi phương thức.

  2. Chúng hiệu quả hơn vì chúng không bận tâm tạo ra các đối tượng mới; họ chỉ sử dụng lại một đối tượng trống rỗng và bất biến. Hiệu ứng này nói chung là rất nhỏ, nhưng đôi khi (rất hiếm khi) quan trọng.


15
+1 cho tham chiếu Java hiệu quả. Một nit: Tôi muốn khuyên bạn nên tham số hóa SetHashSettrong các ví dụ của bạn, vì toàn bộ quan điểm của emptySet()phương pháp và bạn bè (trái ngược với các hằng số, Collections.EMPTY_SETv.v.) là chúng chơi độc đáo với thuốc generic. Ngoài ra, việc sử dụng một tính năng (loại thô) đã bị từ chối vì Java 5 không phải là một công cụ hỗ trợ giảng dạy tốt.
Daniel Pryden

4
Tôi vẫn không bị thuyết phục ... Không phải toàn bộ vấn đề sử dụng Collectionthay vì nullđể tránh Exceptionsbị ném vào các hoạt động sau sao? Sử dụng một bộ sưu tập bất biến sẽ chỉ dẫn đến một số loại ngoại lệ khác mà tôi tưởng tượng. Và gán nulllà chắc chắn không kém hiệu quả hơn so với gán một hằng số bất biến.
fgysin phục hồi Monica

14
@fgysin: Nếu bạn có API nơi khách hàng dự kiến ​​sẽ sửa đổi bộ sưu tập, thì có, việc trả lại bộ sưu tập không thay đổi sẽ không có ý nghĩa gì. Nhưng nếu bạn có API nơi bạn trả lại bộ sưu tập mà khách hàng không được sửa đổi và chỉ nên lặp đi lặp lại, thì việc trả lại chế độ xem cho bộ sưu tập bên dưới có ý nghĩa hoàn hảo để đảm bảo rằng máy khách "xấu" không vô tình sửa đổi bộ sưu tập được sở hữu bởi bạn. Trả lại một bộ sưu tập trống thay vì null có nghĩa là khách hàng của bạn không phải thực hiện kiểm tra null trước khi sử dụng bộ sưu tập, làm cho mã máy khách rõ ràng hơn.
Jean Hominal

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

5
Trong ví dụ của bạn, bạn đang kiểm tra rõ ràng cho tập hợp trống và sử dụng nó làm giá trị sentinel và lớp của bạn có thể thay đổi. Ví dụ nhỏ của bạn sử dụng sentinels và khả năng biến đổi, đó chính xác là những gì Collections.emptyset () đang cố gắng ngăn chặn.
Marc O'Morain

33

Theo kinh nghiệm cá nhân của tôi, phải thừa nhận rằng, rất hữu ích trong trường hợp API yêu cầu bộ sưu tập các tham số, nhưng bạn không có gì để cung cấp. Ví dụ: bạn có thể có một API trông giống như thế này và không cho phép các tham chiếu null:

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

Nếu bạn có một truy vấn không lấy bất kỳ tham số nào, chắc chắn sẽ hơi lãng phí khi tạo HashMap, liên quan đến việc phân bổ một mảng, khi bạn có thể chuyển vào 'Bản đồ trống', một cách hiệu quả là hằng số, cách nó được triển khai trong java.util.Collections.


22

Tại sao tôi muốn có một bộ sưu tập trống bất biến? Điểm là gì?

Có hai khái niệm khác nhau ở đây có vẻ lạ khi được xem cùng nhau. Nó có ý nghĩa hơn khi bạn đối xử với hai khái niệm riêng biệt.

  • Đầu tiên, bạn nên sử dụng một bộ sưu tập bất biến hơn là một bộ sưu tập có thể thay đổi bất cứ nơi nào có thể. Những lợi ích của sự bất biến được ghi lại ở những nơi khác .

  • Thứ hai, bạn nên sử dụng một bộ sưu tập trống hơn là sử dụng null làm trọng tâm. Điều này cũng được mô tả ở đây . Điều đó có nghĩa là bạn sẽ có mã sạch hơn, dễ hiểu hơn, với ít chỗ hơn để ẩn lỗi.

Vì vậy, khi bạn có mã yêu cầu bản đồ, tốt hơn là vượt qua một bản đồ trống thay vì null để chỉ ra sự vắng mặt của bản đồ. Và hầu hết thời gian khi bạn đang sử dụng bản đồ, tốt hơn là sử dụng bản đồ bất biến. Vì vậy, đây là lý do tại sao có một chức năng tiện lợi để tạo ra một bản đồ trống bất biến.


8

Có một vài trường hợp bạn muốn sử dụng bản đồ, danh sách, bộ hoặc các loại bộ sưu tập bất biến khác.

Trường hợp sử dụng đầu tiên và được cho là quan trọng nhất là bất cứ khi nào bạn trả về kết quả của truy vấn hoặc tính toán sẽ trả về một tập hợp (hoặc danh sách hoặc bản đồ) kết quả, bạn nên sử dụng cấu trúc dữ liệu không thay đổi.

Trong trường hợp này, tôi rất thích trả về các phiên bản bất biến của các phiên bản này vì điều này phản ánh tính bất biến thực tế của một kết quả tính toán rõ ràng hơn - bất kể bạn làm gì với dữ liệu sau này, không nên đặt kết quả bạn nhận được từ truy vấn của mình thay đổi.

Trường hợp sử dụng phổ biến thứ hai là khi bạn cần cung cấp một đối số làm đầu vào cho một phương thức hoặc dịch vụ. Trừ khi bạn mong đợi bộ sưu tập đầu vào được sửa đổi bởi dịch vụ hoặc phương thức (thường là một ý tưởng thiết kế thực sự tồi tệ), chuyển qua một bộ sưu tập bất biến thay vì bộ sưu tập có thể thay đổi có thể là lựa chọn hợp lý và an toàn trong nhiều trường hợp.

Tôi nghĩ về nó như là quy ước "vượt qua giá trị" .

Tổng quát hơn - đó là một cách thực hành hợp lý để sử dụng cấu trúc dữ liệu bất biến mỗi khi dữ liệu vượt qua ranh giới mô-đun hoặc dịch vụ. Điều này làm cho lý do dễ dàng hơn nhiều về sự khác biệt giữa đầu vào / đầu ra (không thay đổi) và trạng thái bên trong có thể thay đổi.

Vì tác dụng phụ rất có lợi của việc này là tăng tính bảo mật và an toàn luồng cho các mô-đun / dịch vụ của bạn và đảm bảo phân tách mối quan tâm rõ ràng hơn.

Một lý do chính đáng khác để sử dụng Collections.empty*()các phương pháp là sự thiếu rõ ràng đáng chú ý của chúng. Trong thời kỳ tiền Java7, nếu bạn có một bộ sưu tập chung, bạn phải rắc các chú thích loại chung ở khắp mọi nơi.

Chỉ cần so sánh hai tuyên bố này:

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

đấu với:

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

Loại thứ hai rõ ràng sẽ thắng dễ dàng theo hai cách quan trọng:

  1. Trong tuyên bố đầu tiên, toàn bộ việc khởi tạo một bản đồ trống bị chôn vùi trong tiếng ồn của các khai báo kiểu chung, làm cho một tuyên bố cơ bản tầm thường khó hiểu hơn nhiều so với yêu cầu.
  2. Ngoài việc thiếu chú ý loại chung chung ở phía bên phải, phiên bản thứ hai nêu rõ rằng bản đồ được khởi tạo thành một bản đồ trống. Ngoài ra - biết rằng phương thức này trả về một bản đồ bất biến, giờ đây tôi dễ dàng tìm thấy nơi fooBarMapđang được gán một giá trị không trống khác chỉ bằng cách tìm kiếm /fooBarMap =/.

5

Đối với một, bạn có thể nhận được với chia sẻ tham khảo. Mộtnew HashMap() vv sẽ yêu cầu một đối tượng được phân bổ và có thể một số yếu tố bổ sung để giữ dữ liệu, nhưng bạn chỉ cần một bản sao của bộ sưu tập trống bất biến (danh sách, bộ, bản đồ hoặc bất kỳ yếu tố nào khác). Điều này làm cho nó trở thành một lựa chọn rõ ràng khi một phương thức bạn đang gọi cần chấp nhận Bản đồ nhưng không cần chỉnh sửa nó.

Tôi khuyên bạn nên kiểm tra Java hiệu quả của Josh Bloch , trong đó liệt kê một số thuộc tính rất hay của các đối tượng không thay đổi (bao gồm cả an toàn luồng).


3

Nó có thể hữu ích khi bạn có một hàm trả về immutable collectionvà trong một số trường hợp không có dữ liệu để trả về thay vì trả vềnull bạn có thể trả vềemptyMap()

Nó làm cho mã của bạn dễ dàng hơn và ngăn chặn NullPointerException


3

Hầu hết thời gian chúng tôi sử dụng một constructorđể tạo mới empty map. Nhưng việc Collections methodscung cấp một vài lợi thế để tạo ra việc empty mapsử dụngstatic method java.util.Collections.emptyMap()

  1. Chúng ngắn gọn hơn bởi vì bạn không cần phải loại ra một cách rõ ràng loại chung của bộ sưu tập - nó thường chỉ được suy ra từ ngữ cảnh của lệnh gọi phương thức.

  2. Chúng hiệu quả hơn vì chúng không bận tâm tạo ra các đối tượng mới; họ chỉ sử dụng lại một đối tượng trống rỗng và bất biến. Hiệu ứng này nói chung là rất nhỏ, nhưng đôi khi (rất hiếm khi) quan trọng.


2

Tại sao tôi muốn có một bộ sưu tập trống bất biến? Điểm là gì?

Vì lý do tương tự, bạn sẽ sử dụng Collections.unmodifiableMap()tại một số điểm. Bạn muốn trả về một bản đồ Map ném ngoại lệ nếu người dùng cố gắng sửa đổi nó. Đó chỉ là một trường hợp đặc biệt: Bản đồ trống.


1

Tại sao tôi muốn có một bộ sưu tập trống bất biến? Điểm là gì?

Vì những lý do tương tự tại sao bạn có thể muốn các đối tượng bất biến. Chủ yếu bởi vì bạn có thể ngủ an toàn vào ban đêm với kiến ​​thức rằng nhiều luồng có thể truy cập vào cùng một thể hiện của một đối tượng và tất cả chúng sẽ được nhìn thấy cùng một giá trị. Không có mục nào trong bộ sưu tập vẫn là một giá trị hợp lệ mà bạn muốn duy trì.

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.