Sao chép bộ Java


83

Có cách nào để sao chép a TreeSet? Đó là, nó có thể đi

Set <Item> itemList;
Set <Item> tempList;

tempList = itemList;

hay bạn phải thực hiện lặp đi lặp lại các bộ và sao chép từng bộ một?


7
tempList.addAll(itemList)
dhblah

Câu trả lời:


155

Một cách khác để làm điều này là sử dụng hàm tạo bản sao :

Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>(oldSet);

Hoặc tạo một tập hợp trống và thêm các phần tử:

Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>();
newSet.addAll(oldSet);

Không giống như clonenhững thứ này cho phép bạn sử dụng một lớp tập hợp khác, một bộ so sánh khác hoặc thậm chí điền từ một số loại tập hợp (không phải tập hợp) khác.


Lưu ý rằng kết quả của việc sao chép a Setlà một Settham chiếu mới có chứa các đối tượng là phần tử nếu là bản gốc Set. Bản thân các đối tượng phần tử không được sao chép hoặc nhân bản. Điều này phù hợp với cách mà các CollectionAPI Java được thiết kế để hoạt động: chúng không sao chép các đối tượng phần tử.


7

Với Java 8, bạn có thể sử dụng streamcollectsao chép các mục:

Set<Item> newSet = oldSet.stream().collect(Collectors.toSet());

Hoặc bạn có thể thu thập vào một ImmutableSet(nếu bạn biết rằng tập hợp không nên thay đổi):

Set<Item> newSet = oldSet.stream().collect(ImmutableSet.toImmutableSet());

8
Bạn có thể ... nhưng hàm tạo bản sao (v.v.) sẽ hiệu quả hơn nếu bạn chỉ đơn giản là sao chép một bộ sưu tập.
Stephen C

3

Hàm tạo bản sao được cung cấp bởi @Stephen C là cách để thực hiện khi bạn có một hàm Setbạn đã tạo (hoặc khi bạn biết nó đến từ đâu). Khi nó đến từ a Map.entrySet(), nó sẽ phụ thuộc vào việc Maptriển khai bạn đang sử dụng:

findbugs nói

Phương thức entrySet () được phép trả về một khung nhìn của Bản đồ bên dưới trong đó một đối tượng Entry đơn lẻ được sử dụng lại và trả về trong quá trình lặp. Kể từ Java 1.6, cả IdentityHashMap và EnumMap đều làm như vậy. Khi lặp qua một Bản đồ như vậy, giá trị Mục nhập chỉ có giá trị cho đến khi bạn chuyển sang lần lặp tiếp theo. Ví dụ, nếu bạn cố gắng chuyển một entrySet như vậy vào một phương thức addAll, mọi thứ sẽ trở nên sai lầm nghiêm trọng.

Như addAll()được gọi bởi hàm tạo bản sao, bạn có thể thấy mình có một Tập hợp chỉ một Mục nhập: mục cuối cùng.

MapMặc dù vậy, không phải tất cả các triển khai đều làm được điều đó, vì vậy nếu bạn biết việc triển khai của mình là an toàn về mặt đó, thì phương thức khởi tạo bản sao chắc chắn là cách để đi. Nếu không, bạn phải tự tạo các Entryđối tượng mới :

Set<K,V> copy = new HashSet<K,V>(map.size());
for (Entry<K,V> e : map.entrySet())
    copy.add(new java.util.AbstractMap.SimpleEntry<K,V>(e));

Chỉnh sửa: Không giống như các thử nghiệm tôi đã thực hiện trên Java 7 và Java 6u45 (nhờ Stephen C), nhận xét của findbugs dường như không còn phù hợp nữa. Nó có thể đã xảy ra trên các phiên bản Java 6 trước đó (trước u45) nhưng tôi không có bất kỳ điều gì để kiểm tra.


1
Điều này có dựa trên quan sát không? Nếu vậy, đó có vẻ như là một lỗi trong quá trình addAlltriển khai. FWIW, các Maptriển khai mà tôi đã xem xét đều lặp lại bộ mục nhập (ở một số cấp độ) và trích xuất khóa và giá trị cho mỗi bộ . Thực tế là trình lặp đặt mục nhập có thể trả về cùng một đối tượng mỗi lần không quan trọng. Trường hợp duy nhất tôi thấy khác biệt là EnumMapnơi mà chính phương thức tạo bản sao đang sao chép các mục nhập ... nếu bản đồ nguồn là một EnumMap.
Stephen C

1
@StephenC có vẻ như bạn nói đúng: các thử nghiệm tôi đã thực hiện IdentityHashMapkhông dẫn đến lỗi đó. Rắc rối hơn là tôi đã thử nghiệm nó trên Java 6u45 và cũng không có vấn đề gì. Tôi đoán đây là một lỗi trong findbugs (hoặc JDK mà họ dựa trên các quy tắc của họ ...). Tôi sẽ chỉnh sửa câu trả lời của mình.
Matthieu

3

Bắt đầu từ Java 10 :

Set<E> oldSet = Set.of();
Set<E> newSet = Set.copyOf(oldSet);

Set.copyOf()trả về một không thể thay đổi Setcó chứa các phần tử của giá trị đã cho Collection.

Giá trị đã cho Collectionkhông được có nullvà không được chứa bất kỳ nullphần tử nào .


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.