java入门学习提升第二十篇:Java集合类详解(三)List接口

今天要说的是Collection族长下的三名大将之一,List,Set,Queue中的List,它们都继承自Collection接口,所以Collection接口的所有操作,它们自然也是有的。

List,Set,Queue,分别是列表,集合,队列的意思,代表着Collection家族下的三种不同的势力,它们各有所长,也各有所短,就像骑兵,步兵和水兵,各有各的优势,并没有谁一定比谁更好的说法,合适的才是最好的。接下来,将会分别介绍这三名大将,从中你也会看到它们各自的特点。

本篇先来介绍一下List接口。

我们先来看看List的源码:

public interface List extends Collection {

// 查询接口

/**

* 列表元素个数

*/

int size();

/**

* 是否为空

*/

boolean isEmpty();

/**

* 是否包含某元素

*/

boolean contains(Object o);

/**

* 返回一个List迭代器

*/

Iterator iterator();

/**

* 将List转换为Object数组

*/

Object[] toArray();

/**

* 转换为指定类型数组

*/

T[] toArray(T[] a);

// 修改操作

/**

* 添加元素,成功返回true

*/

boolean add(E e);

/**

* 移除某一个元素,成功返回true

*/

boolean remove(Object o);

// 批量操作

/**

* 判断是否包含集合C 中的所有元素

*/

boolean containsAll(Collection c);

/**

* 将集合C 中所有元素添加到列表

*/

boolean addAll(Collection c);

/**

* 将集合C 中所有元素添加到列表,添加在序号为index的元素之后

*/

boolean addAll(int index, Collection c);

/**

* 从列表中移除集合C 中所有元素

*/

boolean removeAll(Collection c);

/**

* 从列表中移除所有不在集合C 中的元素

*/

boolean retainAll(Collection c);

/**

* 全部替换

*/

default void replaceAll(UnaryOperator operator) {

Objects.requireNonNull(operator);

final ListIterator li = this.listIterator();

while (li.hasNext()) {

li.set(operator.apply(li.next()));

}

}

/**

* 根据指定的比较器来排序,如果传入的比较器是null,则元素必须实现Comparable 接口

*/

@SuppressWarnings({"unchecked", "rawtypes"})

default void sort(Comparator c) {

Object[] a = this.toArray();

Arrays.sort(a, (Comparator) c);

ListIterator i = this.listIterator();

for (Object e : a) {

i.next();

i.set((E) e);

}

}

/**

* 移除所有元素

*/

void clear();

// 比较和hash

boolean equals(Object o);

int hashCode();

// 根据序号进行的操作

/**

* 获取指定序号的元素

*/

E get(int index);

/**

* 替换指定序号的元素

*/

E set(int index, E element);

/**

* 在指定序号的元素后插入元素

*/

void add(int index, E element);

/**

* 移除指定序号的元素

*/

E remove(int index);

// 搜索操作

/**

* 返回元素第一次出现的位置,如果未找到则返回-1

*/

int indexOf(Object o);

/**

* 返回元素出现的最后一个位置

*/

int lastIndexOf(Object o);

// List迭代器

/**

* 返回一个List迭代器

*/

ListIterator listIterator();

/**

* 返回一个序号从Index开始的List迭代器

*/

ListIterator listIterator(int index);

// 视图

/**

* 返回一个子队列,序列从fromIndex到toIndex,包含fromIndex,不包含toIndex

* 对子队列的修改会影响原队列

* 如果原队列修改,那么对子队列的影响是未定义的

*/

java.util.List subList(int fromIndex, int toIndex);

/**

* 创建一个可分割的迭代器(用于并行计算)

*/

@Override

default Spliterator spliterator() {

return Spliterators.spliterator(this, Spliterator.ORDERED);

}

}

其实JDK里的注释已经十分丰富,大家平时有时间可以多看看,为了方便阅读,我这里用简单粗暴的语言进行了精简翻译。

List即列表,存储的是有序集合,里面的元素有序存储,可以重复,所谓有序集合,顾名思义,就是里面的元素存放是有顺序的,每个插入的元素都对应着一个序号,可以根据序号获取元素。

List支持的操作也很丰富,最常用的增删改查,批量添加,批量替换,批量删除,还有搜索,排序操作,还支持普通迭代器和可分割式迭代器,前者主要用于遍历,后者则主要用于并行式计算,关于迭代器的知识后面会统一介绍。下面是使用常见操作的一个小栗子:

public class Test {

public static void main(String[] args){

test();

}

static void test(){

List integers = new ArrayList<>();

List integersA = new ArrayList<>();

//添加元素

integers.add(1);

integers.add(2);

integers.add(3);

integers.add(4);

integersA.add(1);

integersA.add(2);

integersA.add(33);

integersA.add(44);

System.out.println("列表大小:" + integers.size());

System.out.println("是否为空:" + integers.isEmpty());

System.out.println("是否包含某元素:" + integers.contains(2));

System.out.println("是否包含全部元素:" + integers.containsAll(integersA));

//转换为数组

Integer[] integerArray = integers.toArray(new Integer[0]);

System.out.println("遍历数组:");

for (int i = 0; i < integerArray.length; i++){

System.out.println(integerArray[i]);

}

System.out.println("当前列表integers:" + integers);

//批量添加

System.out.println("批量添加元素");

integers.addAll(integersA);

System.out.println("当前列表integers:" + integers);

//移除元素

System.out.println("移除元素");

integers.remove(1);

System.out.println("当前列表integers:" + integers);

//批量移除

System.out.println("批量移除元素");

integers.removeAll(integersA);

System.out.println("当前列表integers:" + integers);

//开始替换

System.out.println("批量替换元素");

integers.replaceAll(it -> it + 1);

System.out.println("当前列表integers:" + integers);

//从列表中移除所有不在集合integersA中的元素

integersA.add(2);

integersA.add(4);

System.out.println("保留元素");

integers.retainAll(integersA);

System.out.println("当前列表integers:" + integers);

//插入

System.out.println("开始插入");

System.out.println("当前列表integersA:" + integersA);

integersA.add(2,155);

integersA.add(1,125);

System.out.println("当前列表integersA:" + integersA);

//排序

System.out.println("开始排序——使用内部比较器");

integersA.sort(null);

System.out.println("当前列表integersA:" + integersA);

System.out.println("开始排序——使用外部比较器");

integersA.sort((itA, itB) -> itB - itA);

System.out.println("当前列表integersA:" + integersA);

//序号操作

Integer a = integersA.get(2);

System.out.println("integersA第三个元素是:" + a);

System.out.println("开始替换");

integersA.set(3, 66);

System.out.println("当前列表integersA:" + integersA);

System.out.println("开始移除");

integersA.remove(3);

System.out.println("当前列表integersA:" + integersA);

//搜索操作

System.out.println("查找元素2(第一次出现)位置:" + integersA.indexOf(2));

System.out.println("查找元素2(最后一次出现)位置:" + integersA.lastIndexOf(2));

//子队列操作

List subList = integersA.subList(0, 4);

System.out.println("子队列:" + subList);

subList.add(5);

subList.add(5);

subList.add(5);

System.out.println("当前子列表:" + subList);

System.out.println("当前列表integersA:" + integersA);

integersA.add(1, 233);

integersA.add(1, 233);

integersA.add(1, 233);

System.out.println("当前列表integersA:" + integersA);

System.out.println("当前子列表:" + subList);

}

}

大家可以先想想结果,再下看面的答案。

实际输出如下:

列表大小:4

是否为空:false

是否包含某元素:true

是否包含全部元素:false

遍历数组:

1

2

3

4

当前列表integers:[1, 2, 3, 4]

批量添加元素

当前列表integers:[1, 2, 3, 4, 1, 2, 33, 44]

移除元素

当前列表integers:[1, 3, 4, 1, 2, 33, 44]

批量移除元素

当前列表integers:[3, 4]

批量替换元素

当前列表integers:[4, 5]

保留元素

当前列表integers:[4]

开始插入

当前列表integersA:[1, 2, 33, 44, 2, 4]

当前列表integersA:[1, 125, 2, 155, 33, 44, 2, 4]

开始排序——使用内部比较器

当前列表integersA:[1, 2, 2, 4, 33, 44, 125, 155]

开始排序——使用外部比较器

当前列表integersA:[155, 125, 44, 33, 4, 2, 2, 1]

integersA第三个元素是:44

开始替换

当前列表integersA:[155, 125, 44, 66, 4, 2, 2, 1]

开始移除

当前列表integersA:[155, 125, 44, 4, 2, 2, 1]

查找元素33(第一次出现)位置:4

查找元素33(最后一次出现)位置:5

子队列:[155, 125, 44, 4]

当前子列表:[155, 125, 44, 4, 5, 5, 5]

当前列表integersA:[155, 125, 44, 4, 5, 5, 5, 2, 2, 1]

当前列表integersA:[155, 233, 233, 233, 125, 44, 4, 5, 5, 5, 2, 2, 1]

Exception in thread "main" java.util.ConcurrentModificationException

at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1239)

at java.util.ArrayList$SubList.listIterator(ArrayList.java:1099)

at java.util.AbstractList.listIterator(AbstractList.java:299)

at java.util.ArrayList$SubList.iterator(ArrayList.java:1095)

at java.util.AbstractCollection.toString(AbstractCollection.java:454)

at java.lang.String.valueOf(String.java:2994)

at java.lang.StringBuilder.append(StringBuilder.java:131)

at com.frank.chapter20.Test.test(Test.java:115)

at com.frank.chapter20.Test.main(Test.java:15)

不知道符不符合你的预期,这里关于内部比较器和外部比较器的知识只一笔带过,Integer类型是实现了Comparable接口的,所以sort方法传入null时会使用Integer的内部比较器进行排序,而使用外部比较器时,使用的是Java8的新特性,lamada表达式,省去了方法名和参数类型,因为函数式接口不存在重载方法,所以编译器可以推断出参数类型,这样就不用再大费周章的用new语法去创建一个比较器(当然,只是语法糖而已,如果不是很理解比较器,可以先行百度,后面的文章里也会有详细介绍)。在最后报出了一个ConcurrentModificationException,因为原队列修改后,子队列视图就被破坏了,所以再次访问子视图时就会报错。

List是最常用的容器类,List最大的特点便是要求元素有序存储,List跟数组相比,最大的优势在于List大小可以动态扩展,但数组支持随机存取,所以当元素个数的固定的时候,使用数组往往效率更高。(当然,一般情况下还是使用List吧,因为支持的操作更加丰富,比如进行排序时不需要自己写算法)。

一般来说,对元素没有特殊要求,不需要去重存储,没有先进先出的要求的场景下,List是最好的选择。

List接口下有多个常用的实现类,每个类都有其特点,具体选择哪种类需要根据实际情况进行选择。

希望大家能通过这篇文章,了解List的主要方法及其使用方法以及常用场景,关于List的常见具体实现类的讲解将在之后的文章里进行说明和比较。

本篇到此结束,欢迎大家继续关注。

我做开发十多年的时间,如果大家对于学习java的学习方法,学习路线以及你不知道自己应该是自学还是培训的疑问,都可以随时来问我,大家可以加我的java交流学习qun:四九四,八零一,九三一,qun内有学习教程以及开发工具。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • 转载自:Java集合框架实例 1- 介绍 集合是程序和语言的基本思想。应用程序通常都会应用到集合,例如雇员的信息,...
    01_小小鱼_01阅读 383评论 0 1
  • 第十天 权限修饰符 public protected default private 同一类 true true ...
    炙冰阅读 520评论 0 1
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,360评论 0 4
  • 【程序1】 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔...
    开心的锣鼓阅读 3,303评论 0 9
  • 01如果个税起征点能调到一万+,那么三四线城市里普通工薪阶层可以小松一口气了,个人所得税暂时不会再变成工薪税。至于...
    一抹山色远阅读 379评论 0 3