Pertanyaan yang diajukan tentang cara mengubah array menjadi daftar. Sebagian besar jawaban sejauh ini menunjukkan cara membuat daftar baru dengan konten yang sama dengan array, atau merujuk ke perpustakaan pihak ketiga. Namun, ada opsi sederhana dan bawaan untuk konversi semacam ini. Beberapa dari mereka sudah dibuat sketsa di jawaban lain (misalnya yang ini ). Tetapi saya ingin menunjukkan dan menguraikan derajat kebebasan tertentu untuk implementasi di sini, dan menunjukkan potensi manfaat, kelemahan, dan peringatan.
Setidaknya ada dua perbedaan penting yang harus dibuat:
- Apakah daftar yang dihasilkan harus berupa tampilan pada array atau apakah itu harus daftar baru
- Apakah daftar yang dihasilkan harus dimodifikasi atau tidak
Opsi akan diringkas di sini dengan cepat, dan program contoh lengkap ditampilkan di bagian bawah jawaban ini.
Membuat daftar baru versus membuat tampilan pada array
Ketika hasilnya harus menjadi daftar baru , maka salah satu pendekatan dari jawaban lain dapat digunakan:
List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());
Tetapi orang harus mempertimbangkan kelemahan dari melakukan ini: Sebuah array dengan long
nilai 1000000 akan menempati sekitar 8 Megabytes memori. Daftar baru juga akan menempati kira-kira 8 Megabita. Dan tentu saja, array lengkap harus dilalui saat membuat daftar ini. Dalam banyak kasus, membuat daftar baru sama sekali tidak perlu. Sebagai gantinya, cukup membuat tampilan pada array:
// 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);
(Lihat contoh di bawah untuk implementasi toList
metode ini)
Implikasi memiliki tampilan pada array adalah bahwa perubahan dalam array akan terlihat dalam daftar:
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!
Untungnya, membuat salinan (yaitu, daftar baru yang tidak terpengaruh oleh modifikasi dalam array) dari tampilan sepele:
List<Long> copy = new ArrayList<Long>(asList(array));
Sekarang, ini adalah salinan yang benar, setara dengan apa yang dicapai dengan solusi berbasis aliran yang ditunjukkan di atas.
Membuat dimodifikasi pandangan atau unmodifiable tampilan
Dalam banyak kasus, itu akan cukup ketika daftar hanya-baca . Isi daftar yang dihasilkan sering tidak akan diubah, tetapi hanya diteruskan ke pemrosesan hilir yang hanya membaca daftar.
Mengizinkan modifikasi daftar menimbulkan beberapa pertanyaan:
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?
Dimungkinkan untuk membuat tampilan daftar pada array yang dapat dimodifikasi . Ini berarti bahwa perubahan dalam daftar, seperti pengaturan nilai baru pada indeks tertentu, akan terlihat dalam array.
Tetapi tidak mungkin untuk membuat tampilan daftar yang dapat dimodifikasi secara struktural . Ini berarti bahwa tidak mungkin melakukan operasi yang memengaruhi ukuran daftar. Ini hanya karena ukuran array yang mendasarinya tidak dapat diubah.
Berikut ini adalah MCVE yang menunjukkan opsi implementasi yang berbeda, dan kemungkinan cara menggunakan daftar yang dihasilkan:
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();
}
}
Output dari contoh ditunjukkan di sini:
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