🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # list List的介绍。有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。与 set 不同,列表通常允许重复的元素 List接口: * 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。 * 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。 * 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。 List接口的常用子类有: * ArrayList集合 * LinkedList集合 ## list常用方法 ![](https://box.kancloud.cn/b3228d72b9fc645e0b279e0de9fcec94_892x400.png) * 增加元素方法 - add(Object e):向集合末尾处,添加指定的元素 - add(int index, Object e):向集合指定索引处,添加指定的元素,原有元素依次后移 * 删除元素方法 - remove(Object e):将指定元素对象,从集合中删除,返回值为被删除的元素 - remove(int index):将指定索引处的元素,从集合中删除,返回值为被删除的元素 * 替换元素方法 - set(int index, Object e):将指定索引处的元素,替换成指定的元素,返回值为替换前的元素 * 查询元素方法 - get(int index):获取指定索引处的元素,并返回该元素 **由于List集合拥有索引,因此List集合迭代方式除了使用迭代器之外,还可以使用索引进行迭代。** ~~~ for (int i = 0; i < list.size(); i++) { String str = list.get(i); System.out.println(str); } ~~~ ## Iterator的并发修改异常 在list集合迭代元素中,对元素进行判断,一旦条件满足就添加一个新元素。代码如下 ~~~ //创建List集合 List<String> list = new ArrayList<String>(); //给集合中添加元素 list.add("abc1"); list.add("abc2"); list.add("abc3"); list.add("abc4"); //迭代集合,当有元素为"abc2"时,集合加入新元素"itcast" Iterator<String> it = list.iterator(); while(it.hasNext()){ String str = it.next(); //判断取出的元素是否是"abc2",是就添加一个新元素 if("abc2".equals(str)){ list.add("123");// 该操作会导致程序出错 } } //打印容器中的元素 System.out.println(list); ~~~ 运行上述代码发生了错误 java.util.ConcurrentModificationException这是什么原因呢? 在迭代过程中,使用了集合的方法对元素进行操作。导致迭代器并不知道集合中的变化,容易引发数据的不确定性。 **并发修改异常解决办法:在迭代时,不要使用集合的方法操作元素。 那么想要在迭代时对元素操作咋办?通过ListIterator迭代器操作元素是可以的,ListIterator的出现,解决了使用Iterator迭代过程中可能会发生的错误情况** **如何解决 ** 第一: 使用普通for循环 第二(重点):使用listIterator -->是List 特有的,其他集合不能使用 **注意添加的时候一定要用ListIterator添加,不是list** ~~~ public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("abc1"); list.add("abc2"); list.add("abc3"); ListIterator<String> it = list.listIterator(); while (it.hasNext()) { String str = it.next(); if ("abc1".equals(str)) { //这边要用迭代器添加,不能用list添加 it.add("123"); } } System.out.println(list); } ~~~ ## java.lang.Iterable.forEach java8提供了循环的新方式 以下是几个示例,运行结果就不贴出来了,就是循环显示 ~~~ String[] a = { "17", "52", "33", "412", "59", "62", "71" }; List<String> list = Arrays.asList(a); //这个是使用的lambda表达式的的循环 list.forEach(cc -> System.out.println(cc)); ~~~ ~~~ String[] a = { "17", "52", "33", "412", "59", "62", "71" }; List<String> list = Arrays.asList(a); //这个是使用lambda表达式的简化版本双冒号表达式(调用out对象的println方法) list.forEach(System.out::println); ~~~ ~~~ String[] a = { "17", "52", "33", "412", "59", "62", "71" }; List<String> list = Arrays.asList(a); //这个还是用的java8提供的新函数,但是没有用lambda表达式 list.forEach(new Consumer<String>() { @Override public void accept(String t) { // TODO Auto-generated method stub System.out.println(t); } }); ~~~ ## 数据类型 栈 : 手枪的弹夹 : 手枪的压栈 ---> 喝酒 --->先进后出,后进先出 队列 : 超市的购物,先排队,先处理 ---> 喝酒 --->先进去,先出来,后进去,后出来 数组 : 查找快:因为底层有索引,并且是连续 增删慢: 数组的长度的是固定的,当我们在进行增删时,会创建一个新的数组,并且将老数组中的值拷贝到新数组中 链表: 查找慢(底层是链表,两两相连,依次往下找,直到找到为止) --->linkedList 采用二分法查找 增删快 :原因在于他仅仅只需要改变相邻元素的地址值 ## ArrayList集合 **线程不安全的** Collections中定义了synchronizedList(List list)将此ArrayList转化为线程安全的 **ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快**,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。 许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。 ## LinkedList集合 **线程不安全,线程安全用ConcurrentLinkedQueue** **LinkedList集合数据存储的结构是链表结构。方便元素添加、删除的集合。** 实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法 ![](https://box.kancloud.cn/990ac96df4da9861d721a5b33026b6c7_908x907.png) LinkedList是List的子类,List中的方法LinkedList都是可以使用 ~~~ LinkedList<String> link = new LinkedList<String>(); //添加元素 link.addFirst("abc1"); link.addFirst("abc2"); link.addFirst("abc3"); //获取元素 System.out.println(link.getFirst()); System.out.println(link.getLast()); //删除元素 System.out.println(link.removeFirst()); System.out.println(link.removeLast()); while(!link.isEmpty()){ //判断集合是否为空 System.out.println(link.pop()); //弹出集合中的栈顶元素 } ~~~ ## Vector集合 Vector集合数据存储的结构是**数组结构**,为JDK中最早提供的集合。Vector中提供了一个独特的取出方式,就是枚举Enumeration,它其实就是早期的迭代器。 此接口Enumeration的功能与 Iterator 接口的功能是类似的。Vector集合已被ArrayList替代。枚举Enumeration已被迭代器Iterator替代。 ![](https://box.kancloud.cn/d98522b8940b6dbe7bdaf1ba53380cec_910x453.png) Vector集合对ArrayList集合使用的对比 ArrayList是线程不安全的 Vector线程安全 # toArray() 需要特别注意,不能这样写: ~~~ ArrayList<String> list=new ArrayList<String>(); String strings[]=(String [])list.toArray(); ~~~ 这样写编译没有什么问题,但是运行时会报ClassCastException,这是因为Java中允许向上和向下转型,但是这个转型是否成功是根据Java虚拟机中这个对象的类型来实现的。Java虚拟机中保存了每个对象的类型。而数组也是一个对象。数组的类型是java.lang.Object。把java.lang.Object转换成java.lang.String是显然不可能的事情,因为这里是一个向下转型,而虚拟机只保存了这是一个Object的数组,不能保证数组中的元素是String的,所以这个转型不能成功。数组里面的元素只是元素的引用,不是存储的具体元素,所以数组中元素的类型还是保存在Java虚拟机中的。 因此正确的方法是这样的 ~~~ //要转换的list集合 List<String> testList = new ArrayList<String>(){{add("aa");add("bb");add("cc");}}; //使用toArray(T[] a)方法 String[] array2 = testList.toArray(new String[testList.size()]); //打印该数组 for(int i = 0; i < array2.length; i++){ System.out.println(array2[i]); } ~~~