学习日记-day15-5.25
完成目标:
学习java下半段课程
知识点:
1.创造异常对象
创建异常对象,只是为了后面学习如何处理异常,其他的暂时没有意义。
public class Demo03Exception {public static void main(String[] args) {String s = "a.tx1t";method(s);}public static void method(String s){if (!s.endsWith(".txt")){//故意创建异常对象,用throw说明此处有异常throw new NullPointerException();}System.out.println("我要执行了");}
}
知识点 | 核心内容 | 重点 |
异常对象创建 | 通过throw关键字手动创建异常对象(如NullPointerException),非异常处理,仅用于显式标记问题 | throw vs throws(带s为处理异常) |
字符串结尾判断 | 使用s.endsWith(".txt")方法检测字符串是否以指定后缀结尾 | 方法返回值逻辑(true/false)及!取反操作 |
虚拟机异常处理机制 | 未捕获的异常由虚拟机逐层向上抛出,最终打印异常信息并终止程序 | 异常抛出流程与默认处理方案的不可逆性 |
代码执行中断 | 异常抛出后,后续代码不再执行(如示例中"我要执行了"未输出) | 异常对程序流程的阻断作用 |
2.异常处理方式throws
public class Demo04Exception {public static void main(String[] args)throws FileNotFoundException {String s = "a.txt1";add(s);//添加功能delete();//删除功能update();//修改功能find();//查询功能}private static void add(String s)throws FileNotFoundException {if (!s.endsWith(".txt")) {//故意创建异常throw new FileNotFoundException("文件找不到");}System.out.println("我要执行了");}private static void find() {System.out.println("查询功能");}private static void update() {System.out.println("修改功能");}private static void delete() {System.out.println("删除功能");}
}
知识点 | 核心内容 | 重点 |
throws异常处理方式 | 通过throws关键字将异常抛给调用者处理,格式为在方法参数和方法体之间声明异常 | 手动throws与虚拟机默认处理的区别:本质相同,但throws属于主动处理方案 |
throws的局限性 | 无脑向上抛异常会导致程序终止,影响其他正常功能执行(如示例中delete/update/found方法未执行) | 开发实践原则:避免因单一功能异常导致系统整体不可用 |
多异常处理方案 | 1. 并列声明多个异常(throws Ex1, Ex2); 2. 利用继承关系:throws父类异常覆盖子类(IOException覆盖FileNotFoundException); 3. 终极方案:直接throws Exception(所有异常的父类) | 多态应用:父类异常可接收子类异常对象 |
编译时异常特性 | FileNotFoundException等非RuntimeException子类需强制处理,否则编译报错 | 继承体系判断:检查异常类是否直接/间接继承RuntimeException |
异常触发逻辑 | 示例中通过条件判断(如!s.endsWith(".txt")或s==null)主动抛出异常 | 异常信息定制:通过异常类构造方法传递自定义错误描述(如new FileNotFoundException("异常原因")) |
3.异常处理方式try catch
public class Demo06Exception {public static void main(String[] args){String s = "a.txt1";try{//int[] arr = null;//System.out.println(arr.length);//NullPointerExceptionadd(s);//添加功能}catch (FileNotFoundException e){System.out.println(e);}delete();//删除功能update();//修改功能find();//查询功能}private static void add(String s)throws FileNotFoundException {if (!s.endsWith(".txt")) {//故意创建异常throw new FileNotFoundException("文件找不到");}System.out.println("我要执行了");}private static void find() {System.out.println("查询功能");}private static void update() {System.out.println("修改功能");}private static void delete() {System.out.println("删除功能");}}
多个catch块分别捕获不同异常
try{可能出现异常的代码}catch(异常 对象名){处理异常的代码-> 将来开发会将异常信息保存到日志文件中}catch(异常 对象名){处理异常的代码-> 将来开发会将异常信息保存到日志文件中}catch(异常 对象名){处理异常的代码-> 将来开发会将异常信息保存到日志文件中}catch(异常 对象名){处理异常的代码-> 将来开发会将异常信息保存到日志文件中}
知识点 | 核心内容 | 重点 |
异常处理方式 | 两种异常处理方式:throws声明异常和try-catch捕获异常 | throws与try-catch的使用场景区别 |
try-catch基本结构 | try块包含可能异常代码,catch块捕获并处理特定异常 | 异常对象命名规范(常用e) |
异常信息处理 | 最简单处理方式是打印异常到控制台,实际开发应记录到日志文件 | 控制台输出与日志文件的本质区别 |
多异常捕获 | 可通过多个catch块分别捕获不同异常,或直接捕获父类异常 | 子父类异常捕获的优先级问题 |
异常处理影响 | try-catch可防止异常扩散,保证非异常代码正常执行 | 无处理 vs throws vs try-catch的连锁反应 |
日志文件作用 | 永久保存程序运行详细信息(SQL语句、异常堆栈等) | 日志分析与bug定位的关联性 |
精准捕获原则 | 推荐针对性捕获具体异常类,Exception是终极兜底方案 | NullPointerException等运行时异常的特殊性 |
printStackTrace() | 比直接输出e能显示更完整的异常堆栈信息 | 方法调用链的调试价值 |
4.finally
public class Demo08Exception {public static void main(String[] args){String s = "a.txt";try {add(s);//添加功能} catch (FileNotFoundException e) {e.printStackTrace();}finally {System.out.println("我必须执行");}}private static void add(String s)throws FileNotFoundException {if (!s.endsWith(".txt")) {//故意创建异常throw new FileNotFoundException("文件找不到");}System.out.println("我要执行了");}
}
知识点 | 核心内容 | 重点 |
finally关键字 | 不管是否触发异常,finally代码块都会执行(特殊情况除外) | finally与final的区别 |
finally的执行条件 | 通常一定会执行,但若执行System.exit(0)(终止当前正在执行的java虚拟机),则不会执行 | System.exit(0)的影响 |
finally与try-catch配合使用 | finally通常与try-catch一起使用,确保资源释放 | try-catch-finally的标准格式 |
finally的执行顺序 | 即使catch中有return,finally仍会执行 | finally中的return会覆盖catch中的return |
finally的使用场景 | 主要用于关闭资源(如数据库连接、IO流等) | GC无法回收的资源需手动关闭 |
IO流资源关闭示例 | FileWriter等对象需在finally中调用close()方法 | 手动关闭资源的必要性 |
5.继承中方法重写抛异常问题
public class Demo10Exception {public static void main(String[] args) {}class A{public void method()/*throws Exception*/{}}class B extends A{@Overridepublic void method()/*throws Exception*/{}}
}
知识点 | 核心内容 | 易混淆点 |
继承体系下的异常抛出规则 | 父类方法抛出异常时,子类重写后可选择抛出或不抛出异常;父类方法未抛出异常时,子类重写后不可抛出异常 | 子类重写方法的异常声明必须兼容父类(子类异常 ≤ 父类异常) |
代码验证方法 | 通过class A(父类)与class B(子类)的继承关系,演示throws Exception在不同场景下的编译结果 | 父类无异常声明时,子类抛出异常会导致编译报错 |
最佳实践建议 | 重写方法时应保持与父类一致的异常声明,避免额外抛出异常 | 子类异常范围扩大(如父类IOException,子类Exception)违反里氏替换原则 |
6.throws和try...catch的使用时机
知识点 | 核心内容 | 重点 |
异常处理方案选择 | try-catch用于处理后需继续执行后续代码的情况,throws用于方法间递进调用关系 | 区分编译期异常(必须处理)和运行期异常(通常不处理) |
三层架构异常处理 | 表现层(Controller)必须用try-catch最终处理,业务层(Service)和持久层(DAO)可先throws | 无脑throws到表现层是严重错误,异常信息不应暴露给用户 |
编译期异常特性 | 必须处理否则编译不通过(如IOException),处理方式:throws或try-catch | 开发工具通常提供快速修复建议(Alt+Enter) |
运行期异常特性 | 通常由代码逻辑错误引起(如NullPointerException),直接修改代码而非捕获 | 与编译期异常的强制处理要求形成对比 |
分层架构调用流程 | 页面→Controller→Service→DAO,异常应沿调用链反向传递 | 需注意方法返回值与异常处理的配合使用 |
7.自定义异常&打印异常信息
public class LoginUserException extends Exception{public LoginUserException() {}public LoginUserException(String message) {super(message);}
}public class Demo11Exception {public static void main(String[] args) throws LoginUserException {//1.定义一个用户名,代表已经注册的用户String username = "root";//2.创建Scanner对象,录入用户名Scanner sc = new Scanner(System.in);System.out.println("请您输入要登录的用户名:");String name = sc.next();//3.判断用户名是否和已经存在的用户名一致if (name.equals(username)){System.out.println("登录成功了");}else{throw new LoginUserException("登录失败了,用户名或者密码有问题");}}
}
Throwable类中的方法:String toString() :输出异常类型和设置的异常信息String getMessage(): 输出设置的异常信息 void printStackTrace():打印异常信息是最全的:包括异常类型,信息,以及出现的行数等
public class Demo11Exception {public static void main(String[] args) {//1.定义一个用户名,代表已经注册的用户String username = "root";//2.创建Scanner对象,录入用户名Scanner sc = new Scanner(System.in);System.out.println("请您输入要登录的用户名:");String name = sc.next();//3.判断用户名是否和已经存在的用户名一致if (name.equals(username)) {System.out.println("登录成功了");} else {try {throw new LoginUserException("登录失败了,用户名或者密码有问题");}catch (Exception e){//System.out.println(e.toString());//System.out.println(e.getMessage());e.printStackTrace();}}}
}
知识点 | 核心内容 | 重点 |
自定义异常 | 继承Exception或RuntimeException创建自定义异常类 | 字符串比较用equals()而非== |
异常处理 | try-catch捕获异常 | 编译时异常必须处理,运行时异常可不处理 |
异常信息打印 | toString() /getMessage() /printStackTrace() 三种方法 | printStackTrace()输出最完整异常信息 |
构造方法 | 通过有参构造设置异常信息 | super(message)调用父类构造传递信息 |
登录功能实现 | 用户名比对实现基础登录验证 | Scanner录入用户输入数据 |
8.object类 toString
所有类的根类(父类),所有的类都会直接或者间接继承Object类
public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}public class Test01 {public static void main(String[] args) {Person p1 = new Person("金莲", 26);System.out.println(p1);//com.atguigu.b_object.Person@4eec7777System.out.println(p1.toString());//com.atguigu.b_object.Person@4eec7777System.out.println("==============");ArrayList<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");System.out.println(list);//[张三, 李四, 王五]System.out.println(list.toString());//[张三, 李四, 王五]}
}
知识点 | 核心内容 | 重点 |
Object类toString方法 | Object类是所有类的超类,其toString方法默认返回对象地址值(格式:包名.类名@16进制哈希值) | 直接输出对象名时: - 未重写:调用Object.toString()返回地址值; - 重写后:调用重写方法返回自定义内容 |
toString方法重写 | 重写后应返回对象内容(如Person类的name和age),可通过IDE快捷键Alt+Insert自动生成 | 集合类(如ArrayList)已重写toString,输出元素内容而非地址值 |
哈希值与16进制转换 | Object.toString() 中 Integer.toHexString() 将哈希码(十进制)转为16进制字符串 | 地址值后半部分的16进制数来源 |
集合类的toString行为 | ArrayList等集合类继承链中重写了toString(如AbstractCollection),输出元素列表而非地址值 | 易混淆点:直接输出集合对象与自定义类对象的差异 |
9.Object.equals()
概述:比较两个对象的地址值是否相等public boolean equals(Object obj) {return (this == obj);}== 针对于基本数据类型来说,比较的是值 == 针对于引用数据类型来说,比较的是地址值== 如果没有重写Object中的equals方法,那么就会调用Object中的equals方法,比较对象的地址值== 如果重写了Object中的equals方法,那么就会调用重写后的equals方法,应该比较对象的内容
知识点 | 核心内容 | 重点 |
Object.equals()方法 | 默认比较对象地址值,可重写为比较内容 | 地址值比较 vs 内容比较 |
String类的equals() | 重写Object.equals(),比较字符串内容而非地址 | new String("ABC").equals(new String("ABC"))返回true |
重写equals()规范 | 需处理:null值、类型检查、自反性、内容比对 | instanceof检查 + 强制类型转换 |
多态与向下转型 | 父类引用调用子类属性需强制转换 | Object obj = new Person(); obj.name编译报错 |
IDE快捷操作 | Alt+Insert生成equals()/hashCode() | 自动包含空检查、类型校验、自反性优化 |
==与equals()区别 | 基本类型比值,引用类型比地址 | String s1==s2与s1.equals(s2)差异 |
10.Object类 clone
public class Person implements Cloneable{private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}public class Test03 {public static void main(String[] args) throws CloneNotSupportedException {Person p2 = new Person("涛哥", 16);Object o = p2.clone();Person p3 = (Person) o;//克隆了一个新对象System.out.println(p2==p3);//比较地址值 falseSystem.out.println(p2.equals(p3));//true}
}
知识点 | 核心内容 | 重点 |
克隆方法 | 复制属性值相同的新对象 | 地址值不同但内容相同 |
Cloneable接口 | 实现该接口才能使用克隆功能 | 必须重写clone()方法 |
克隆实现步骤 | 1. 实现Cloneable接口; 2. 重写clone方法; 3. 调用super.clone() | 返回Object类型需要强制转换 |
克隆验证 | 1. 比较对象地址(==); 2. 比较对象内容(equals) | 地址比较false/内容比较true |
克隆与new对比 | 克隆保留原对象属性值 | 比new创建对象效率更高 |