คำถามที่ถามเกี่ยวกับวิธีการเปลี่ยนอาร์เรย์เป็นรายการ คำตอบส่วนใหญ่จนถึงตอนนี้แสดงวิธีสร้างรายการใหม่ที่มีเนื้อหาเดียวกันกับอาร์เรย์หรือเรียกไปยังไลบรารีบุคคลที่สาม อย่างไรก็ตามมีตัวเลือกที่เรียบง่ายและมีอยู่แล้วสำหรับการแปลงประเภทนี้ บางคนได้รับการร่างในคำตอบอื่น ๆ แล้ว (เช่นคำตอบนี้ ) แต่ฉันอยากจะชี้ให้เห็นและอธิบายรายละเอียดของระดับความเป็นอิสระสำหรับการดำเนินการที่นี่และแสดงให้เห็นถึงประโยชน์ที่อาจเกิดขึ้นข้อเสียและข้อควรระวัง
มีความแตกต่างที่สำคัญอย่างน้อยสองประการ:
- ไม่ว่าจะเป็นรายการที่เกิดขึ้นควรจะเป็นมุมมองในอาร์เรย์หรือไม่ว่ามันควรจะเป็นรายการใหม่
- ควรจะแก้ไขรายการผลลัพธ์หรือไม่
ตัวเลือกจะถูกสรุปที่นี่อย่างรวดเร็วและโปรแกรมตัวอย่างแบบสมบูรณ์จะแสดงที่ด้านล่างของคำตอบนี้
การสร้างรายการใหม่กับการสร้างมุมมองบนอาเรย์
เมื่อผลลัพธ์ควรเป็นรายการใหม่อาจใช้วิธีการหนึ่งจากคำตอบอื่น ๆ :
List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());
แต่ควรพิจารณาข้อเสียของการทำเช่นนี้: อาร์เรย์ที่มีlong
ค่า1000000 จะครอบครองหน่วยความจำประมาณ 8 เมกะไบต์ รายการใหม่จะยังครอบครองประมาณ 8 เมกะไบต์ และแน่นอนว่าต้องมีการสำรวจเต็มรูปแบบในขณะที่สร้างรายการนี้ ในหลายกรณีการสร้างรายการใหม่นั้นไม่จำเป็น แต่มันก็เพียงพอแล้วที่จะสร้างมุมมองบนอาเรย์:
// 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);
(ดูตัวอย่างที่ด้านล่างสำหรับการนำtoList
วิธีการไปใช้)
ความหมายของการมีมุมมองในอาร์เรย์คือการเปลี่ยนแปลงในอาร์เรย์จะมองเห็นได้ในรายการ:
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!
โชคดีที่การสร้างสำเนา (นั่นคือรายการใหม่ที่ไม่ได้รับผลกระทบจากการแก้ไขในอาร์เรย์) จากมุมมองนั้นเป็นเรื่องเล็กน้อย:
List<Long> copy = new ArrayList<Long>(asList(array));
ตอนนี้นี่เป็นสำเนาที่แท้จริงซึ่งเทียบเท่ากับสิ่งที่เกิดขึ้นกับโซลูชันที่ใช้สตรีมที่แสดงไว้ด้านบน
การสร้างมุมมองที่แก้ไขได้หรือมุมมองที่ไม่สามารถแก้ไขได้
ในหลายกรณีก็จะเพียงพอเมื่อรายการที่มีการอ่านอย่างเดียว เนื้อหาของรายการผลลัพธ์มักจะไม่ได้รับการแก้ไข แต่ส่งผ่านไปยังการประมวลผลแบบดาวน์สตรีมเท่านั้นที่อ่านรายการเท่านั้น
การอนุญาตให้แก้ไขรายการทำให้เกิดคำถาม:
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?
มันเป็นไปได้ในการสร้างมุมมองรายการในอาร์เรย์ที่สามารถปรับเปลี่ยนได้ ซึ่งหมายความว่าการเปลี่ยนแปลงในรายการเช่นการตั้งค่าใหม่ที่ดัชนีหนึ่งจะปรากฏในอาร์เรย์
แต่มันเป็นไปไม่ได้ที่จะสร้างมุมมองรายการที่เป็นที่ปรับแก้โครงสร้าง ซึ่งหมายความว่าไม่สามารถทำการดำเนินการที่ส่งผลกระทบต่อขนาดของรายการ นี่เป็นเพียงเพราะขนาดของอาร์เรย์ที่อยู่ภายใต้ไม่สามารถเปลี่ยนแปลงได้
ต่อไปนี้เป็นMCVE ที่แสดงตัวเลือกการใช้งานที่แตกต่างกันและวิธีที่เป็นไปได้ของการใช้รายการผลลัพธ์:
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();
}
}
ผลลัพธ์ของตัวอย่างจะแสดงที่นี่:
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