集合

集合:就是用来 存放数据 的一个 容器

Java提供的集合类

长度可以改变

能存储任意的对象

长度是随着你元素的个数增加而增加

🐤数组和集合的区别

数组能存 基本数据类型,和 引用数据类型

集合当中只能存放 引用数据类型,直接放基本数据类型,也会自动帮你装箱(把基本数据类型转成对象)集合当中只能存放 对象 也就是引用数据类型

数组的长度是固定的,定义好就不能再去增长,在程序跑起来的时候是不能修改的,还没有跑起来是可以修改的,相当于还在定义

集合长度是可以改变的,根据元素的个数增长而增加,在程序跑起来了,元素突然增加的集合的长度也会改变,而数组就不能

什么时候使用数组,什么时候使用集合

如果元素个数是 固定 的,推荐使用 数组

如果元素个数 不是固定 的,推荐使用 集合

集合继承结构图

cef14722ee12cdcf187799928235fc49.png

Collection 是一个接口,真正使用的是它的 实现类

集合通用方法

添加元素

创建 Student.java

/**

* @author BNTang

**/

public class Student {

public String name;

public int age;

}

测试类代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c = new ArrayList();

boolean b1 = c.add("abc");

// 会自动装箱(把基本数据类型转成对象)

boolean b2 = c.add(10);

boolean b3 = c.add(true);

Student s = new Student();

s.name = "BNTang";

s.age = 23;

boolean b4 = c.add(s);

System.out.println(c);

}

}

207e9b852539e63e78deb34870d86747.png

4d8052c44deeb0da868efcfde4443052.png

删除元素

测试代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c2 = new ArrayList();

c2.add("a");

c2.add("b");

c2.add("c");

System.out.println(c2);

// 可以从集合当中移除指定元素

c2.remove("a");

System.out.println(c2);

}

}

3a70631407a24a8fdb97bd57f2b5f5d1.png

判断一个集合是否为空

测试代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c2 = new ArrayList();

c2.add("a");

c2.add("b");

c2.add("c");

// 判断一个集合是否为空,为空返回 true,不为空返回 false

System.out.println(c2.isEmpty());

}

}

9e0d931a855563f4dab67272420d3347.png

获取集合当中的长度

测试代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c2 = new ArrayList();

c2.add("a");

c2.add("b");

c2.add("c");

// 获取集合当中的长度(也就是有几个元素)

System.out.println(c2.size());

}

}

2781da328e44dfcaf3607bf12e539abd.png

清空集合当中所有的内容

测试代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c2 = new ArrayList();

c2.add("a");

c2.add("b");

c2.add("c");

c2.clear();

System.out.println(c2);

System.out.println(c2.size());

}

}

c4e989150391af4252e54b3c0b09d56e.png

把c2当中的所有元素合并到c1当中

测试代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c1 = new ArrayList();

c1.add("a");

c1.add("b");

c1.add("c");

c1.add("d");

Collection c2 = new ArrayList();

c2.add("a");

c2.add("b");

c2.add("c");

c2.add("d");

c2.add("e");

System.out.println(c1);

c1.addAll(c2);

System.out.println(c1);

}

}

b61a9f12c7f6fd623878ee6d3054c65f.png

删除c1两个集合中的交集元素

例如 c1 调用删除的方式 c2 作为参数传入, c2 当中的元素在 c1 当中存在了,就会删除该元素

测试代码如下,结果自行运行:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c1 = new ArrayList();

c1.add("a");

c1.add("b");

c1.add("c");

c1.add("d");

Collection c2 = new ArrayList();

c2.add("a");

c2.add("b");

c2.add("e");

c1.removeAll(c2);

System.out.println(c1);

}

}

d648b971bd85f449674f4623d98a88f2.png

判断调用的集合是否包含(全部包含)传入集合

意思是判断传入的集合当中所有的值是否和当前集合中的内容匹配

注意是传入的集当中的值全部进行判断,其中一个在当前集合中不包含就为 false,全部存在就为 true

代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c1 = new ArrayList();

c1.add("a");

c1.add("b");

c1.add("c");

c1.add("d");

Collection c2 = new ArrayList();

c2.add("a");

c2.add("b");

c2.add("e");

boolean res = c1.containsAll(c2);

System.out.println(res);

}

}

4dd9158496ceaab1a590558d28796d07.png

取交集把交集的结果赋值给调用者

代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c1 = new ArrayList();

c1.add("a");

c1.add("b");

c1.add("c");

c1.add("d");

Collection c2 = new ArrayList();

c2.add("a");

c2.add("b");

boolean b = c1.retainAll(c2);

System.out.println(c1);

System.out.println(b);

}

}

66880d7a94b1246de41d85e9ef8e7ef8.png

集合的遍历

集合遍历

代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection c1 = new ArrayList();

c1.add("a");

c1.add("b");

c1.add("c");

c1.add("d");

// 会出现类型转换异常

// c1.add(10);

Object[] arr = c1.toArray();

for (Object o : arr) {

System.out.println(o);

}

}

}

164b2820ff96f0fd25df7ac1b7e68460.png

迭代器遍历

ee2d79c2dfbcf335fc41f293fc906755.png

代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) {

Collection arrayList = new ArrayList();

arrayList.add("a");

arrayList.add(1);

arrayList.add("c");

Iterator iterator = arrayList.iterator();

while (iterator.hasNext()) {

System.out.println(iterator.next());

}

}

}

迭代器源码

有一个 iterator 方法返回了一个 Iterator 类型的结果,内部又定义了一个内部类实现了 Iterator 接

由于不同的集合数据结构都不一样所以都有自己不一样的实现

首先定义 3 个变量分别记录不同的结果,当前角标,和最后一个元素两个

每次调用 next 方法都会把当前角标赋值一份给 i,如果 i 大于了当前集合的个数,则会抛出异常,没有元素异常

不大于则会取出当前集合元素用一个变量接收,在判断一下当前 i,是否大于当前变量接收的角标如果大于的话则会抛出一个 并发修改异常,如果不大于,等于则会进行取元素,会把当前 i 赋值给 lastRet 变量

public Iterator iterator() {

return new Itr();

}

/**

* An optimized version of AbstractList.Itr

*/

private class Itr implements Iterator {

int cursor; // index of next element to return

int lastRet = -1; // index of last element returned; -1 if no such

int expectedModCount = modCount;

// prevent creating a synthetic constructor

Itr() {}

public boolean hasNext() {

return cursor != size;

}

@SuppressWarnings("unchecked")

public E next() {

checkForComodification();

int i = cursor;

if (i >= size)

throw new NoSuchElementException();

Object[] elementData = ArrayList.this.elementData;

if (i >= elementData.length)

throw new ConcurrentModificationException();

cursor = i + 1;

return (E) elementData[lastRet = i];

}

public void remove() {

if (lastRet < 0)

throw new IllegalStateException();

checkForComodification();

try {

ArrayList.this.remove(lastRet);

cursor = lastRet;

lastRet = -1;

expectedModCount = modCount;

} catch (IndexOutOfBoundsException ex) {

throw new ConcurrentModificationException();

}

}

}

并发修改异常,这个问题是调用了集合自身的 remove 方法,导致了底层在判断的时候数据不一致抛出的,自己看一下集合 remove 源码就知道为啥会出现这个问题了

public boolean remove(Object o) {

final Object[] es = elementData;

final int size = this.size;

int i = 0;

found: {

if (o == null) {

for (; i < size; i++)

if (es[i] == null)

break found;

} else {

for (; i < size; i++)

if (o.equals(es[i]))

break found;

}

return false;

}

fastRemove(es, i);

return true;

}

private void fastRemove(Object[] es, int i) {

modCount++;

final int newSize;

if ((newSize = size - 1) > i)

System.arraycopy(es, i + 1, es, i, newSize - i);

es[size = newSize] = null;

}

所以在移除元素的时候尽可能的调用迭代器的 remove 方法,迭代器的 remove 方法,查看源码就知道为什么了

public void remove() {

if (lastRet < 0)

throw new IllegalStateException();

checkForComodification();

try {

ArrayList.this.remove(lastRet);

cursor = lastRet;

lastRet = -1;

expectedModCount = modCount;

} catch (IndexOutOfBoundsException ex) {

throw new ConcurrentModificationException();

}

}

List集合

ArrayList

添加元素

代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

List person = new ArrayList<>();

person.add("jackie"); //索引为0

person.add("peter"); //索引为1

person.add("annie"); //索引为2

person.add("martin"); //索引为3

person.add("BNTang"); //索引为4

System.out.println(person);

}

}

获取元素

代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

List person = new ArrayList<>();

person.add("jackie"); //索引为0

person.add("peter"); //索引为1

person.add("annie"); //索引为2

person.add("martin"); //索引为3

person.add("BNTang"); //索引为4

System.out.println(person.get(4));

}

}

删除元素

代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

List person = new ArrayList<>();

person.add("jackie"); //索引为0

person.add("peter"); //索引为1

person.add("annie"); //索引为2

person.add("martin"); //索引为3

person.add("BNTang"); //索引为4

person.remove(0);

System.out.println(person);

}

}

遍历集合元素

上面我写了一种方式

这种是传统的 for 循环的方式根据长度遍历

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

List person = new ArrayList<>();

person.add("jackie"); //索引为0

person.add("peter"); //索引为1

person.add("annie"); //索引为2

person.add("martin"); //索引为3

person.add("BNTang"); //索引为4

for (int i = 0; i < person.size(); i++) {

System.out.println(person.get(i));

}

}

}

迭代器遍历

fc4b114f2cd25b35bec3e009bf9a28ea.png

代码如下:

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

List list = new ArrayList();

list.add("jackie"); //索引为0

list.add("peter"); //索引为1

list.add("annie"); //索引为2

list.add("martin"); //索引为3

list.add("BNTang"); //索引为4

Iterator it = list.iterator();

while (it.hasNext()) {

System.out.println(it.next());

}

}

}

🐤并发修改异常

017af26c78e0f1d8e8ca2757348ba682.png

🐸并发修改异常原因

7d5e0f1618b73008b809ccbb8cf860ea.png

🦄解决并发修改异常

cb25d1e7d519ca4fc1871d9ae544c8fa.png

ListIterator迭代器

80fe9b83406a81759788817fe666c079.png

ArrayList数据结构

05a8cab72cfd8d557a102bb64e7eff5f.png

c37dca782a457831d3976f13f03f94bd.png

去除List集合中重复的元素

如果比较的是自定义对象需要自己覆盖 equals 方法,他默认比较的是 内存地址,而我们想要达到对象里面的属性值比较的话需要自己覆盖 equals 当然可以使用编辑器生成例如:intellij IDEA

21c05a28db7ec6bac454850962297a82.png

LinkedList

遍历元素

b093010b8cd5441dc95d866d1b9066be.png

特有方法

08d7fcefc48785fb8d44d70194cb79c2.png

LinkedList数据结构

2c8562778dd6b4335d6e9ba3fadb55c6.png

46183b4dbd3532dbba13586d21bff241.png

e902d7bd4e40a2d075dc74193548637f.png

Vector

a66698043ff5f6a7c970af6b7b07ea76.png

泛型

List 中添加元素存在的问题

往集合当中存储元素,可以存任何类型元素

使用某个类型当中特有的方法,必须得要转回来才可以进行使用

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

List list = new ArrayList();

list.add(1);

list.add("abc");

Object obj = list.get(1);

String str = (String) obj;

str.substring(0, 1);

}

}

没有泛型存在的问题

f35c8cb8b50e95e8fb76c5b6e29e8ad3.png

f303cdfe055fd17319b833b54b171766.png

6d26184fcb15e814999cef203232db04.png

什么是泛型:广泛通用的类型

一开始还不确定是什么类型,在使用的时候,才能确定是什么类型

在开始定义类的时候,留一个插口

在创建对象的时候,再去插入对应的类型

🐤泛型注意点

泛型前后类型必须得要保持一致

从 Java7 开始,后面的类型可以不写:new ArrayList<>(); 菱形语法

泛型是没有继承的

泛型其实是一个 语法糖(本质还是 Object,内部其实还是要做强转)

没有使用泛型的 List

e8db27e9c17a6ee6981c41ad4b71df5a.png

4c1a73249870c6f35d9c671e900d854d.png

泛型类

在类上面定义的泛型,在创建对象的时候,要指明泛型的类型

泛型类当中定义的泛型只能用在普通方法上面

不能使用在静态方法上面

静态方法是直接使用类名调用,泛型是在创建对象的时候,才去指定类型,所以就不能使用了

ed7f2b6d606a7b43760e12e6b77092b9.png

泛型方法

就是在方法上面添加了泛型

单独对一个方法上面声明泛型,方法当中定义的泛型

ed7f2b6d606a7b43760e12e6b77092b9.png

自定义泛型方法

4e052220b00e5d758daf806cd98ac214.png

通配符

不知道使用什么类型来接收的时候,可以使用 ? 来表示未知

通配符只是用来做接收使用

不能做添加操作

7cf1eabecc09205847bab311f56e0610.png

6f0d93e5213dadf5a21b0e853880e35f.png

泛型上限

泛型的上限:用来限定元素的类型必须得是指定类型(Number)的子类

9fb5d1a6e2900d9bed81407c90bde9fd.png

泛型下限

用来限定元素的类型必须得是指定类型(Number)的父类(或者是指定的类)

1ec8a1254d5be46407c5f1b6b49c0a9c.png

泛型擦除

把一个有泛型集合赋值给了一个没有泛型的集合最后就没有泛型了 → 也就是泛型擦除(把泛型给去掉了)

56c32940aaca990e4603ed3578e97d7b.png

数组与集合的转换

把数组转成集合

51b41709b0f1161225f205c2e70872bd.png

引用数据类型的数组转集合

1c1eac893ee15647c3ecc045349b6ab3.png

集合转数组

list3 是上图中的集合连着的,阅读的时候需要注意一下

9ec23d3179041a7c741f005477b8170d.png

Set

Set 当中存的元素是 无序 的,里面没有 重复 的元素

HashSet

5e24a481e9d42fe9c9be48de4ea9d1f6.png

5ebe180282d32e56bec9673372105330.png

HashSet 自定义对象的比较方法,需要重写 hashcode 和 equals,他底层其实是用 hashCode 来比较的

5b89244cb130221c565c2a470e6ab751.png

获取1到20之间随机数

自己可以抽出一个方法来

传的数字是几就生成几个不重复的随机数

b1acc8be1fa7ae5c0b87e96b44d130f5.png

LinkedHashSet

LinkedHashSet 它是 HashSet 的子类

它底层是使用 链表 实现,是 Set 集合当中唯一的一个保证元素是怎么存怎么取的

HashSet 能够保证元素的唯一

8efddfb3586cdb8d68653d5817b45abe.png

TreeSet

c82c39720cd26c96381b8ea94d305a32.png

0afe849b662077e567fc8e57b54d2c77.png

8dd215c28edcaae66cf0e259d2ab0eb6.png

0573756e4262b0b789d16ba806f3c15a.png

Map

52c75de3c8e8255662d4fe7ac133d71d.png

映射关系

A集合、B集合可能是(ArrayList LinkedList Vector HashSet LinkedHashSet TreeSet)这其中的一种集合类型

A集合当中的每一元素,都可以在B集合当中找到一个唯一的一个值与之对应

A集合当中的元素不能是重复的(Set)

A集合当中的每一个元素称它是一个 key(键)

B集合当中的每一个元素称它是一个 value(值)

b30b2a7aa3f486f06ffcc0c9f82d99b5.png

添加功能

7f00c57cb54a45f33554fdcf03224591.png

删除功能

eb87ed9d70d37726f6b6a6779607f27e.png

获取长度

d8a69268ce2569f4a7c3b9908303cada.png

遍历Map

f31c7967b5df7d2b326bde5f5319e093.png

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

Map map = new HashMap<>();

map.put("张三", 20);

map.put("李四", 21);

map.put("王五", 22);

Set allKeys = map.keySet();

Iterator it = allKeys.iterator();

while (it.hasNext()) {

String key = it.next();

Object val = map.get(key);

System.out.println(key + "=" + val);

}

System.out.println("------------");

for (String key : map.keySet()) {

System.out.println(key + "=" + map.get(key));

}

}

}

2392d95e9a793ea592b9f33110506b9a.png

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

Map map = new HashMap<>();

map.put("张三", 20);

map.put("李四", 21);

map.put("王五", 22);

Set> entrySet = map.entrySet();

Iterator> it = entrySet.iterator();

while (it.hasNext()) {

Map.Entry en = it.next();

String key = en.getKey();

Integer value = en.getValue();

System.out.println(key + " = " + value);

}

System.out.println("--------------");

for (Map.Entry entry : entrySet) {

System.out.println(entry.getKey() + "=" + entry.getValue());

}

}

}

TreeMap

如果是自定义对象,想要按照自己的方式进行排序,你就可以参考我上面介绍的 TreeSet 的方式进行实现一个接口,然后覆盖里面的 compareTo 方法

db704dbd3c0887f5d27f7b3de2bc96d6.png

ce44ee238885bf973f157763c5ca8b34.png

HashTable

8d478009b023b31f4a4748de45e7246c.png

LinkedHashMap

使用 HashMap 它的 key 是没有顺序的

LinkedHashMap 添加的元素是有顺序(你怎么放的,打印时就是什么顺序的)

a3e2fea1182ad229ecd18437266fef1c.png

/**

* @author BNTang

**/

public class Demo {

public static void main(String[] args) throws Exception {

Map map = new HashMap<>();

map.put("张三", 20);

map.put("李四", 21);

map.put("王五", 22);

System.out.println(map);

HashMap hm = new HashMap<>();

hm.put("张三", 20);

hm.put("李四", 20);

hm.put("王五", 20);

System.out.println(hm);

LinkedHashMap hm2 = new LinkedHashMap<>();

hm2.put("张三", 20);

hm2.put("李四", 20);

hm2.put("王五", 20);

System.out.println(hm2);

}

}

异常

Java 程序在运行过程当中出现的 错误

异常继承体系

Throwable

996f4fd41a27c4ce64a811b216b42820.png

🐸Throwable继承体系

65cf28da9572bbc447063c528f09af50.png

异常处理方式

自己处理,然后继续运行

自己没有办法处理,交给 JVM 来处理

JVM 有一个默认的异常处理机制处理异常,并将该异常的名称,异常信息,异常出现的位置给打印在控制台上,同时停止程序的运行

dd285e33caf9da380405aec4a1f9b592.png

8b89a8efa7cbe04d1f375e48c1846a21.png

10/0;

违背了算法运算法则,抛出异常

抛出的异常是一个对象

New ArithmeticException(“/by zero”),把这个异常对象返回

此时想把异常对象赋值给 a

a 是一个 int 类型不能接收,main方法解决不了

交给 JVM 来处理,JVM 就将该异常在控制台打印程序终止

自己处理异常

基本格式

try...catch...finally

try{

可能出现异常的代码

}catch(异常类型){

}finally{

处理完异常最后做的处理

}

try:用来检测可能出现异常的代码

catch:用来捕获出现的异常

finally:一般用来释放资源

24fbdd6cf55403abf6984591bffb035b.png

10/0;会创建一个异常对象

New ArithmeticException(“/by zero”)

赋值给a,接收不了,此时就把异常对象传给catch当中的参数a

能够接收,就会执行catch当中的内容,程序也没有终止

只有在 try 中的代码出了问题的时候才会执行 catch 当中的内容

出问题时 catch 处理完毕之后,后续的代码继续执行

try…catch 可以同时处理多个异常

在 try 当中可能会出现不同的异常类型此时可以使用多个 catch 来进行处理

7c1fe6bdef5b617d4fa9a491da1901d7.png

ab6390e60bf89e974fd3fb520b2ca7fc.png

70a4663e8ae1849e5a44f1f1b8e99af7.png

3c2d7b967aeeddc3355ed06379a900ac.png

Exception e 不能写在最上面,写在上面会报错,因为下面的永远不会执行到

因为 Exception 是所有异常的父类,所以就不会再一一往下进行判断了

4e26c6bdcca2def9bc0f3c1b9f2f8682.png

🐤JDK7处理多个异常

7470959c1c46a6ccf26f2a3d4bb69c07.png

常用方法

获取异常信息

06a32e30561079f92efb1110755bc7f6.png

获取异常的类名和异常信息

698631691cbae48b638fcdb95867fd26.png

获取异常类名和异常信息,及异常出现的位置

749b32d2fd24b3731ba05fcacbc7323c.png

throws方式处理异常

🐤抛出运行时异常

1400e684b342611b5900e9a97730842c.png

抛出运行时异常,不需要处理这个抛出的异常

🐸抛出编译时异常

66594026e58d92edcd1c9ce12d86f008.png

抛出了一个编译时异常,必须得要有人处理如果不处理,必须继续往上抛,抛给方法调用者

dda34f462d5be79ae378a342b87cef2a.png

此时由于 setAge 内部抛出了一个异常,在调用该方法时必须得要处理抛出的异常

处理异常

e2e2c5b8913edfd99bb9eca6674e228b.png

可以选择继续往上抛

6983f3d9695fb9f739d8ca7329bfa0ab.png

throw与throws的区别

throw

用在方法体内,跟的是异常对象名称,也就是异常对象实例

只能抛出一个异常对象

表示抛出异常

throws

用在方法声明后面,跟的是异常类名

可以跟多个异常类名,中间使用逗号隔开

表示抛出异常,由方法调用者来处理

247f4b7716cdf2ffe7c52b2de9e33de9.png

编译时异常与运行时异常

运行时异常:所有的 RuntimeException 类及其子类称为运行时异常,在编译时不会报错,在运行过程中程序会被终止运行

编译时异常:程序员必须显示的处理了这个异常,否则程序就会发生错误无法通过编译,就跑不起来

编译时异常发生的情况

bda2decc781f3e896155563656854acd.png

在编译时就必须处理这个异常

这个代码是读取一个文件,在读取时,它也不确定你这个文件是否存在

如果不存在,你要怎么处理,所以在编译时就要确定好

如果文件不存在该怎么样处理

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐