8.4.1 Java 8改进的List接口和ListIterator接口

8.4.1 Java 8改进的List接口和ListIterator接口

List作为Collection接口的子接口,当然可以使用Collection接口里的全部方法。而且由于List是有序集合,因此List集合里增加了一些根据索引来操作集合元素的方法。

List集合中增加的索引相关的方法

根据索引 增 删 改 查元素

List新增的根据索引增删改查方法 描述
void add(int index, E element) 将元素element插入到List集合的index
boolean addAll(int index, Collection<? extends E> c) 将集合c所包含的所有元素都插入到List集合的index
E remove(int index) 删除并返回index索引处的元素。
E set(int index, E element) index索引处的元素替换成element对象,返回被替换的旧元素。
E get(int index) 返回集合index索引处的元素。

set方法不会改变集合长度

当调用Listset(int index, Object element)方法来更新List集合指定索引处的元素时,指定的索引必须是List集合的有效索引。
例如,集合长度是4,就不能指定替换索引为4处的元素。也就是说,set(int index, Object element)方法不会改变List集合的长度.

查询元素的索引

方法 描述
int indexOf(Object o) 返回对象oList集合中第一次出现的位置索引.
int lastIndexOf(Object o) 返回对象oList集合中最后一次出现的位置索.

截取子List

方法 描述
List<E> subList(int fromIndex, int toIndex) 返回从索引fromIndex(包含)到索引toIndex(不包含)处所有集合元素组成的子集合。subXxxx方法一般遵循前闭后开原则.

所有的List实现类都可以调用这些方法来操作集合元素。与Set集合相比,List增加了根据索引来插入、替换和删除集合元素的方法

Java8增加的默认方法

除此之外,Java 8还为List接口添加了如下两个默认方法

方法 描述
default void replaceAll(UnaryOperator<E> operator) 根据operator指定的计算规则重新设置List集合的所有元素
default void sort(Comparator<? super E> c) 根据Comparator参数对List集合的元素排序

程序 List集合常规用法

下面程序示范了List集合的常规用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.*;

public class ListTest
{
public static void main(String[] args)
{
List books = new ArrayList();
// 向books集合中添加三个元素
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂Android讲义"));
System.out.println(books);
// 将新字符串对象插入在第二个位置
books.add(1 , new String("疯狂Ajax讲义"));
for (int i = 0 ; i < books.size() ; i++ )
{
System.out.println(books.get(i));
}
// 删除第三个元素
books.remove(2);
System.out.println(books);
// 判断指定元素在List集合中位置:输出1,表明位于第二位
System.out.println(books.indexOf(new String("疯狂Ajax讲义"))); //①
//将第二个元素替换成新的字符串对象
books.set(1, new String("疯狂Java讲义"));
System.out.println(books);
//将books集合的第二个元素(包括)
//到第三个元素(不包括)截取成子集合
System.out.println(books.subList(1 , 2));
}
}

可以使用普通的for循环遍历List集合

List集合可以根据位置索引来访问集合中的元素,因此List增加了一种新的遍历集合元素的方法:使用普通的for循环来遍历List集合元素。
运行上面程序,将看到如下运行结果:

1
2
3
4
5
6
7
8
9
[轻量级Java EE企业应用实战, 疯狂Java讲义, 疯狂Android讲义]
轻量级Java EE企业应用实战
疯狂Ajax讲义
疯狂Java讲义
疯狂Android讲义
[轻量级Java EE企业应用实战, 疯狂Ajax讲义, 疯狂Android讲义]
1
[轻量级Java EE企业应用实战, 疯狂Java讲义, 疯狂Android讲义]
[疯狂Java讲义]

从上面运行结果清楚地看出List集合的用法。注意①行代码处,程序试图返回新字符串对象在List集合中的位置,实际上List集合中并未包含该字符串对象。因为List集合添加字符串对象时,添加的是通过new关键字创建的新字符串对象,①行代码处也是通过new关键字创建的新字符串对象,两个字符串显然不是同一个对象,但Listindexof方法依然可以返回1。List判断两个对象相等的标准是什么呢?

List如何判断两个对象相等

两个对象相等只要通过equals方法比较返回true,则List就认为这两个元素相等

程序 List通过equals方法来判断元素是否相等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.util.*;

class A
{
public boolean equals(Object obj)
{
return true;
}
}
public class ListTest2
{
public static void main(String[] args)
{
List books = new ArrayList();
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂Android讲义"));
System.out.println(books);
// 删除集合中A对象,将导致第一个元素被删除
books.remove(new A()); // ①
System.out.println(books);
// 删除集合中A对象,再次删除集合中第一个元素
books.remove(new A()); // ②
System.out.println(books);
}
}

编译、运行上面程序,看到如下运行结果:

1
2
3
[轻量级Java EE企业应用实战, 疯狂Java讲义, 疯狂Android讲义]
[疯狂Java讲义, 疯狂Android讲义]
[疯狂Android讲义]

从上面运行结果可以看出,执行①行代码时,程序试图删除一个A对象,List将会调用该A对象的equals()方法依次与集合元素进行比较,如果该equals()方法以某个集合元素作为参数时返回true,List将会删除该元素。
由于A类重写了equals方法,该方法总是返回true。所以每次从List集合中删除A对象时,总是删除List集合中的第一个元素。

java 8中List集合增加的方法

Java 8List集合增加了sort()replaceAll()两个常用的默认方法,其中

  • sort()方法需要一个Comparator对象来控制元素排序,程序可使用Lambda表达式来作为参数;
  • replaceAll()方法则需要个UnaryOperator来替换所有集合元素, UnaryOperator也是一个函数式接口,因此程序也可使用Lambda表达式作为参数。

程序 测试List在Java 8中新增的默认方法

如下程序示范了List集合的两个默认方法的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.*;

public class ListTest3
{
public static void main(String[] args)
{
List books = new ArrayList();
// 向books集合中添加4个元素
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂Android讲义"));
books.add(new String("疯狂IOS讲义"));
// 使用目标类型为Comparator的Lambda表达式对List集合排序
books.sort((o1, o2)->((String)o1).length() - ((String)o2).length());//①
System.out.println(books);
// 使用目标类型为UnaryOperator的Lambda表达式来替换集合中所有元素
// 该Lambda表达式控制使用每个字符串的长度作为新的集合元素
books.replaceAll(ele->((String)ele).length());//②
System.out.println(books); // 输出[7, 8, 11, 16]
}
}
1
2
[疯狂IOS讲义, 疯狂Java讲义, 疯狂Android讲义, 轻量级Java EE企业应用实战]
[7, 8, 11, 16]

上面程序中编号为①的代码控制对List集合进行排序,传给sort()方法的Lambda表达式指定的排序规则是:字符串长度越长,字符串越大,因此执行完第一行粗体字代码之后,List集合中的字符串按由短到长的顺序排列.
程序中编号为②的代码传给replaceAll()方法的Lambda表达式指定了替换集合元素的规则:直接用集合元素(字符串)的长度作为新的集合元素。执行该方法后,**集合元素被替换为[7,8,11,16]**。

List集合独有的listIterator方法

Set只提供了一个iterator()方法不同,List额外提供了一个listIterator()方法:

方法 描述
ListIterator<E> listIterator() Returns a list iterator over the elements in this list (in proper sequence).

该方法返回一个ListIterator对象, ListIterator接口继承了Iterator接口,提供了专门操作List的方法

ListIterator接口增加的方法

ListIterator接口在Iterator接口基础上增加了如下方法。

方法 描述
boolean hasPrevious() 返回该迭代器关联的集合是否还有上一个元素。
E previous() 返回该迭代器的上一个元素
void add(E e) Inserts the specified element into the list (optional operation).

ListIterator和Iterator的对比

  • ListIterator增加了向前迭代的功能,而**Iterator只能向后迭代**
  • ListIterator可通过add()方法向List集合中添加元素,而Iterator只能删除元素.

程序 List独有的迭代器ListIterator的用法

下面程序示范了ListIterator的用法.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.*;

public class ListIteratorTest {
public static void main(String[] args) {
String[] books = { "小明", "小王", "小张" };
List bookList = new ArrayList();
for (int i = 0; i < books.length; i++) {
bookList.add(books[i]);
}

ListIterator lit = bookList.listIterator();
while (lit.hasNext()) {
System.out.println(lit.next());
lit.add("小芳");
}

System.out.println("=======下面开始反向迭代=======");
while (lit.hasPrevious()) {
System.out.println(lit.previous());
}
}
}

从上面程序中可以看出,使用ListIterator迭代List集合时,开始也需要采用正向迭代,即先使用next()方法进行迭代,在迭代过程中可以使用add()方法向上一次迭代元素的后面添加一个新元素。
先正向迭代,然后再反向迭代
运行上面程序,看到如下结果:

1
2
3
4
5
6
7
8
9
10
小明
小王
小张
=======下面开始反向迭代=======
_小芳
小张
_小芳
小王
_小芳
小明