java学习第11天
异常
程序没有按照设计的正常的逻辑执行,出现了不可预知的情况,就叫异常。
一旦程序出现异常,就会终止运行。
学习异常的目的:
- 当程序遇到处理不了的情况,抛出(产生)一个异常,终止程序。
- 当发生异常时,给出提示,让程序能够继续执行。
异常的分类
异常在java里是一种类,所有异常的根类是Throwable。
异常都是继承至Throwable,异常分为两个大类,
一是:Error错误,一般是虚拟机异常,这种错误我们的代码没有办法处理:
二是Exception异常,我们的代码可以抛出异常或者是处理异常。
Exception又分为两大类别;
- RuntimeException 运行时异常
- 非运行时异常
-
Error
Error异常一般不需要我们抛出异常。
异常的产生
就是在我们的方法中遇到处理不到的情况,就会抛出异常
- 在代码中永throw抛出一个Exception类型或子类型的对象
- 在方法上添加throws声明,后面的异常类型要大于等于代码中抛出的异常
//在方法上面需要添加Throws的声明,后面的异常的类型要大于等于代码中throw的类型
public String getSex(int sex) throws Exception {
if (sex == 0){
return "女";
}else if(sex == 1){
return "男";
}else {
//抛出异常,用throw的关键字,后面跟上Exception类型(或子类)的对象
//参数的字符串就是异常的消息
throw new Exception("性别只能是1或0");
}
}
异常处理
当我们调用的方法抛出了非Runtime的异常,就会报编译错误。
要求代码添加try catch语句来处理异常,catch语句可以有多个。(如果只有一个catch,这个异常类型要大于等于抛出的最大的那个异常类型)
finally语句块的代码一定会被执行(不管有没有异常都会执行)
只要有非运行时异常,try catch语句必不可少,但是finally是可选的
try {
System.out.println(createException.getSex(2));
createException.getName();
} catch (IOException e) {
e.printStackTrace();
System.out.println("运行出错");
}catch (Exception e){
e.printStackTrace();
}finally {
//finally的代码一定会被执行(不管有没有异常)
System.out.println("finally语句块");
}
System.out.println("try 语句之后的代码");
运行时异常
如果方法中抛出的继承自RuntimeException的类型异常,不会强制要求添加throws或try catch,不会导致编译错误.
只有在运行时有可能抛出异常
/* try {
createException.division(3,0);
} catch (RuntimeException e) {
e.printStackTrace();
}
*/
createException.division(3,0);
public int division(int a, int b) {
if (b == 0) {
throw new RuntimeException("除数不能为0");
}
return a / b;
}
自定义异常的类
自定义异常类需要继承Exception或RuntimeException
添加构造方法:
public class ProductException extends Exception{
public ProductException(){
}
public ProductException(String message) {
super(message);
}
}
使用自定义异常
try {
throw new ProductException("商品模块出现异常");
} catch (ProductException e) {
e.printStackTrace();
}
集合
一些数据结构的统称,包含List、Set、Map
List
List就是列表,用来存储一组数据的数据结构
List可变长的数据结构,可以知道List里面存有多少个数据。
LIst是有序列表,数据可以重复
ArrayList
ArrayList是采用数组方式实现的
读写和遍历都比较快,插入和删除数据时比较慢。
List基本的使用及其扩展
add()
get()
size()
public static void main(String[] args) {
//用ArrayList创建集合对象
List<Object> str = new ArrayList<>();//默认集合长度为10,会自动扩展。
//add()向列表添加元素。
str.add("张三");
str.add("张三");
str.add(36);
str.add(36);
str.add(null);
System.out.println(str);
System.out.println(str.size());//返回列表的实际的数据的个数
System.out.println(str.get(0));//get() 返回指定下标的元素,下标从0开始
//在指定下表位置插入一个数据,原来位置的数据往后面移动。
str.add(2,"王五");
System.out.println(str);
//扩展
//替换指定下标位置的元素。
str.set(3,"李四");
System.out.println(str);
//删除指定下标位置的元素
str.remove(5);
System.out.println(str);
//判断是否包含某个元素,如果包含返回true
System.out.println("是否包含abc:"+ (str.contains("abc")?"是":"否"));
//返回指定元素在列表中的位置,若找不到则返回 -1
System.out.println(str.indexOf("张三"));
//返回数据的最后一个的下标
System.out.println(str.lastIndexOf("张三"));
//截取子列表,左闭右开区间
List<Object> str1 = str.subList(1, 3);
System.out.println(str1);
List<Object> list = new ArrayList<>();
list.addAll(str);
System.out.println(list);
System.out.println("=======for循环遍历List======");
for (int i = 0; i < list.size(); i++) {
System.out.print(str.get(i)+ " ");
}
System.out.println();
System.out.println("======foreach遍历=====");
for (Object o:list) {
System.out.print(o+" ");
}
//清除列表的所有数据
str.clear();
//判断列表是否是孔,是空返回true,否则返回false
System.out.println(str.isEmpty());
//列表转为数组
Object[] array = list.toArray();
System.out.println("数组长度:"+ array.length);
//通过Arrays工具类,把一个数组转为List
List<Object> list1 = Arrays.asList(array);
System.out.println(list1);
}
LinkedList
采用双向链表来实现的,所以插入和删除的速度快,但是查询遍历的时候速度慢。
- 插入和删除速度快
- 查找和遍历速度慢
- 链表里面的数据保存的是地址
- 每个节点除了自身数据的地址外,还保存了上一个和下一个节点的地址。
LInkedList的一些特殊的方法
public static void main(String[] args) {
LinkedList<Object> linkedList = new LinkedList<>();
linkedList.add(50);
linkedList.add(69);
linkedList.add("张三");
//在列表的最前面插入元素
linkedList.addFirst(1);
//在列表的最后插入元素
linkedList.addLast(90);
System.out.println(linkedList);
//获取第一个元素
System.out.println(linkedList.getFirst());
//获取最后一个元素
System.out.println(linkedList.getLast());
/*
//删除第一个节点(元素)
linkedList.removeFirst();
//删除最后一个节点(元素)
linkedList.removeLast();
*/
System.out.println(linkedList);
//弹出第一个元素(会从列表中删除该元素)
System.out.println("弹出节点:"+linkedList.pop());
//入站(压栈),在第一个位置插入一个元素
linkedList.push(3);
System.out.println("======列表中的元素=======");
System.out.println(linkedList);
}
泛型
因为List可以存各种类型的数据,但是取出来都是Object,所以需要进行强制类型转换。
泛型就是用来解决这个问题,在创建List对象时指定存储的类型,在add()和get()时就自动采用泛型指定的类型。
LIst< String > list = new ArrayList<>(),这个< String >就是泛型,只能存String类型,后面的<>可以不填泛型。
//泛型只能使用应用类型,不能使用基本类型(可以用Integer等包装类)
泛型的使用
//使用泛型,定义变量时,类型后面跟上尖括号,尖括号里写上数据类型
//new对象时,类后面也要有尖括号,尖括号里不写类型,默认跟定义的变量泛型一致
//泛型只能使用应用类型,不能使用基本类型(可以用Integer等包装类)
List<String> list = new ArrayList<>();
//一旦指定泛型之后,相关方法的参数,返回类型都跟泛型的类型一样
list.add("张三");
list.add("李四");
list.add("王五");
System.out.println(list);
Set集合
无序集合,元素不重复,无索引(下标、序号)。(不能通过下标访问。)
哈希表 hash table
哈希表,散列表,是一种高效的数据结构。
要保存的数据称为值,根据hash算法给每个值算出一个hash code。
保存数据就用hash code 与值一一对应保存。
如下图所示:左边是数组方式保存数据,右边是hash表方式保存。中间是模拟的一个hash算法(当然,肯定不是这样算的)。
根据hash code 从表里面找是否存在,
- 不存在就当成一个新的值保存。
- 存在:再去判断equals是否相等:
- false 直接添加
- true 说明两个值一样,不添加。
Hash code的结论:
- 两个值的hash code 相同,他们的equals不一定相同。
- 如果两个值得equals相同,hash code 不一定相同
- 两个值的hash code相同,equals也相同,他们的值一定相同。