集合类型

  • 数组的局限性
  • ArrayList(常用方法 + 基本使用)
    • ArrayList — retainAll
    • ArrayList — toArray
    • ArrayList 的遍历(5种)
    • ArrayList 的扩容原理
  • 自定义迭代器 Iterable、Iterator
    • 集合遍历的注意点(遍历集合的同时删除元素)
    • ListIterator(遍历同时对元素进行操作)
  • LinkedList
    • LinkedList vs ArrayList
  • Stack
  • Queue
  • Set
    • HashSet
    • LinkedHashSet
    • TreeSet
  • Map
    • HashMap
    • HashMap — 遍历
    • LinkedHashMap
    • TreeMap
  • List vs Set vs Map
  • java.util.Collections

Java笔记目录可以点这里:Java 强化笔记(适合有基础的童鞋,不适合小白)

这篇文章只是学习一些集合的使用,更多底层细节可以看这个 【恋上数据结构】数据结构与算法

java.util 包中有个集合框架(Collections Framework),提供了一大堆常用的数据结构

  • ArrayListLinkedListQueueStackHashSetHashMap

数据结构是计算机存储、组织数据的方式:

  • 在实际应用中,根据使场景来选择最合适的数据结构

集合框架预览
下图:紫色代表接口、蓝色是抽象类、绿色是实现类

数组的局限性


数组的局限性:

  • 无法动态扩容
  • 操作元素的过程不够面向对象

ArrayList 是 Java 中的动态数组

  • 一个可以动态扩容的数组
  • 封装了各种实用的数组操作

ArrayList(常用方法 + 基本使用)

常用方法:

public int size() // 元素数量
public boolean isEmpty() // 是否为空
public boolean contains(Object o) // 是否包含元素o
public int indexOf(Object o) // 从前往后查询元素o的下标
public int lastIndexOf(Object o) // 从后往前查询元素o的下标
public E get(int index) // 获取下标为index的元素
public E set(int index,E element) // 设置下标index的元素为element
public boolean add(E e) // 往最后添加一个元素e
public void add(int index,E element) // 往下标index处添加一个元素e
public E remove(int index) // 移除index处的元素
public boolean remove(Object o) // 移除元素o
public void clear() // 清空public Object[] toArray()  // 转为数组
public <T>T[] toArray(T[] a) // 转为数组(指定类型)
public void trimToSize() // 缩容, 缩小到当前容量
public void ensureCapacity(int minCapacity) // 扩容public boolean addAll(Collection<? extends E>c)
public boolean addAll(int index, Collection<? extends E> c)
public boolean removeAll(Collection<?>c)
public boolean retainAll(Collection<?>c)
public void forEach(Consumer<? super E> action)
public void sort(Comparator<? super E> c)

ArrayList 的基本使用:

// 如果不使用泛型, ArrayList中可以放任何东西, 不推荐这样使用(不安全)
ArrayList list = new ArrayList();
list.add(11);
list.add(false);
list.add(null);
list.add(3.14);
list.add(0, "jack");
list.add('8');// 3
System.out.println(list.indexOf(null));
// 6
System.out.println(list.size());
// [jack, 11, false, null, 3.14, 8]
System.out.println(list);

ArrayList — retainAll

list1.retainAll(list2): 会从 list1 中删除掉 list2 中元素以外的所有元素。

List<Integer> list1 = new ArrayList<>();
list1.add(11);
list1.add(22);
list1.add(33);
list1.add(44);List<Integer> list2 = new ArrayList<>();
list2.add(22);
list2.add(44);// 从 list1 中删除掉 list2 中元素以外的所有元素
list1.retainAll(list2);
// [22, 44]
System.out.println(list1);

需要注意的是 public boolean retainAll(Collection<?>c) 接收的参数类型是 Collection ,Java 中大部分集合之间都可以互相调用 retainAll

List<Integer> list = new ArrayList<>();
list1.add(11);
list1.add(22);
list1.add(33);
list1.add(44);Stack<Integer> stack = new Stack<>();
stack.push(11);// 从 list1 中删除掉 stack 中元素以外的所有元素
list.retainAll(stack);
// [11]
System.out.println(list);

ArrayList — toArray

Integer[] array0 = (Integer[]) list.toArray(); 这段代码是不可行的,原因是 ArrayList 中不写泛型是可以任意添加元素的,强转 list.toArray() 的返回值极其不安全,会抛出 java.lang.ClassCastException 异常。

List<Integer> list = new ArrayList<>();
list.add(11);
list.add(22);
list.add(33);// 不可以强转为Intger[], 会抛出异常: java.lang.ClassCastException
// Integer[] array0 = (Integer[]) list.toArray();// 可以利用 Object[]来接收, 但是更推荐下面的写法
Object[] array1 = list.toArray();
// [Ljava.lang.Object;@15db9742
System.out.println(array1);
// [11, 22, 33]
System.out.println(Arrays.toString(array1));// 比起用 Object[]接收,更推荐这种写法
Integer[] array2 = list.toArray(new Integer[0]);
// [Ljava.lang.Integer;@6d06d69c
System.out.println(array2);
// [11, 22, 33]
System.out.println(Arrays.toString(array2));

具体为什么不能转,请对比下面一系列情况:

Object obj1 = 11;
// 可以正常转换
Integer obj2 = (Integer) obj1;
System.out.println(obj2); // 11
Object obj1 = new Object();
// java.lang.ClassCastException
Integer obj2 = (Integer) obj1;
System.out.println(obj2);
Object[] array1 = {11, 22, 33};
// 上一行代码的本质就是下面一行
// Object[] array1 = new Object[] {11, 22, 33};
// java.lang.ClassCastException
Integer[] array2 = (Integer[]) array1;
System.out.println(array1);

ArrayList 的遍历(5种)

经典的 for 循环遍历,可以获取遍历元素的下标:

// 经典
int size = list.size();
for (int i = 0; i < size; i++) {System.out.println(list.get(i));
}

利用迭代器进行遍历:

// 迭代器
Iterator<Object> it = list.iterator();
while(it.hasNext()) {Object obj = it.next();System.out.println(obj);
}

实现了 Iterable 接口的对象,都可以使用 for-each 格式遍历元素:比如 ListSet 等;
Iterable 在使用 for-each 格式遍历元素时,本质是使用了 Iterator 对象(迭代器)。

// for-each 格式
for (Object obj : list) {System.out.println(obj);
}

集合的 forEach 利用匿名内部类遍历:

list.forEach(new Consumer<Object>() {@Overridepublic void accept(Object t) {System.out.println();}
});

利用了 lambda 表达式的 forEach

list.forEach((obj) -> {System.out.println(obj);
});

最精简的遍历输出,了解一下即可:

list.forEach(System.out::println);

ArrayList 的扩容原理

具体的在 恋上数据结构(第一季) 已经讲得很详细了,我已烂熟于心…再不济点进源码看看就行。

自定义迭代器 Iterable、Iterator

前面说过,实现了 Iterable 接口的对象,都可以使用迭代器for-each 格式(本质还是迭代器)遍历元素。

如何让自定义对象实现实现可迭代的功能呢?

import java.util.Iterator;public class ClassRoom implements Iterable<String> {private String[] students;public ClassRoom(String... students) { // 可变参数的本质是数组 this.students = students; // 所以可变参数可以用数组来接收}@Overridepublic Iterator<String> iterator() {return new ClassRoomIterator();}private class ClassRoomIterator implements Iterator<String> {private int index; // 游标@Overridepublic boolean hasNext() {return index < students.length;}@Overridepublic String next() {return students[index++];}}}

我们来测试一下它的遍历:

ClassRoom room = new ClassRoom("Jack", "Rose", "Jerry");
// for-each格式遍历
for (String string : room) {System.out.println(string);
}
// 迭代器遍历
Iterator<String> it = room.iterator();
while(it.hasNext()) {System.out.println(it.next());
}

集合遍历的注意点(遍历集合的同时删除元素)

首先我们先往集合里加点东西:

List<Integer> list = new ArrayList<>();
list.add(11);
list.add(22);
list.add(33);
list.add(44);

然后我们通过遍历的方式,挨个删除所有的元素

可能有人会这么写,这样是错误的:抛出异常 java.lang.IndexOutOfBoundsException

int size = list.size();
for (int i = 0; i < size; i++) {// java.lang.IndexOutOfBoundsExceptionlist.remove(i);
}

或者会这么写,这样写也是错误的:会少删除元素

for(int i =0; i < list.size(); i++) {list.remove(i);
}
System.out.println(list); // [22, 44]

下面两种写法也是错误的:抛出异常 java.util.ConcurrentModificationException

// java.util.ConcurrentModificationException
list.forEach((e) -> {list.remove(e);
});
// java.util.ConcurrentModificationException
for (Integer e : list) {list.remove(e);
}

我们会发现,遍历的集合的方法特别多,但是如果要在遍历的同时删除元素,以上都是不可行的。
使用迭代器forEach 遍历集合元素时,若使用了集合自带的方法修改集合的长度(比如 addremove 等方法),会抛出 java.util.ConcurrentModificationException 异常。

如果希望在遍历元素的同时删除元素

  • 请使用 Iterator 进行遍历
  • 然后使用 Iteratorremove 方法删除元素
Iterator<Integer> it = list.iterator();
while(it.hasNext()) {it.next();it.remove();
}
// 删除成功
System.out.println(list); // []
System.out.println(list.size()); // 0

ListIterator(遍历同时对元素进行操作)

ListIterator 继承自 Iterator,在 Iterator 的基础上增加了一些功能

boolean hasNext();  // 是否有下一个元素
E next(); // 获取下一个元素
boolean hasPrevious(); // 是否有前一个元素
E previous(); // 获取前一个元素
int nextIndex();
int previousIndex();
void remove();
void set(E e);
void add(Ee);

基本使用:

List<Integer> list = new ArrayList<>();
list.add(11);
list.add(22);
list.add(33);ListIterator<Integer> it = list.listIterator();
// 从前往后遍历
while (it.hasNext()) { System.out.println(it.next());
} // 11 22 33// 从后往前遍历
while (it.hasPrevious()) {System.out.println(it.previous());
} // 33 22 11

遍历同时对元素进行操作

ListIterator<Integer> it = list.listIterator();
while (it.hasNext()) {it.set(it.next() + 55);
}
System.out.println(list); // [66, 77, 88]

遍历同时添加元素

ListIterator<Integer> it = list.listIterator();
while(it.hasNext()) {it.add(66);System.out.println(it.next());it.add(77);
}
System.out.println(list); // [66, 11, 77, 66, 22, 77, 66, 33, 77]

LinkedList

LinkedList 是一个双向链表

  • 实现了 List 接口
  • API 跟 ArrayList 类似

LinkedList vs ArrayList

Stack


Stack 常用方法:

Stack 使用:

Stack<Integer> stack = new Stack<>();
stack.push(11);
stack.push(22);
stack.push(33);System.out.println(stack.peek()); // 33System.out.println(stack.search(11)); // 3while(!stack.isEmpty()) {System.out.println(stack.pop());
} // 33 22 11

Queue


Queue 常用方法:

Queue 使用:

Queue<Integer> queue = new LinkedList<>();
queue.add(11);
queue.add(22);
queue.add(33);System.out.println(queue.element()); // 11while (!queue.isEmpty()) {System.out.println(queue.remove());
} // 11 22 33

Set

  • 只要是 Set 都可以用作去重

HashSet

HashSet 简单使用:

Set<String>set = new HashSet<>();
set.add("Jack");
set.add("Rose");
set.add("Kate");
set.add("Jack");
set.add("Hello");System.out.println(set.size()); // 4// 元素的存储是无序的
System.out.println(set);  // [Kate, Hello, Rose, Jack]set.remove("B");
System.out.println(set); // [Kate, Hello, Rose, Jack]

HashSet 的遍历:

Set<String> set = new HashSet<>();
set.add("Jack");
set.add("Rose");
set.add("Kate");// 元素的遍历是无序的// 增强for循环遍历
for (String str : set) {System.out.println(str);
} // Kate Rose jack// 迭代器遍历
Iterator<String> it = set.iterator();
while (it.hasNext()) {System.out.println(it.next());
} // Kate Rose jack// forEach遍历
set.forEach((str) -> {System.out.println(str);
}); // Kate Rose jack

LinkedHashSet

  • LinkedHashSetHashSet 的基础上(可去重),记录了元素的添加顺序

LinkedHashSet 简单使用:

Set<String> set = new LinkedHashSet<>();
set.add("Jack");
set.add("Rose");
set.add("Kate");
set.add("Jack");
set.add("Hello");System.out.println(set.size()); // 4// 元素的存储是有序的(添加顺序)
System.out.println(set);  // [Jack, Rose, Kate, Hello]// 元素的遍历是有序的(添加顺序)
for (String str : set) {System.out.println(str); // Jack Rose Kate
}set.remove("B");
System.out.println(set); // [Jack, Rose, Kate, Hello]

TreeSet

  • TreeSet 要求元素必须具备可比较性,默认从小到大的顺序遍历元素(可通过比较器修改)
// 字符串继承了Comparable, 具有可比较性, 默认按字母顺序从小到大
Set<String> set =new TreeSet<>();
set.add("Jack");
set.add("Rose");
set.add("Jim");
set.add("Kate");
set.add("Rose");
set.add("Larry");System.out.println(set); // [Jack, Jim, Kate, Larry, Rose]for (String str : set) {System.out.println(str); // Jack Jim Kate Larry Rose
}

通过比较器自定义比较方式:

// 默认比较方式是从小到大
// 通过比较器修改为从大到小
Set<Integer> set = new TreeSet<>((i1, i2) -> i2 -i1);
set.add(33);
set.add(11);
set.add(55);
set.add(22);
set.add(44);System.out.println(set); // [55, 44, 33, 22, 11]for (Integer i : set) {System.out.println(i); // 55 44 33 22 11
}

Map

HashMap

  • HashMap 存储的是键值对(key-value),Map 译为 映射,有些编程语言中叫做 字典

HashMap 简单使用:

HashMap<String, Integer> map = new HashMap<>();
map.put("Jack", 11);
map.put("Rose", 22);
map.put("Jim", 22);
map.put("Jack", 33); // 重复
map.put("Kate", 11);System.out.println(map.size()); // 4System.out.println(map.get("Jack")); // 33System.out.println(map); // {Kate=11, Rose=22, Jack=33, Jim=22}map.remove("Rose");
System.out.println(map); // {Kate=11, Jack=33, Jim=22}

HashMap — 遍历

HashMap<String, Integer> map = new HashMap<>();
map.put("Jack", 11);
map.put("Rose", 22);
map.put("Jim", 33);

最简洁的遍历方法:通过 forEach 遍历

// forEach 遍历, 推荐
map.forEach((key, value) -> {System.out.println(key + "=" + value);
}); // Rose=22 Jack=11 Jim=33

通过键值对 entrySet 遍历:

// entrySet 是一组键值对, 通过键值对来遍历, 推荐
Set<Entry<String, Integer>> entries = map.entrySet();
for (Entry<String, Integer> entry : entries) {System.out.println(entry.getKey() + "=" + entry.getValue());
} // Rose=22 Jack=11 Jim=33

先取出 value 的集合,再遍历:无法通过 value 获取 key,只能遍历 value

// 只能遍历 value
Collection<Integer> values = map.values(); // value的集合
for (Integer value : values) {System.out.println(value);
} // 22 11 33

取出 key 的集合,再遍历:可以通过 key 获取 value,但是效率低下

Set<String> keys = map.keySet(); // key的集合
for (String key : keys) {// 先遍历key, 又通过key去找到value (整体效率较低)System.out.println(key + "=" + map.get(key));
} // Rose=22 Jack=11 Jim=33

LinkedHashMap

  • LinkedHashMapHashMap 的基础上,记录了元素的添加顺序
Map<String, Integer> map = new LinkedHashMap<>();
map.put("Jack", 11);
map.put("Rose", 22);
map.put("Jim", 33);
map.put("Kate", 44);System.out.println(map); // {Jack=11, Rose=22, Jim=33, Kate=44}map.forEach((k, v) -> {System.out.println(k + "=" + v);
}); // Jack=11 Rose=22 Jim=33 Kate=44map.remove("Rose");
System.out.println(map); // {Jack=11, Jim=33, Kate=44}

TreeMap

  • TreeMap 要求 key 必须具备可比较性,默认从小到大的顺序遍历 key(可通过比较器修改)
Map<String, Integer> map = new TreeMap<>();
map.put("Jack", 11);
map.put("Rose", 22);
map.put("Jim", 33);
map.put("Kate", 44);
map.put("Larry", 55);System.out.println(map); // {Jack=11, Jim=33, Kate=44, Larry=55, Rose=22}map.forEach((k, v) -> {System.out.println(k + "=" + v);
}); // Jack=11 Jim=33 Kate=44 Larry=55 Rose=22

List vs Set vs Map

java.util.Collections

  • java.util.Collections 是一个常用的集合工具类,提供了很多实用的静态方法

【Java 集合】ArrayList、LinkedList、Stack、Queue、Set、Map, 迭代器 Iterable、Iterator,Collections类相关推荐

  1. 【腾讯面试题】Java集合:List、Set以及Map

    Java集合:List.Set以及Map 概述 Collection接口 List:有序,可重复 ArraysList Vector LinkedList Set:无序,唯一 HashSet Link ...

  2. java集合-ArrayList

    java集合 ArrayList Iterable Comparable(排序接口) 项目结构: class Dog implements Comparable<Dog> {private ...

  3. List 系列 ArrayList LinkedList CopyOnWriteArrayList Queue系列 ArrayDeque ConcurrentLinkedDeque LinkedBlo

    LinkedBlockingDeque作为一种阻塞双端队列,提供了队尾删除元素和队首插入元素的阻塞方法.该类在构造时一般需要指定容量,如果不指定,则最大容量为Integer.MAX_VALUE.另外, ...

  4. Java集合框架总结(5)——Map接口的使用

    Java集合框架总结(5)--Map接口的使用 Map用于保存具有映射关系的数据(key-vlaue).Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较总是返回fa ...

  5. Java集合框架--List、Set、Map

    Java集合框架接口和类的层次结构: java.util.Collection [I] +--java.util.List [I]+--java.util.ArrayList [C]+--java.u ...

  6. Java集合的使用:List与Map

    由David发表在天码营 Java的容器 定义好Post类之后,现在需要对博客文章进行管理.我们可以定义一个PostRepository类,通过PostRepository可以做以下操作: 创建博客 ...

  7. Java集合 ArrayList 扩容

    Java的集合框架 集合的分类 可以分为单列集合和双列集合 单列集合主要有Collection下面的List与Set,其中List最长被用到的是ArrayList与LinkedList以及Vctor三 ...

  8. java vector arraylist linkedlist用法与区别

    首先,它们是list的实现类,大致说一下vector arraylist linkedlist的区别. 1.线程安全来讲, vector是线程安全,arraylist linkedlist线程不安全. ...

  9. java集合框架LinkedList类的方法理解

    java提供的LinkedList类是双向列表,列表中的每个节点都包含了对前一个和后一个元素的引用. LinkedList与ArrayList一样实现List接口,只是ArrayList是List接口 ...

  10. java集合-ArrayList学习笔记

    集合和数组关系? 1)     集合是一种容器,可以存储多个数据. 2)     数组的长度是固定的,集合的长度是可变的. 3)     集合中存储的元素必须为引用类型数据,初始值为NULL Arra ...

最新文章

  1. linux 压缩 解压 命令大全
  2. xp系统如何开启索引服务器,Windows XP系统关闭磁盘索引的两个方法图文教程
  3. 如何快速掌握一门新技术/语言/框架…
  4. [基础]iOS 可视化编程(全系列)
  5. Linux中常见目录的作用
  6. 寒假作业3:抓老鼠啊
  7. Head First Python 学习笔记(第二章:分享你的代码)
  8. asp fso的神奇功能
  9. GIF图形文件格式文档
  10. 【视频开发】【Live555】摄像头采集,264编码,live555直播
  11. step14. ubuntu18.04下载安装scala(转)
  12. CODING 助力江苏高速信息实现组织敏捷与研发敏捷,领跑智慧交通新基建
  13. 如何在水平线中间添加文字
  14. Spring boot项目 maven多模块打包,子模块报错问题解决
  15. 计算机切换器鼠标反应慢,kvm切换器故障操作解决方法详解
  16. mysql直方图_MySQL · 特性分析 · 直方图的实现与分析
  17. Ardupilot移植经验分享(2)
  18. 只需Ctrl+T,让 Excel 变身为「超级表格」
  19. MySQL数据库的官网下载、安装及卸载(2018年最新)
  20. img 图片 下边距 解决办法

热门文章

  1. 抖音打破了传统互联网的商业逻辑
  2. 家庭网络,怎么给每个房间装一个无线路由器?
  3. 苹果电脑如何修改环境变量
  4. sql server序列_SQL Server中的Microsoft时间序列
  5. alwayson高可用组_AlwaysOn可用性组–如何在集群实例和独立实例之间设置AG(第2部分)
  6. 如何在SQL Server中检查日期是否为假期
  7. Spring注解@ConfigurationPropertie
  8. HTML(XHTML)基础知识(三)——【image】
  9. js进阶 10-9 -of-type型子元素伪类选择器
  10. 【转】C++中的inline用法