Tạo Danh sách có thể thay đổi từ mảng?


84

Tôi có một mảng mà tôi muốn chuyển thành một List, để sửa đổi nội dung của mảng.

Stack Overflow có rất nhiều câu hỏi / câu trả lời rằng địa chỉ Arrays.asList()và làm thế nào nó chỉ cung cấp một cái nhìn Danh sách các mảng cơ bản, và làm thế nào cố gắng để thao tác Danh sách kết quả sẽ thường ném một UnsupportedOperationExceptionnhư các phương pháp sử dụng để thao tác danh sách (ví dụ add(), remove()vv) là không được thực hiện bởi việc triển khai Danh sách được cung cấp bởi Arrays.asList().

Nhưng tôi không thể tìm thấy ví dụ về cách biến một mảng thành một Danh sách có thể thay đổi. Tôi cho rằng tôi có thể lặp qua mảng và put()từng giá trị vào một Danh sách mới, nhưng tôi đang tự hỏi liệu có một giao diện tồn tại để thực hiện việc này cho tôi hay không.

Câu trả lời:


122

Một cách đơn giản:

Foo[] array = ...;
List<Foo> list = new ArrayList<Foo>(Arrays.asList(array));

Điều đó sẽ tạo ra một danh sách có thể thay đổi - nhưng nó sẽ là bản sao của mảng ban đầu. Thay đổi danh sách sẽ không thay đổi mảng. Tất nhiên, bạn có thể sao chép lại sau bằng cách sử dụng toArray.

Nếu bạn muốn tạo chế độ xem có thể thay đổi trên một mảng, tôi tin rằng bạn sẽ phải tự triển khai điều đó.


2
Arrays.asList trả một cái nhìn vào một mảng, với những phương pháp đột biến được hỗ trợ mà không ảnh hưởng đến kích thước của danh sách
Timo Westkämper

1
@ jon-tenset Tôi biết, tôi chỉ nói rằng Arrays.asList cung cấp cho bạn một danh sách được hỗ trợ bằng mảng với khả năng thay đổi hạn chế, nếu bạn cần thêm / bớt / chèn thì gói ArrayList là một cách tiếp cận tốt hơn.
Timo Westkämper

4
Java cần làm rõ ràng khả năng thay đổi / tính bất biến trong tất cả các phương thức nhà máy tĩnh này. Thật tiếc khi phát hiện ra rằng bạn đã tạo ra một điều bất biến trong thời gian chạy.
dustinevan

1
@dustinevan: Các tài liệu được khá rõ ràng IMO: "Returns một danh sách kích thước cố định được hỗ trợ bởi các mảng được chỉ định (thay đổi vào danh sách trả lại. 'ghi thông qua' để mảng.)"
Jon Skeet

1
@JonSkeet không muốn lãng phí thời gian của bạn - cảm ơn vì tất cả những gì bạn làm. Tôi chỉ muốn bỏ phiếu để rõ ràng hơn về tên của chính họ - tôi chắc chắn rằng các tài liệu đều rõ ràng. Một số người trong chúng ta đang nhảy múa giữa các ngôn ngữ và điều này khá rõ ràng trong các ngôn ngữ khác.
dustinevan

21

Và nếu bạn đang sử dụng API bộ sưu tập của Google

Lists.newArrayList(myArray)

1
Đây là câu trả lời ngắn gọn nhất. Cảm ơn.
eugene82

2
Ngay cả bản thân Guava cũng khuyên bạn nên sử dụng một trong hai new ArrayList<>(Arrays.asList(...))- javadoc cho phương thức này ngụ ý rằng nó sẽ không còn được dùng nữa vì nó không đủ hữu ích.
Đón Logan

2020 và vẫn không bị phản đối. Nhảy vào!
markthegrea

11

Mã đơn giản này sử dụng API luồng có trong Java 8 tạo một danh sách (hoặc chế độ xem) có thể thay đổi chứa các phần tử trong mảng của bạn:

Foo[] array = ...;
List<Foo> list = Stream.of(array).collect(Collectors.toCollection(ArrayList::new));

Hoặc, hợp lệ như nhau:

List<Foo> list = Arrays.stream(array).collect(Collectors.toCollection(ArrayList::new));

4

Nếu bạn đang sử dụng Bộ sưu tập Eclipse (trước đây là Bộ sưu tập GS ), bạn có thể sử dụng FastList.newListWith(...)hoặc FastList.wrapCopy(...).

Cả hai phương thức đều lấy varargs, vì vậy bạn có thể tạo mảng nội dòng hoặc truyền vào một mảng hiện có.

MutableList<Integer> list1 = FastList.newListWith(1, 2, 3, 4);

Integer[] array2 = {1, 2, 3, 4};
MutableList<Integer> list2 = FastList.newListWith(array2);

Sự khác biệt giữa hai phương pháp là liệu mảng có được sao chép hay không. newListWith()không sao chép mảng và do đó mất thời gian liên tục. Bạn nên tránh sử dụng nó nếu bạn biết mảng có thể bị thay đổi ở nơi khác.

Integer[] array2 = {1, 2, 3, 4};
MutableList<Integer> list2 = FastList.newListWith(array2);
array2[1] = 5;
Assert.assertEquals(FastList.newListWith(1, 5, 3, 4), list2);

Integer[] array3 = {1, 2, 3, 4};
MutableList<Integer> list3 = FastList.wrapCopy(array3);
array3[1] = 5;
Assert.assertEquals(FastList.newListWith(1, 2, 3, 4), list3);

Lưu ý: Tôi là người cam kết cho Bộ sưu tập Eclipse.


1
Đó là một API bộ sưu tập tuyệt vời mà bạn đã có ở đó. Điều đầu tiên tôi đã thấy có thể cám dỗ tôi tránh xa các triển khai của chính mình ... chỉ có điều dường như còn thiếu mà tôi thấy nói chung là hữu ích là một triển khai tập hợp được sắp xếp được hỗ trợ bởi một mảng (mà tôi thấy là hiệu quả hơn nhiều so với một triển khai dựa trên cây cho một trong hai dữ liệu hiếm khi được sửa đổi hoặc cho các tập hợp có thể được sửa đổi thường xuyên nhưng thường chứa ít hơn 10 phần tử).
Jules

0
myNewArrayList = new ArrayList<>(Arrays.asList(myArray));

1
@JonSkeet Tôi biết rằng bình luận của bạn là từ năm 2012 và bây giờ tôi rất tin tưởng vào tương lai, nhưng tôi cho rằng nhận xét này không được tổ chức tốt khi xem xét IDE của tôi cụ thể là gạch chân và nói "này, đừng khai báo điều này với một loại đã khai báo. bạn không cần nó ở đó "?
Brent Thoenen

1
@BrentThoenen: Tôi không hiểu nhận xét của bạn. Bạn có nhận thấy rằng bình luận của tôi đề cập đến bản sửa đổi 1, được sử dụng myNewArrayList = new ArrayList(...), tức là loại thô? Có sự khác biệt giữa "sử dụng toán tử kim cương để cho phép trình biên dịch làm việc với đối số kiểu" và "sử dụng kiểu thô".
Jon Skeet

1
Tôi đã đăng câu trả lời này và sống trong quên lãng suốt thời gian qua rằng chính @JonSkeet đã nhận xét về câu trả lời của tôi. Cảm ơn Brent đã bình luận.
Sid

@JonSkeet ahh, tệ quá. tôi đã không kiểm tra bản sửa đổi mà bạn đang bình luận. Tôi đã đưa ra một giả định sai trong java 2012 đó cũng giả định rằng toán tử kim cương trống cũng là một kiểu thô. Đó là của tôi b. cảm ơn vì câu trả lời!
Brent Thoenen,

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.