回顾
集合
Collection
List : 有序可重复
Set : 无序不可重复
Map : 键值对
List :
ArrayList
底层:数组
默认长度:10
扩容时机:数组添加满的时候,再次添加的时候
扩容后长度:原长度的1.5倍
特点:查询的速度快,插入和速度相对慢,线程不安全
LinkedList
底层:链表(双向链表)
特点:查询的速度慢,插入和删除的速度快
Vector
底层:数组
特点:查询的速度快,插入和速度相对慢,线程安全 效率相对ArrayList慢一点。
Set:
HashSet:
底层:就是HashMap,我们把所有的值都存放在HashMap的key中
重复的依据:
- hashCode值相等
- equals为true
LinkedHashSet
- 记录下保存的顺序
TreeSet
作用: 会自动为元素排序
要求:类实现Comparable接口
- 实现compareTo方法
- 0
- 正数
- 负数
- 0
class LinkedList {
Node first;
Node last;
int size;
public void add(Object obj) {
//添加元素,首先创建一个Node对象
Node node = new Node();
node.value = obj;
//获取最后一个Node
Node n = last;
//当前Node设置最后一个
last = node;
//原最后Node的下一个元素设置当前Node
n.next = node;
//当前Node的上一个设置为原来的最后Node
node.prev = n;
}
public Object get(int index) {
Node n = first;
for(int i=0; i<index; i++) {
n = n.next;
}
return n;
}
}
class Node {
Object value;
Node next;
Node prev;
}
Node n1 = new Node();
n1.value = "小备";
Node n2 = new Node();
n2.value = "小羽";
Node n3 = new Node();
n3.value = "小飞";
n1.next = n2;
n2.next = n3;
n2.prev = n1;
n3.prev = n2;
Node gy = n1.next;
Node zf = gy.next;
Node lb = gy.prev;
Map:键值对
int size();
boolean isEmpty();
V put(K k, V v);
V get(K k);
Set<K> keySet();
Collection<Entry<K,V>> entrySet();
- 一个值对应一个键
- 键是不能够重复的
- hashCode值相等,equals为true
- 后面添加的会覆盖前面的
- key和value都可以null
HashMap:
底层:数组加链表,数组保存的数据类型是链表
class HashMap {
Node[] table; //维护的是一个Node类型的数组
//默认长度 : 16
//加载因子 : 0.75
//树化阈值 : 8
//反树化阈值 : 6
}
class Node {
int hash; //key的hash值
Object key;
Object value;
Node next; // 单项链表
}
异常
1. 概念
异常:程序中出现的不正常的情况
我们需要对异常进行处理
异常需要处理,如果不处理,后续代码就不会执行了
2. 分类
-
Error 错误 没法处理
-
Exception 异常 可以处理
- 运行时异常
- NullPointerException
- ArrayIndexOutOfBoundsException
- ClassCastException
- NumberFormatException
- ArithmeticException
- 检查时异常
- ParseException
- Exception
package com.qf; import java.text.ParseException; import java.text.SimpleDateFormat; public class Demo02 { @SuppressWarnings("null") public static void main(String[] args) throws ParseException { //ParseException String dateString = "2asdf"; SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd"); sf.parse(dateString); //ArithmeticException int r = 9/0; //NumberFormatException String numStr = "adr"; int ii = Integer.parseInt(numStr); //ClassCastException Integer i = 7; Object o = i; Double d = (Double) o; //ArrayIndexOutOfBoundsException int[] arr = new int[4]; int v = arr[4]; //NullPointerException String str = null; //获取字符串长度 int len = str.length(); } }
- 运行时异常
3. 处理
为什么要处理
因为异常不处理,一旦发生,程序不再往下执行。
try //尝试
catch //捕获
finally //最终
try {
//需要处理的代码
} catch(定义可能会出现的异常类 e) {
//如果出现该异常,则会被捕获,就执行该catch定义的代码块
//代码执行后,程序还会继续往下执行
}
try {
//需要处理的代码
} catch(定义可能会出现的异常类 e) {
//如果出现该异常,则会被捕获,就执行该catch定义的代码块
//代码执行后,程序还会继续往下执行
} catch(定义可能会出现的异常类 e) {
//如果出现该异常,则会被捕获,就执行该catch定义的代码块
//代码执行后,程序还会继续往下执行
}...
- 不能捕获相同的异常
- 捕获异常的顺序,是从小到大的顺序
- Exception是所有异常的父类
try {
//需要处理的代码
} finally {
//一定会执行的代码,即使出现return,也要执行, 后续代码还会继续执行
}
try {
//需要处理的代码
} catch(定义可能会出现的异常类 e) {
} catch(定义可能会出现的异常类 e) {
}
...
} finally {
//一定会执行的代码,即使出现return,也要执行, 后续代码还会继续执行
}
4. 两个关键字
4.1 throw
我们可以通过throw主动的抛出一个异常,告诉方法的调用者,出错了,这不是当真正出错的时候再告诉方法的调用者。
- 如果主动抛出的是运行异常,则不需要在方法上声明
- 如果主动抛出的是检测异常,则需要在方法上进行声明
/*
* 两个数相除
*/
public static int divide(int a, int b) {
if(b==0) { // 当b=0时,还没有发生错误操作时,就应该告诉方法的调用者,你错了,程序不再往下执行了
throw new ArithmeticException("0不能作为除数");
}
System.out.println("继续执行代码块-----------------");
return a/b;
}
4.2 throws
定义一个方法在执行时,可能会产生的异常,方法的调用者必须执行这些异常
* 当我们主动抛出的异常,不是运行异常时
* 这是必须在方法的声明时,定义调用该方法,可能会出现该异常,
* 通过throws声明,可以声明多种异常
* 方法的调用必须处理这些异常
package com.qf;
import java.text.ParseException;
public class Demo04 {
//public static void main(String[] args) throws NoSuchFieldException, ParseException {
public static void main(String[] args) {
int a=5, b=1;
int result = divide(a, b);
System.out.println(result);
String str = null;
/*
* 当调用的方法,通过throws声明了,可能会产生异常,在调用时就必须进行处理
* 1. 不处理,也把他抛掉
* 如果出现异常,那就出现异常嘛
* 2. 处理,通过try-catch 自动生成
*/
int i=0;
try {
i = parseNum(str);
} catch (NoSuchFieldException | ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(i);
}
/*
* 两个数相除
*/
public static int divide(int a, int b) {
if(b==0) { // 当b=0时,还没有发生错误操作时,就应该告诉方法的调用者,你错了,程序不再往下执行了
throw new ArithmeticException("0不能作为除数");
}
System.out.println("继续执行代码块-----------------");
return a/b;
}
/*
* 当我们主动抛出的异常,不是运行异常时
* 这是必须在方法的声明时,定义调用该方法,可能会出现该异常,
* 通过throws声明,可以声明多种异常
* 方法的调用必须处理这些异常
*/
public static int parseNum(String str) throws ParseException,NoSuchFieldException {
if (str == null) {
throw new ParseException("str不能为null", 0);
}
return Integer.parseInt(str);
}
}
5. 自定义异常
- 定义类继承Exception
- 继承Exception子类都可
- 定义构造方法
- 传输错误信息
package com.qf;
public class Demo06 {
public static void main(String[] args) {
test(0);
}
public static void test(int a) {
if(a ==0) {
throw new MyException("自定义异常");
}
}
}
//自定义异常
class MyException extends RuntimeException {
//定义构造方法,传递错误信息
public MyException(String msg) {
super(msg);
}
}