0%

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

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

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

方法 描述
void add(int index, Object element) 将元素element插入到List集合的index处。
boolean addAll(int index, Collection c) 将集合c所包含的所有元素都插入到List集合的index
Object get(int index) 返回集合index索引处的元素。
int indexOf(Object o) 返回对象o在List集合中第一次出现的位置索引.
int lastIndexOf(Object o) 返回对象o在List集合中最后一次出现的位置索.
Object remove(int index) 删除并返回 index索引处的元素。
Object set(int index, Object element) index索引处的元素替换成element对象,返回被替换的旧元素。
List subList(int fromIndex, int tolndex) 返回从索引 fromIndex(包含)到索引toIndex(不包含)处所有集合元素组成的子集合。subXxxx方法一般遵循前闭后开原则.
所有的List实现类都可以调用这些方法来操作集合元素。与Set集合相比,List增加了根据索引来插入、替换和删除集合元素的方法。除此之外,Java 8还为List接口添加了如下两个默认方法
方法 描述
void replaceAll(UnaryOperator operator) 根据 operator指定的计算规则重新设置List集合的所有元素。
void sort(Comparator 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));
}
}

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

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如何判断两个对象相等

List判断两个对象相等只要通过equals方法比较返回true即可。看下面程序

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集合中的第一个元素。
当调用Listset(int index, Object element)方法来更新List集合指定索引处的元素时,指定的索引必须是List集合的有效索引。例如集合长度是4,就不能指定替换索引为4处的元素—也就是说,set( int index, Object element)方法不会改变List集合的长度.
Java 8List集合增加了sort()replaceAll()两个常用的默认方法,其中
sort()方法需要一个Comparator对象来控制元素排序,程序可使用Lambda表达式来作为参数;
replaceAll()方法则需要个UnaryOperator来替换所有集合元素, UnaryOperator也是一个函数式接口,因此程序也可使用Lambda表达式作为参数。如下程序示范了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]
Set只提供了一个iterator()方法不同,List还额外提供了一个listIterator()方法,该方法返回一个ListIterator对象, ListIterator接口继承了Iterator接口,提供了专门操作List的方法。 ListIterator接口在Iterator接口基础上增加了如下方法。

方法 描述
boolean hasPrevious() 返回该迭代器关联的集合是否还有上一个元素。
Object previous() 返回该迭代器的上一个元素.
void add(Object o) 在指定位置插入一个元素。
## ListIterator和Iterator的对比 ##
- ListIterator增加了向前迭代的功能,而Iterator只能向后迭代
- ListIterator可通过add()方法向List集合中添加元素,而Iterator只能删除元素.

下面程序示范了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
小明
小王
小张
=======下面开始反向迭代=======
_小芳
小张
_小芳
小王
_小芳
小明

原文链接: 8.4.1 Java 8改进的List接口和ListIterator接口