自学Java基础知识第十五天
day15
1. Collections工具类
List : 有索引, 元素可重复
实现类 : ArrayList(主要使用查询), LinkedList(主要增删)
Set : 没有索引, 元素不重复
实现类 : HashSet(元素存取无序) LinkedHashSet(元素存取有序)
Map : 没有索引, key值不重复
双列数据, a= 4
实现类 : HashMap(元素存取无序) LinkedHashMap(元素存取有序)
注意 : 集合中存储自定义类型, 通过类型成员变量进行去重复, alt + shift + s 重写hashCode和equals方法
- Collections 是单列集合(List,Set)工具类, 来自于java.util包
- Collections工具类, JDK中没有给出任何构造, 不能实例化对象, 因为类型中的所有成员和方法都是静态的, 类名.直接调用
- Collections常用方法功能:
1) sort(List list) : 将参数list集合进行默认的升序排列(从小到大),没有返回值类型
2) binarySearch(List<T> list, T key) : 查找参数key在list集合中的出现的索引位置, 找到了返回值结果 >= 0 , 没有找到返回负数
注意 : 折半查找需要集合是升序
3) frequency(Collection<?> c, Object o): 获取到元素o在集合c中出现的次数,返回值类型int类型
4) max(Collection<?> c) : 获取到集合c中的最大值
5) min(Collection<?> c) : 获取到集合c中的最小值
6) replaceAll(List<T> list,T old, T new ) : 将集合list中的所有old元素替换成new元素
7) reverse(List list) : 将list集合中的元素进行反转(逆序排序)
8) shuffle(List list) : 将参数list集合中的元素进行无规则的混乱排序(洗牌场景使用)
9) swap(List list, int index1 , int index2) : 将集合list中index1和index2索引位置元素进行交换
代码
package com.ujiuye.collections; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; public class Demo01_Collections工具类 { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(12); list.add(99); list.add(2); list.add(-5); list.add(12);
// 1. sort(List list) : 将参数list集合进行默认的升序排列(从小到大) Collections.sort(list); System.out.println(list);// [-5, 2, 12, 99]
// 2. binarySearch(List<T> list, T key) : 查找参数key在list集合中的出现索引位置, 找到了返回值结果 >= 0 , 没有找到返回负数 int index = Collections.binarySearch(list, 99); System.out.println(index);// 3
System.out.println(Collections.binarySearch(list, -99));
//3)frequency(Collection<?> c, Object o): 获取到元素o在集合c中出现的次数,返回值类型int类型 System.out.println(Collections.frequency(list, 12));// 1
HashSet<Integer> set = new HashSet<>(); set.add(199); set.add(18); set.add(6); /*4)max(Collection<?> c) : 获取到集合c中的最大值 5)min(Collection<?> c) : 获取到集合c中的最小值*/ System.out.println(Collections.max(set));// 199 System.out.println(Collections.min(set));// 6
// 6. replaceAll(List<T> list,T old, T new ) : 将集合list中的old元素替换成new元素 Collections.replaceAll(list, 12, 888); System.out.println(list);// [-5, 2, 888, 888, 99]
// 7. reverse(List list) : 将list集合中的元素进行反转(逆序排序) Collections.reverse(list); System.out.println(list);// [99, 888, 888, 2, -5]
// 8. shuffle(List list) : 将参数list集合中的元素进行无规则的混乱排序(洗牌场景) /*Collections.shuffle(list); System.out.println(list);//[2, 888, -5, 888, 99] */
// 9. swap(List list, int index1 , int index2) : 将参数index1和index2索引位置元素进行交换 Collections.swap(list, 0, 2); System.out.println(list);//[888, 888, 99, 2, -5] } } |
2. 异常
2.1 异常的概述
- 异常(Exception) : 代码编译或者运行过程中,发生的不正常情况,或者错误情况,称为异常
- java中, 每一种异常都封装成一个类, 当有异常场景发生, 创建出对应的异常对象, 会将异常的发生位置, 发生原因, 封装在对象中, 将异常信息展示,提示代码问题
- 代码中发生的异常, 可以进行处理,可以进行代码跳转, 甚至可以避免
2.2 异常的体系结构
Throwable : 可抛出异常类型, 是所有的错误和异常的父类, 只有Throwable类型本身或者是他的子类之一, JVM虚拟机才能够对其进行异常处理
--Error : 所有错误的父类, 错误就是代码发生问题比较严重, 需要通过修改代码改善问题, 目前不关注error类别
--Exception : 所有异常父类, 异常表示代码中发生的不太严重的问题, 可以处理, 可以解决, 甚至可以避免, 举例 : NullPointerException
a : 运行时异常 : RuntimeException, 代码运行时才会发生的异常, 这些异常不需要进行任何的处理
b : 编译时异常 : 除了运行时异常之外的所有异常,全部都是编译时期异常, 编译时期异常如果发生, 代码自动提示进行处理, 必须进行声明或者处理
2.3 JVM虚拟机异常默认处理机制
- 如果代码中发生异常, 代码中没有对于异常的任何处理方式, 此时JVM虚拟机自动帮助代码进行异常处理
总结 : 代码发生异常, 将异常一层一层向上抛给方法的调用者, 直到抛给main, main方法抛给JVM, 最后由JVM输出异常信息, 停止代码
2.4 异常手动处理方式
- 异常声明 : 代码可能有异常, 不处理, 在方法上声明可能发生的异常类型, 目的, 就是为了告知方法调用者, 调用方法时,对于可能发生的异常问题进行预处理
- 异常处理 : 使用语法结构, 将代码中发生的异常处理掉, 异常处理掉之后,代码不会停止, 可以继续运行
try...catch系列语法结构
2.5 throw关键字
- throw : 关键字, 表示抛出异常
- throw关键字使用场景:
如果认为代码中可能有一些不正常场景出现, 那么可以对这种场景的发生使用throw关键字抛出一个对应的异常信息, 进而让代码停止或者跳转. 因此代码的停止或者是跳转就把握在自己的控制中
- throw关键字语法结构:
使用在方式中 :
throw new 异常(异常详细信息写清楚);
- throw关键字每次只能创建和抛出一个异常
- throw关键字在实际开发中使用:
通过前端录入数据信息, 需要数据传送到后台系统, 后台接到信息之后,需要验证数据信息的合法性, 例如 : 验证客户姓名 ,规则 : 不能带有特殊符号,名字长度不超过50个字符, 于是验证出姓名并不符合实际要求, 可以使用throw关键字, 创建出一个异常, 抛出异常
if(!name.matches(regex)){
throw new Exception(“名字不能出现特殊字符,长度不能超过50位”);
}
代码
package com.ujiuye.exception; public class Demo03_Throw { public static void main(String[] args) { int[] arr = {1,2,3}; getArrayEle(arr,5); }
public static void getArrayEle(int[] arr , int index) {
// 1. 预判数组arr不能为null if(arr == null) { throw new NullPointerException("数组不能为null"); }
// 2. 预判操作的索引index,不能越界 if(index < 0 || index >= arr.length) { throw new ArrayIndexOutOfBoundsException(index+"在数组中不存在,无法操作"); } int ele = arr[index]; System.out.println(ele); } } |
2.6 throws关键字
- throws :关键字, 表示异常的声明, 是异常的一种处理方式
- throws 关键字使用场景:
如果方法中可能会出现编译时期异常, 而方法中没有对异常进行任何处理, 那么可以在方法上将可能会发生的编译时期异常使用throws关键字进行声明, 如果有多个编译时期异常, 多个异常之间使用,进行分隔
throws关键字声明异常, 目的就是为了告知方法调用者, 对于这些可能发生的异常进行预处理
- throws 关键字使用:
修饰符 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2...{
}
- throws 关键字, 主要进行编译时期异常声明, 方法中发生的运行时异常, 可以不进行声明和处理
代码
package com.ujiuye.exception; import java.io.FileNotFoundException; public class Demo04_Throws { public static void main(String[] args) throws FileNotFoundException{ String s = "123.txt"; // 预处理 : FileNotFoundException checkFile(s); }
// 1. 定义方法 : 验证给出的字符串是不是abc.txt文件 public static void checkFile(String s) throws FileNotFoundException{ // 1. 引用数据类型验证不为null if(s == null) { // 证明NullPointerException--->运行时异常 throw new NullPointerException("文件不能为空"); }
// 2. 验证文件是不是abc.txt if(!"abc.txt".equals(s)) { //Unhandled exception type FileNotFoundException //没有解决异常类型 : FileNotFoundException throw new FileNotFoundException("文件不是abc.txt,无法操作"); } } } |
2.7 throw关键字和throws关键字的比较
- 功能不同:
a : throw 关键字表示抛出异常
b : throws 关键字声明异常
- 定义使用位置不同:
a : throw关键字定义使用在方法中
b : throws 关键字使用在方法声明上
- 处理异常个数不同:
a : throw关键字每次抛出一个异常
b : throws 关键字可以声明多个异常
- 运行机制不同:
a : throw关键字执行到了, 一定有一个异常发生了
b : throws 关键字执行到了, 不一定有异常发生
2.8 try...catch语句处理异常
- 语法结构:
try{
// 可能会发生异常的代码
}catch(可能会发生异常类 异常对象名){
// 异常发生后, 处理方式
}
- 说明:
1) try : 关键字, 表示尝试, 语法结构中, try主要作用检测代码是否有异常
2) catch : 关键字, 表示捕获异常, 捕获小括号中罗列出的异常, catch大括号中就是对于异常的处理方式
- try...catch运行机制:
1) 先执行try代码块中的逻辑, 如果try中没有异常, catch代码块不用执行, 代码接着try...catch语法之后继续运行
2) 如果try代码中发生异常, try检测出异常, 从发生异常当前行代码, 不再继续运行try之后的代码, 直接将发生的异常抛出, 抛给catch
3) catch接收到异常, 与小括号中的异常类型进行匹配
a : 匹配成功, catch捕获异常成功, 执行catch大括号内容, 处理异常,异常处理完毕,代码不需要停止, 接着整个try..catch语句之后继续运行
b : 匹配失败,证明catch没有捕获住异常, 异常通过JVM虚拟机默认处理, 打印异常信息,代码停止
代码
package com.ujiuye.exception; public class Demo05_TryCatch { public static void main(String[] args) { int i; try { i = 10 / 0; System.out.println(i); }catch(ArithmeticException ex) { i = 0; System.out.println("0不能做除数, 设置数据默认值为0"); } System.out.println("处理异常完毕, 代码继续" + i); } } |
2.9 try...catch...catch处理异常
- 一段代码有可能会发生多种异常, 需要多个catch语句分别进行每一种异常的捕获, 因此有了多catch语句处理异常
- 语法结构:
try{
// 可能会发生异常的代码
}catch(异常类型1 对象1){
// 异常处理方式1;
}catch(异常类型2 对象2){
// 异常处理方式1;
}...
- 执行机制:
1) 执行try代码块中逻辑, 没有异常发生, 所有catch都不执行, 代码继续向下运行
2) 如果try代码块中发生异常, 从发生异常当前行直接将异常抛给catch, catch从上到下依次进行异常类型匹配, 如果匹配某个catch成功, 执行对应的异常处理方式, 处理完毕, 整个try...catch语句结束, 代码继续向下运行,不停止
3) 如果所有catch语句都没有捕获住try代码块中的异常, 那只能使用JVM默认异常处理方式
- 多catch语句使用的注意事项:
在使用多catch语句捕获多个异常时,如果多个异常之间具有子父类继承关系, 必须先捕获子类异常,后捕获父类异常, 因为如果父类异常先捕获, 会利用多态表达式将抛出的子类异常捕获住, 如果后面的子类异常没有可执行捕获的机会, 就会报错
代码
package com.ujiuye.exception; import java.io.FileNotFoundException; public class Demo06_TryCatchCatch { public static void main(String[] args) { String s = "123.txt"; try { checkFile(s); }catch(FileNotFoundException ex) {// 先捕获子类 System.out.println("文件no"); }catch(Exception ex) {// 后捕获父类 System.out.println("文件为空"); }
try { checkFile(s); }catch(Exception ex) { // Exception ex = new FileNotFoundException("文件不是abc.txt,无法操作"); System.out.println("文件为空"); }/*catch(FileNotFoundException ex) {// 报错原因是这段代码永远不会执行到,上面多态将子类异常捕获住了 System.out.println("文件no"); }*/
System.out.println("处理异常完毕, 代码继续"); }
// 1. 定义方法 : 验证给出的字符串是不是abc.txt文件 public static void checkFile(String s) throws FileNotFoundException,Exception{ // 1. 引用数据类型验证不为null if(s == null) { // 证明Exception--->编译时期异常 throw new Exception("文件不能为空"); }
// 2. 验证文件是不是abc.txt if(!"abc.txt".equals(s)) { //Unhandled exception type FileNotFoundException //没有解决异常类型 : FileNotFoundException throw new FileNotFoundException("文件不是abc.txt,无法操作"); } } } |
2.10 try...catch...finally处理异常
- 语法结构:
try{
// 可能会发生异常的代码
}catch(异常类型1 对象1){
// 异常处理方式1;
}catch(异常类型2 对象2){
// 异常处理方式1;
}...
finally{
// 一定需要执行代码
}
- 说明:
finally : 表示一定会被执行的
- 运行机制:
1) 如果try代码块没有异常, catch不执行, 在整个try...catch..finally语法结构结束之前, 必须先执行finally
2) 如果try代码块中有异常, 与catch匹配和异常捕获, 在整个try...catch..finally语法结构结束之前, 必须先执行finally
3) 实际开发中尽量不要在finally中设计return关键字返回, 因为返回一定会执行
- 实际开发中划账交易:
购买成功, 必须划账成功; 购买失败, 必须划账失败;
boolean flag = false; // flag表示划账是否成功标志, false证明划账失败, true证明划账成功
try{
flag = 划账交易调用; // 如果成功划账, flag就为true
}catch(Exception e){// 证明划账失败
冲销客户账务; // 把钱退还给客户
}finally{
// 保证客户账务一定归还成功
if(!flag){
// 1. 查询当前交易流水
// 2. 根据交易流水的状态,决定是否继续进行账务的二次撤销
}
}
代码
package com.ujiuye.exception; public class Demo07_TryCatchFinally { public static void main(String[] args) { int i = funciton(); System.out.println(i);// 99 }
public static int funciton() { try { int i = 10 / 0; System.out.println("try----"+i); return i; }catch(Exception e) { int i = 10; System.out.println("catch---"+i); return i; }finally { System.out.println("我必须执行"); return 99; } } } |
2.11 try...finally语句
- 语法结构:
try{
代码逻辑;
}finally{
// 一定会被运行的代码
}
- 上述语法结构,没有catch语句, 因此代码中发生异常, 没有异常的处理方式,还是需要通过JVM虚拟机默认进行异常处理
- 运行机制:
不论try代码块中是否有异常, finally中的逻辑一定会执行
使用场景 : 如果代码不进行异常任何处理, 但是又有一定需要执行的代码, 可以使用上述语句
代码
package com.ujiuye.exception; public class Demo08_TryFinally { public static void main(String[] args) { try { System.out.println(10/0); System.out.println("123"); }finally { System.out.println("456"); } } } |
2.12 异常中方法功能
在所有异常和错误父类Throwable中, 定义出了可以追踪异常信息的方法功能 , 子类异常本身没有特殊方法功能, 都是使用从父类Throwable中继承来的方法
- 构造方法:
a : Throwable() , 表示创建出一个异常对象, 没有描述异常发生具体信息
b : Throwable(String message) : 创建出一个异常对象, 也将异常的发生原因描述清楚
- Throwable中提供了获取异常信息的方式
a : getMessage() : 获取到封装在异常对象中的异常信息 ,返回值类型String类型
b : toString() : 获取到异常类型和异常信息, 返回值类型String类型
c : printStackTrace() : 将异常的发生原因, 异常类型, 异常详细信息, 异常发生具体代码行数进行输出,开发中常见的异常信息输出方式
代码
package com.ujiuye.exception; import java.io.FileNotFoundException; public class Demo09_Throwable中的方法功能 { public static void main(String[] args) { String s = "123.txt"; try { checkFile(s); } catch (FileNotFoundException e) {//new FileNotFoundException("文件不是abc.txt,无法操作"); /*String result = e.getMessage(); System.out.println(result);*/
/*String result1 = e.toString(); System.out.println(result1);*/
// 方法中自带异常信息输出打印, 打印时以标准错误流,红色突出显示进行输出 e.printStackTrace(); }
System.out.println("over"); }
// 1. 定义方法 : 验证给出的字符串是不是abc.txt文件 public static void checkFile(String s) throws FileNotFoundException{ // 1. 引用数据类型验证不为null if(s == null) { // 证明NullPointerException--->运行时异常 throw new NullPointerException("文件不能为空"); }
// 2. 验证文件是不是abc.txt if(!"abc.txt".equals(s)) { //Unhandled exception type FileNotFoundException //没有解决异常类型 : FileNotFoundException throw new FileNotFoundException("文件不是abc.txt,无法操作"); } } } |
2.13自定义异常
为什么要自定义异常类 : 因为发现异常类中,没有封装其他方法功能, 只能追踪异常信息, 实际项目需求中, 发生异常, 处理异常, 需要给出问题的解决方案, 不仅仅是查看异常信息而已, 因此可以自定义出异常, 在自定义异常类中封装很多的方法, 当自定义异常发生, 创建出一个自定义异常类对象, 可以随意调用封装好的方法功能, 因而解决异常问题
自定义异常的实现步骤:
- 创建出一个类, 类名以Exception为结尾, 标志是一个异常类
- 自定义类继承Exception, 或者RuntimeException
a : 如果自定义类直接父类是Exception, 自定义异常类就是编译时期异常类
b : 如果自定义类直接父类是RuntimeException, 自定义异常类就是运行时期异常类
- 在自定义类中,定义出构造方法, 为了可以封装异常具体描述信息
- 可以在异常类中随便定义很多方法功能
代码
package com.ujiuye.exception; public class WrongNumberException extends Exception{ public WrongNumberException(String s) { super(s); }
public WrongNumberException() { super(); }
public void wrongNumber() { System.out.println("数据为负数不合理"); } } |
package com.ujiuye.exception; public class Demo10_测试自定义异常类 { public static void main(String[] args) { int age = -20; try { if(age < 0) { throw new WrongNumberException("年龄不合理"); } }catch(WrongNumberException ex) {// new WrongNumberException("年龄不合理"); ex.printStackTrace(); ex.wrongNumber(); } } } |