Câu hỏi hỏi về cách biến một mảng thành một danh sách. Hầu hết các câu trả lời cho đến nay cho thấy cách tạo một danh sách mới có cùng nội dung với mảng hoặc được đề cập đến các thư viện của bên thứ ba. Tuy nhiên, có các tùy chọn đơn giản, tích hợp sẵn cho loại chuyển đổi này. Một số trong số chúng đã được phác thảo trong các câu trả lời khác (ví dụ: câu này ). Nhưng tôi muốn chỉ ra và xây dựng một số mức độ tự do nhất định cho việc thực hiện ở đây, và cho thấy những lợi ích tiềm năng, nhược điểm và cảnh báo.
Có ít nhất hai điểm khác biệt quan trọng cần thực hiện:
- Liệu danh sách kết quả sẽ là một khung nhìn trên mảng hay liệu nó có phải là một danh sách mới không
- Danh sách kết quả có nên sửa đổi hay không
Các tùy chọn sẽ được tóm tắt ở đây một cách nhanh chóng và một chương trình ví dụ hoàn chỉnh được hiển thị ở dưới cùng của câu trả lời này.
Tạo một danh sách mới so với việc tạo một khung nhìn trên mảng
Khi kết quả phải là một danh sách mới , thì một trong những cách tiếp cận từ các câu trả lời khác có thể được sử dụng:
List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());
Nhưng người ta nên xem xét những hạn chế của việc này: Một mảng có 1000000 long
giá trị sẽ chiếm khoảng 8 Megabyte bộ nhớ. Danh sách mới cũng sẽ chiếm khoảng 8 Megabyte. Và tất nhiên, toàn bộ mảng phải được duyệt qua khi tạo danh sách này. Trong nhiều trường hợp, việc tạo một danh sách mới đơn giản là không cần thiết. Thay vào đó, nó là đủ để tạo ra một khung nhìn trên mảng:
// This occupies ca. 8 MB
long array[] = { /* 1 million elements */ }
// Properly implemented, this list will only occupy a few bytes,
// and the array does NOT have to be traversed, meaning that this
// operation has nearly ZERO memory- and processing overhead:
List<Long> list = asList(array);
(Xem ví dụ ở phía dưới để biết cách thực hiện toList
phương thức)
Hàm ý của việc có một cái nhìn trên mảng là những thay đổi trong mảng sẽ hiển thị trong danh sách:
long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);
System.out.println(list.get(1)); // This will print 34
// Modify the array contents:
array[1] = 12345;
System.out.println(list.get(1)); // This will now print 12345!
May mắn thay, tạo một bản sao (nghĩa là mới danh sách không bị ảnh hưởng bởi các sửa đổi trong mảng) từ chế độ xem là không đáng kể:
List<Long> copy = new ArrayList<Long>(asList(array));
Bây giờ, đây là một bản sao thực sự, tương đương với những gì đạt được với giải pháp dựa trên luồng đã được trình bày ở trên.
Tạo chế độ xem có thể sửa đổi hoặc không thể thay đổi chế độ xem
Trong nhiều trường hợp, nó sẽ đủ khi danh sách chỉ đọc . Nội dung của danh sách kết quả thường sẽ không được sửa đổi, mà chỉ được chuyển qua xử lý xuôi dòng chỉ đọc danh sách.
Cho phép sửa đổi danh sách đặt ra một số câu hỏi:
long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);
list.set(2, 34567); // Should this be possible?
System.out.println(array[2]); // Should this print 34567?
list.set(3, null); // What should happen here?
list.add(99999); // Should this be possible?
Có thể tạo chế độ xem danh sách trên mảng có thể sửa đổi . Điều này có nghĩa là những thay đổi trong danh sách, như đặt giá trị mới tại một chỉ mục nhất định, sẽ hiển thị trong mảng.
Nhưng không thể tạo chế độ xem danh sách có thể thay đổi cấu trúc . Điều này có nghĩa là không thể thực hiện các thao tác ảnh hưởng đến kích thước của danh sách. Điều này chỉ đơn giản là vì kích thước của mảng bên dưới không thể thay đổi.
Sau đây là MCVE hiển thị các tùy chọn triển khai khác nhau và các cách có thể sử dụng danh sách kết quả:
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.RandomAccess;
public class PrimitiveArraysAsLists
{
public static void main(String[] args)
{
long array[] = { 12, 34, 56, 78 };
// Create VIEWS on the given array
List<Long> list = asList(array);
List<Long> unmodifiableList = asUnmodifiableList(array);
// If a NEW list is desired (and not a VIEW on the array), this
// can be created as well:
List<Long> copy = new ArrayList<Long>(asList(array));
System.out.println("array : " + Arrays.toString(array));
System.out.println("list : " + list);
System.out.println("unmodifiableList: " + unmodifiableList);
System.out.println("copy : " + copy);
// Modify a value in the array. The changes will be visible
// in the list and the unmodifiable list, but not in
// the copy.
System.out.println("Changing value at index 1 of the array...");
array[1] = 34567;
System.out.println("array : " + Arrays.toString(array));
System.out.println("list : " + list);
System.out.println("unmodifiableList: " + unmodifiableList);
System.out.println("copy : " + copy);
// Modify a value of the list. The changes will be visible
// in the array and the unmodifiable list, but not in
// the copy.
System.out.println("Changing value at index 2 of the list...");
list.set(2, 56789L);
System.out.println("array : " + Arrays.toString(array));
System.out.println("list : " + list);
System.out.println("unmodifiableList: " + unmodifiableList);
System.out.println("copy : " + copy);
// Certain operations are not supported:
try
{
// Throws an UnsupportedOperationException: This list is
// unmodifiable, because the "set" method is not implemented
unmodifiableList.set(2, 23456L);
}
catch (UnsupportedOperationException e)
{
System.out.println("Expected: " + e);
}
try
{
// Throws an UnsupportedOperationException: The size of the
// backing array cannot be changed
list.add(90L);
}
catch (UnsupportedOperationException e)
{
System.out.println("Expected: " + e);
}
try
{
// Throws a NullPointerException: The value 'null' cannot be
// converted to a primitive 'long' value for the underlying array
list.set(2, null);
}
catch (NullPointerException e)
{
System.out.println("Expected: " + e);
}
}
/**
* Returns an unmodifiable view on the given array, as a list.
* Changes in the given array will be visible in the returned
* list.
*
* @param array The array
* @return The list view
*/
private static List<Long> asUnmodifiableList(long array[])
{
Objects.requireNonNull(array);
class ResultList extends AbstractList<Long> implements RandomAccess
{
@Override
public Long get(int index)
{
return array[index];
}
@Override
public int size()
{
return array.length;
}
};
return new ResultList();
}
/**
* Returns a view on the given array, as a list. Changes in the given
* array will be visible in the returned list, and vice versa. The
* list does not allow for <i>structural modifications</i>, meaning
* that it is not possible to change the size of the list.
*
* @param array The array
* @return The list view
*/
private static List<Long> asList(long array[])
{
Objects.requireNonNull(array);
class ResultList extends AbstractList<Long> implements RandomAccess
{
@Override
public Long get(int index)
{
return array[index];
}
@Override
public Long set(int index, Long element)
{
long old = array[index];
array[index] = element;
return old;
}
@Override
public int size()
{
return array.length;
}
};
return new ResultList();
}
}
Đầu ra của ví dụ được hiển thị ở đây:
array : [12, 34, 56, 78]
list : [12, 34, 56, 78]
unmodifiableList: [12, 34, 56, 78]
copy : [12, 34, 56, 78]
Changing value at index 1 of the array...
array : [12, 34567, 56, 78]
list : [12, 34567, 56, 78]
unmodifiableList: [12, 34567, 56, 78]
copy : [12, 34, 56, 78]
Changing value at index 2 of the list...
array : [12, 34567, 56789, 78]
list : [12, 34567, 56789, 78]
unmodifiableList: [12, 34567, 56789, 78]
copy : [12, 34, 56, 78]
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.NullPointerException