Java 集合(三)

四. List 集合

  • List 集合代表一个元素有序、可重复的集合,其中每个元素都有其对应的顺序索引,可以通过索引来访问指定位置的集合元素。

1. Java 8 改进的 List 接口和 ListIterator 接口

  • 作为 Collection 接口的子接口,List 可以使用 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 toIndex):返回从索引 fromIndex(包含)到索引 toIndex(不包含)处所有集合元素组成的子集合。
  • 示例程序:

    import java.util.*;
    
    public class ListTest {
        public static void main(String[] args) {
            List books = new ArrayList();
            // 向 books 集合中添加三个元素
            books.add(new String("禅与摩托车维修艺术"));
            books.add(new String("在路上"));
            books.add(new String("麦田里的守望者"));
            System.out.println(books);
            // 将新字符串对象插入在第二个位置
            books.add(1, new String("追风筝的人"));
    
            for(int i=0 ; iout.println(books.get(i));
            }
    
            // 删除第三个元素
            books.remove(2);
            System.out.println(books);
            // 判断指定元素在 List 集合中的位置,输出 1,表明位于第二位
            System.out.println(books.indexOf(new String("追风筝的人")));  // ①
            // 将第二个元素替换成新的字符串对象
            books.set(1,  new String("在路上"));
            System.out.println(books);
            // 将 books 集合的第二个元素(包括)到第三个元素(不包括)截取成子集合
            System.out.println(books.subList(1, 2));
        }
    }
    输出结果:
        [禅与摩托车维修艺术, 在路上, 麦田里的守望者]
        禅与摩托车维修艺术
        追风筝的人
        在路上
        麦田里的守望者
        [禅与摩托车维修艺术, 追风筝的人, 麦田里的守望者]
        1
        [禅与摩托车维修艺术, 在路上, 麦田里的守望者]
        [在路上]
  • List 判断两个对象相等的标准:只要 equals() 方法比较返回 true 即可。
  • Java 8 还为 List 接口添加了如下两个默认方法:

    • void replaceAll(UnaryOperator operator):根据 operator 指定的计算规则重新设置 List 集合的所有元素。replaceAll() 方法需要一个 UnaryOperator 来替换所有集合元素,UnaryOperator 也是一个函数式接口,可以使用 Lambda 表达式作为参数。
    • void sort(Comparator c):根据 Comparator 参数对 List 集合的元素排序。sort() 方法需要一个 Comparator 对象来控制元素排序,可使用 Lambda 表达式来作为参数。
    • 示例程序:
      import java.util.*;
      
      public class ListTest3 {
          public static void main(String[] args) {
      
              List books = new ArrayList();
              books.add(new String("禅与摩托车维修艺术"));
              books.add(new String("追风筝的人"));
              books.add(new String("麦田里的守望者"));
              books.add(new String("在路上"));
      
              // 使用目标类型为 Comparator 的 Lambda 表达式对 List 集合排序
              books.sort((o1, o2) -> ((String)o1).length() - ((String)o2).length());
              System.out.println(books);
              // 使用目标类型为 UnaryOperatorLambda 表达式来替换集合中所有元素
              // 该 Lambda 表达式控制使用每个字符串的长度作为新的集合元素
              books.replaceAll(ele -> ((String)ele).length());
              System.out.println(books);
          }
      }
      输出结果:
          [在路上, 追风筝的人, 麦田里的守望者, 禅与摩托车维修艺术]
          [3, 5, 7, 9]
  • 与 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 只能删除元素)
    • 示范程序:
      import java.util.*;
      
      public class ListIteratorTest {
          public static void main(String[] args) {
              String[] books = {
                  "禅与摩托车维修艺术", "追风筝的人",
                  "麦田里的守望者"
              };
              List bookList = new ArrayList();
              for (int i=0 ; iwhile(lit.hasNext()) {
                  System.out.println(lit.next());
                  lit.add("-----分隔符-----");
              }
              System.out.println("=====下面开始反向迭代=====");
              while(lit.hasPrevious()) {
                  System.out.println(lit.previous());
              }
          }
      }
      输出结果:
          禅与摩托车维修艺术
          追风筝的人
          麦田里的守望者
          =====下面开始反向迭代=====
          -----分隔符-----
          麦田里的守望者
          -----分隔符-----
          追风筝的人
          -----分隔符-----
          禅与摩托车维修艺术

2. ArrayList 和 Vector 实现类

  • ArrayList 和 Vector 完全支持前面介绍的 List 接口的全部功能
  • ArrayList 和 Vector 类都是基于数组实现的 List 类,它们封装了一个动态的允许再分配Object[] 数组
    • ArrayList 或 Vector 对象使用 initialCapacity 参数来设置该数组的长度
    • 向 ArrayList 或 Vector 中添加元素超出了该数组的长度时,它们的 initialCapacity 会自动增加。
    • 如果向 ArrayList 或 Vector 集合中添加大量元素时,可使用 ensureCapacity(int minCapacity) 方法一次性地增加 initialCapacity。这可以减少重分配次数,提高性能。
    • 如果开始就知道 ArrayList 或 Vector 集合需要保存多少个元素,可以在创建它们的时候就指定 initialCapacity 大小。如果创建空的 ArrayList 或 Vector 集合时不指定 initialCapacity 参数,则 Object[] 数组的长度默认为 10。
    • 除此之外,ArrayList 或 Vector 集合还提供了如下两个方法来重新分配 Object[] 数组:
      • void ensureCapacity(int minCapacity):将 ArrayList 或 Vector 集合的 Object[] 数组长度增加大于或等于 minCapacity 值。
      • void trimToSize():调整 ArrayList 或 Vector 集合的 Object[] 数组长度为当前元素的个数。调用该方法可减少 ArrayList 或 Vector 集合对象占用的存储空间。
  • Vector 是一个古老的集合,里面有一些功能重复的方法。其中方法名更短的是后来新增的,方法名更长的方法则是 Vector 原有的方法。Vector 有很多缺点,尽量少用 Vector 实现类
  • ArrayList 和 Vector 的显著区别:
    • ArrayList 是线程不安全的。多个线程访问同一个 ArrayList 集合时,如果有超过一个线程修改了 ArrayList 集合,则程序必须手动保证该集合的同步性。
    • Vector 是线程安全的。正是由于这一点,Vector 的性能比 ArrayList 的性能要低。
    • 实际上,即使要保证 List 集合线程安全,也不推荐使用 Vector 的实现类。可以使用 Collections 工具类,将一个 ArrayList 变成线程安全的。
  • Vector 还提供了一个 Stack 子类,用于模拟“栈”这种数据结构。“栈”是指“后进先出”(LIFO)的容器。最后被“push”进栈的元素,将最先被“pop”出栈。与 Java 中的其他集合一样,进栈出栈的都是 Object,从栈中取出元素后往往要进行强制类型转换(除非你使用的是 Object 具有的操作)。Stack 类里提供了如下方法:
    • Object peek():返回栈的第一个元素,但并不将该元素 pop 出栈
    • Object pop():返回栈的第一个元素,并将其 pop 出栈。
    • void push(Object item):将一个元素 push 进栈,最后一个进栈的元素总是位于栈顶。
    • Stack 继承了 Vector,也是比较古老的集合类,同样线程安全、性能较差。我们要尽量避免使用 Stack 类。如果要用到“栈”这种数据结构,可以考虑使用 ArrayDeque。

3. 固定长度的 List

  • Arrays.ArrayList 是 Arrays 的内部类 ArrayList 的实例。它是一个固定长度的 List 集合,程序只能遍历访问该集合里的元素,不可增加、删除该集合里的元素,否则会引发 UnsupportedOperationException 异常。

你可能感兴趣的:(Java学习,java)