Java Arrays 和 List的相互轉化
最近在 leetcode 刷題的時候遇到過好幾次這樣的情況:需要返回的資料型別是陣列(Arrays
),但是求解的時候並不知道陣列的長度,這時候就需要先用 List
進行臨時儲存,最後再轉化為 Arrays
返回。所以這裡將 java 中 Arrays
和 List
之間的轉化總結一下。
Arrays
轉為 List
1. 利用Arrays.asList()
方法
Arrays
類提供了 asList()
方法,我們先來看看原始碼:
可以看到,Arrays.asList()
是泛型方法,傳入的必須是物件陣列而不是基本資料型別的陣列。首先拿 String
陣列來看一下:
沒有問題,陣列“變成了” List
List
的 get()
方法進行元素訪問。但是換成 int[]
陣列呢?Eclipse提示出錯了,需要將
List
的元素型別換成 int[]
,也就是說對於基本資料型別的陣列,Arrays.asList()
會將整個陣列作為一個最後返回的列表中的一個物件。不信的話就改成 int[]
試一下,看結果:所以,對於基本資料型別的陣列,是不能用
Arrays.asList()
將其轉化為 List
的。
另一個坑
是不是以為對於物件陣列,Arrays.asList()
就可以無腦使用了呢?還是圖樣圖森破啊。再看看原始碼:
發現了吧!Arrays.asList()
這裡返回的ArrayList
java.util.ArrayList
,而是java.util.Arrays
自己定義的一個靜態內部類,這個內部類繼承了AbstarctList
類。並且,這個自定義的內部類並沒有實現java.util.List
的修改方法例如add
、remove
等。因此對於轉化後的List物件如果進行修改會報異常!!
2. 使用 Java8 的Stream
介面
挖完坑之後當然是要填坑了。其實自己實現Arrays
轉為 List
最簡單的就是遍歷添加了,不用多說。這裡說一個Java8以上版本中的高階操作——Stream介面,這個介面主要就是用來支援對元素流的函式式操作,更詳細的介紹可以參考官方文件。先給出轉化程式碼:
public static void main(String[] args) {
int[] arr = {1, 2, 3};
List<Integer> ls = Arrays.stream(arr).boxed().collect(Collectors.toList());
System.out.println(ls.get(0));
}
上面程式碼得到的 ls
支援列表的元素操作函式。Arrays.stream()
函式返回一個IntStream
物件(儲存原始int
型別的Stream
),boxed()
函式是 IntStream
物件的裝箱函式,返回Stream<Integer>
物件。collect()
函式根據指定的Collector
對流元素進行對應操作,上面程式碼中 Collectors.toList()
返回一個將所有元素收集到一個 List
中的 Collector
。
List
轉為 Arrays
1. 使用 List.toArray()
方法
List
有兩個toArray()
方法,其中無參的toArray()
方法返回的是Object[]
陣列,也無法通過強制型別轉換轉換成別的型別(所以不明白無參的這個方法應用場景在哪裡)。此外還有一個有參的泛型方法 <T> T[] toArray(T[] a)
,這個方法可以返回指定型別的陣列,但是也只能是引用型別:
List<String> ls = new ArrayList<>();
ls.add("java");
ls.add("python");
ls.add("php");
String[] arr = ls.toArray(new String[0]);
System.out.println(arr[1]);
像這樣就沒問題,但是對於基本資料型別像char
、int
這樣就會報錯,必須指定為對應的包裝類才可以。因此即使是 <T> T[] toArray(T[] a)
這個方法,也無法直接將Integer
的列表轉化為int[]
陣列。
2. 使用 Java8 的Stream
介面
以List<Integer>
到 int[]
為例,下面這段程式碼就可以實現轉化:
List<Integer> ls = new ArrayList<>();
ls.add(1);
ls.add(3);
ls.add(4);
int[] arr = ls.stream().mapToInt(Integer::intValue).toArray();
System.out.println(arr[1]);
首先通過stream()
方法將列表轉化為流物件,再通過mapToInt()
函式將流物件中的元素對映成int
型別,最後通過Stream
的 toArray
方法轉化為陣列。其中mapToInt()
引數為給定的對映函式,這裡表示對映到int
型別。::
也是java8中的操作符,表示對Integer
類的intValue()
方法的呼叫,更多的使用方式可以看官方文件。
總結
Java集合中只能存放引用型別的資料,不能存放基本資料型別,因此在對基本資料型別資料進行“Arrays-to-List”或者“List-to-Arrays”操作的時候,類本身的方法可能不適用,這時候就必須手動遍歷轉化,或者利用Java8的Stream
介面幫助實現。上面的實現看起來好像是把簡單問題變複雜了,確實在進行簡單轉化的時候遍歷複製元素是最方便的,但是Stream
介面還有一些強大的功能,如果轉化過程中還有一些複雜操作像元素篩選、過濾等 Stream
介面就能夠用到了。