在上一篇Java集合框架之Collection接口中我們知道List接口是Collection接口的子接口,List接口對Collection進行了簡單的擴充,List接口中的元素的特點為有序,可重復,允許null值,因為List繼承了Collection接口,所以繼承自Collection接口中的方法不再贅述,從List接口中的方法來看,List接口主要是增加了面向位置的操作,允許在指定位置上對集合中的元素進行操作,同時增加了一個能夠雙向遍歷線性表的新列表迭代器ListIterator。下面介紹List接口中的方法
void add(int index,E element):在指定位置添加元素
boolean addAll(int index,Collection<? extends E> c),在指定的位置添加一個集合的元素
示例代碼
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 public class ListDemo1 {
7 public static void main(String[] args) {
8 List list1 = new ArrayList();
9 list1.add("紅樓夢");
10 list1.add("三國演義");
11 list1.add("三國演義");
12 list1.add(null);
13 System.out.println("集合的長度:" + list1.size());
14
15 list1.add(1, "平凡的世界");
16 System.out.println(list1);
17
18 List list2 = new ArrayList();
19 list2.add("西游記");
20 list2.add("水浒傳");
21 list1.add(1, list2);
22 System.out.println(list1);
23 }
24 }
輸出結果
集合的長度:4 [紅樓夢, 平凡的世界, 三國演義, 三國演義, null] [紅樓夢, [西游記, 水浒傳], 平凡的世界, 三國演義, 三國演義, null]
可以看到List中有重復的元素以及null元素,如果指定的位置超過了集合的長度,則會報IndexOutOfBoundsException異常,如下
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 public class ListDemo1 {
7 public static void main(String[] args) {
8 List list = new ArrayList();
9 list.add("紅樓夢");
10 list.add("三國演義");
11 list.add("西游記");
12 list.add("水浒傳");
13 System.out.println("集合的長度:" + list.size());
14
15 list.add(5, "平凡的世界"); // 超過了集合的最大長度
16 System.out.println(list);
17 }
18 }
控制台輸出結果
集合的長度:4
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 5, Size: 4
at java.util.ArrayList.rangeCheckForAdd(Unknown Source)
at java.util.ArrayList.add(Unknown Source)
at list.ListDemo1.main(ListDemo1.java:15)
以下講述的方法中,凡是涉及到位置的方法,如果指定的位置超過了集合的最大長度,則同樣報IndexOutOfBoundsException異常。
E get(int index):返回指定位置的元素
int indexOf(Object o):返回此列表中第一次出現的指定元素的索引;如果此列表不包含該元素,則返回 -1
int lastIndexOf(Object o):返回此列表中最後出現的指定元素的索引;如果列表不包含此元素,則返回 -1
List<E> subList(int fromIndex,int toIndex):返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之間的部分視圖。(如果 fromIndex 和 toIndex 相等,則返回的列表為空)
示例代碼
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 public class ListDemo2 {
7 public static void main(String[] args) {
8 List list = new ArrayList();
9 list.add("紅樓夢");
10 list.add("三國演義");
11 list.add("西游記");
12 list.add("水浒傳");
13 list.add("紅樓夢");
14
15 Object object = list.get(0);
16 System.out.println(object);
17
18 int index = list.indexOf("紅樓夢");
19 System.out.println("第一次出現紅樓夢的索引:" + index);
20
21 index = list.indexOf("平凡的世界");
22 System.out.println("第一次出現平凡的世界的索引:" + index);
23
24 index = list.lastIndexOf("紅樓夢");
25 System.out.println("最後一次出現紅樓夢的索引:" + index);
26
27 index = list.lastIndexOf("平凡的世界");
28 System.out.println("最後一次出現平凡的世界的索引:" + index);
29
30 list = list.subList(1, 3); // 不包括3位置的元素
31 System.out.println(list);
32 }
33 }
輸出結果
紅樓夢 第一次出現紅樓夢的索引:0 第一次出現平凡的世界的索引:-1 最後一次出現紅樓夢的索引:4 最後一次出現平凡的世界的索引:-1 [三國演義, 西游記]
E remove(int index):移除列表中指定位置的元素(可選操作)。將所有的後續元素向左移動(將其索引減 1)。返回從列表中移除的元素。
示例代碼
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 public class ListDemo3 {
7 public static void main(String[] args) {
8 List list = new ArrayList();
9 list.add("紅樓夢");
10 list.add("三國演義");
11 list.add("西游記");
12 list.add("水浒傳");
13
14 int index = list.indexOf("西游記");
15 System.out.println("西游記原來的索引:" + index);
16
17 Object object = list.remove(1);
18 System.out.println("刪除的元素: " + object);
19
20 index = list.indexOf("西游記");
21 System.out.println("移除元素之後西游記的索引:" + index);
22
23 System.out.println(list);
24 }
25 }
輸出結果
西游記原來的索引:2 刪除的元素: 三國演義 移除元素之後西游記的索引:1 [紅樓夢, 西游記, 水浒傳]
E set(int index,E element):用指定元素替換列表中指定位置的元素(可選操作)。
代碼示例
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 public class ListDemo4 {
7 public static void main(String[] args) {
8 List list = new ArrayList();
9 list.add("紅樓夢");
10 list.add("三國演義");
11 list.add("西游記");
12 list.add("水浒傳");
13 list.set(0, "平凡的世界");
14 System.out.println(list);
15 }
16 }
輸出結果
[平凡的世界, 三國演義, 西游記, 水浒傳]
ListIterator<E> listIterator():返回此列表元素的列表迭代器(按適當順序)。
ListIterator是一個接口,繼承自Iterator接口,除了擁有Iterator接口中的方法之外,還擁有一些自己特有的方法
boolean hasPrevious():逆向遍歷列表,如果仍有元素可以迭代,則返回 true。
E previous():返回迭代的上一個元素,並移動到上一個位置。
雖然ListIterator可以實現集合的逆向迭代,但是從Java集合框架之Collection接口中我們知道,迭代器初始狀態下前面並沒有任何元素,必須先正向遍歷,才能逆向遍歷,所以一般不使用逆向迭代。
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.ListIterator;
6
7 public class ListDemo5 {
8 public static void main(String[] args) {
9 List list = new ArrayList();
10 list.add("紅樓夢");
11 list.add("三國演義");
12 list.add("西游記");
13 list.add("水浒傳");
14
15 ListIterator it = list.listIterator();
16
17 System.out.println("----------逆向迭代----------");
18 while (it.hasPrevious()) {
19 Object object = (Object) it.previous();
20 System.out.println(object);
21 }
22
23 System.out.println("----------正向迭代----------");
24 while (it.hasNext()) {
25 Object object = it.next();
26 System.out.println(object);
27 }
28
29 System.out.println("----------逆向迭代----------");
30 while (it.hasPrevious()) {
31 Object object = (Object) it.previous();
32 System.out.println(object);
33 }
34 }
35 }
輸出結果
----------逆向遍歷---------- ----------正向遍歷---------- 紅樓夢 三國演義 西游記 水浒傳 ----------逆向遍歷---------- 水浒傳 西游記 三國演義 紅樓夢
從上面結果可以看出,當第一次逆向迭代的時候並沒有任何輸出,當正向迭代後,迭代器到了集合的末尾之後,再次逆向迭代,這時才有輸出。
上面的while循環,我們可以改成for循環
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6
7 public class ListDemo6 {
8 public static void main(String[] args) {
9 List list = new ArrayList();
10 list.add("紅樓夢");
11 list.add("三國演義");
12 list.add("西游記");
13 list.add("水浒傳");
14
15 for (Iterator iterator = list.iterator(); iterator.hasNext();) {
16 Object object = (Object) iterator.next();
17 System.out.println(object);
18 }
19 }
20 }
在效率上,或許for循環的更高,因為for循環結束之後iterator變量的作用域便結束了,iterator變量就消失了。我們還可以結合get(int index)與size()方法來遍歷集合
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 public class ListDemo7 {
7 public static void main(String[] args) {
8 List list = new ArrayList();
9 list.add("紅樓夢");
10 list.add("三國演義");
11 list.add("西游記");
12 list.add("水浒傳");
13
14 for (int i = 0; i < list.size(); i++) {
15 Object object = list.get(i);
16 System.out.println(object);
17 }
18 }
19 }
下面再來看ListIterator中對元素進行操作的方法
void add(E e):將指定的元素插入列表
void remove():從列表中移除由 next 或 previous 返回的最後一個元素
void set(E e):用指定元素替換 next 或 previous 返回的最後一個元素
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.ListIterator;
6
7 public class ListDemo8 {
8 public static void main(String[] args) {
9 List list = new ArrayList();
10 list.add("紅樓夢");
11 list.add("三國演義");
12 list.add("西游記");
13 list.add("水浒傳");
14
15 ListIterator it = list.listIterator();
16
17 it.add("平凡的世界");
18
19 System.out.println(list);
20
21 it.next();
22 it.remove(); // 調用remove方法時需要先調用next或
23 // previous方法,否則將拋出java.lang.IllegalStateException異常
24 it.next();
25 it.set("新三國演義");// 調用remove方法時需要先調用next或
26 // previous方法,否則將拋出java.lang.IllegalStateException異常
27
28 System.out.println(list);
29 }
30 }
輸出結果
[平凡的世界, 紅樓夢, 三國演義, 西游記, 水浒傳] [平凡的世界, 新三國演義, 西游記, 水浒傳] 西游記 水浒傳
有時候我們在操作集合的時候,需要對集合的元素進行添加或者是刪除
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6
7 public class ListDemo9 {
8 public static void main(String[] args) {
9 List list = new ArrayList();
10 list.add("紅樓夢");
11 list.add("三國演義");
12 list.add("水浒傳");
13
14 Iterator it = list.iterator();
15
16 while (it.hasNext()) {
17 String s = (String) it.next();
18 if ("三國演義".equals(s)) {
19 list.add("西游記");
20 }
21 }
22
23 System.out.println(list);
24 }
25 }
運行這段程序,控制台將出現如下錯誤
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at list.ListDemo9.main(ListDemo9.java:17)
ConcurrentModificationException:當方法檢測到對象的並發修改,但不允許這種修改時,拋出此異常。 為什麼會出現這種錯誤呢,這是因為迭代器是依賴於集合而存在的,在判斷成功後,集合中新添加了元素,而迭代器這時還不知道,所以就報錯了,這個錯叫並發修改異常。報錯的地方為代碼17行,正是迭代器獲取元素的時候。如何解決這個問題呢,既然迭代器遍歷集合的時候,集合不能對元素進行操作,那麼使用迭代器操作元素呢
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.ListIterator;
6
7 public class ListDemo10 {
8 public static void main(String[] args) {
9 List list = new ArrayList();
10 list.add("紅樓夢");
11 list.add("三國演義");
12 list.add("水浒傳");
13
14 ListIterator it = list.listIterator();
15
16 while (it.hasNext()) {
17 String s = (String) it.next();
18 if ("三國演義".equals(s)) {
19 it.add("西游記");
20 }
21 }
22
23 System.out.println(list);
24 }
25 }
這時候控制台的沒有報錯了
[紅樓夢, 三國演義, 西游記, 水浒傳]
用迭代器添加的元素時,元素的位置為當前迭代器的位置,換個角度想一下,既然迭代器遍歷集合的時候,迭代器可以對集合的元素進行操作,那麼集合遍歷元素的時候,集合是否也可以對元素進行操作呢
1 package list;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.ListIterator;
6
7 public class ListDemo10 {
8 public static void main(String[] args) {
9 List list = new ArrayList();
10 list.add("紅樓夢");
11 list.add("三國演義");
12 list.add("水浒傳");
13
14 for (int i = 0; i < list.size(); i++) {
15 if ("水浒傳".equals(list.get(i))) {
16 list.add("西游記");
17 }
18 }
19
20 System.out.println(list);
21 }
22 }
輸出結果
[紅樓夢, 三國演義, 水浒傳, 西游記]
當用集合添加元素的時候,添加在了集合的最後面
由上述結果可以知,有兩種方法可以解決並發修改異常ConcurrentModificationException
1、迭代器迭代元素,迭代器修改元素
2、集合遍歷元素,集合修改元素(普通for)