1.分析异常产生的原因?
1.print() 出现数组下标越界,会向上即调用者抛出异常
2.main() 继续向上抛出异常,抛给JVM
3.JVM 对于异常,直接输出红色错误的堆栈信息,程序执行到此结束
Exception in thread "main主线程" 异常全类名:异常理由
程序员解决异常?
1.快速定位异常出现的位置 - 在自己的代码中,第一行异常信息的位置
at 全类名.方法名(类.java:行号)
2.Debug 解决
2 Throwable
Throwable 基本
1.Error 错误
严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。例如:VirtualMachineError JVM错误
1.1 OutOfMemoryError JVM无法正常分配内存空间
1.2 StackOverflowError 由于递归抬升,导致的堆栈溢出
2.Exception 异常 程序在执行的过程中,可能会出现的不正常的事件流
2.1 编译期异常 除了运行期异常以外的
在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常)
ParseException 时间解析异常
IOException IO异常
SQLException SQL异常
ClassNotFoundException 类找不到异常
FileNotFoundException 文件找不到异常
2.2 运行期异常 RuntimeException及其子类
在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)
ArithmeticException 数学异常
NullPointerException 空指针异常
IndexOutOfBoundsException 下标越界异常
ClassCastException 类型转换异常
NumberFormatException 数字格式化异常
3.处理异常的方式
* 处理异常的方式
* 方式一:throw、throws
* 1.消极的处理方式
* 2.向上抛出,抛给调用者处理
* 3.除了main()以外,都会优先选择抛出方式解决,希望调用者可以预见到此问题
* 4.使用场景:自定义异常
*
* 方式二:try...catch...finally
* 1.积极的处理方式
* 2.就地处理
* 3.在抛无可抛的地方,例如:main()、JFrame窗体等
* 4.使用场景:编译期异常
4 throw和throws区别
throw 关键字
1.在方法内部,抛出异常(以自定义异常为主)
2.throw 异常对象; 等价于 throw new 异常构造方法("异常信息");
3.throw抛出是运行期异常RuntimeException,则不会强制处理;
throw抛出是Exception,则会需要强制处理,要么就地try,要么继续向上抛throws 关键字
1.在方法声明处,抛出异常(以自定义异常、编译期异常为主)
2.方法名() throws 异常类1 , 异常类2{ //方法体 }
3.方法后面可以追加多个异常类,一旦有根异常Exception前面异常类可以省略不写
4.一旦选择向上抛出异常,调用者是可以看见,然后也需要做处理,要么就地try(若是main()),要么继续向上抛
5 try...catch...finally
* 处理异常的方式
* 方式一:throw、throws
* 1.消极的处理方式
* 2.向上抛出,抛给调用者处理
* 3.除了main()以外,都会优先选择抛出方式解决,希望调用者可以预见到此问题
* 4.使用场景:自定义异常
*
* 方式二:try...catch...finally
* 1.积极的处理方式,就地处理
* 2.在抛无可抛的地方,例如:main()、JFrame窗体等
* 3.使用场景:编译期异常
* 4.语法
* try{
* //可能会发生异常的代码,一旦到异常,后续不会再执行
* }catch(异常类1 对象名){
* //处理异常
* }catch(异常类2 对象名){
* //处理异常
* }catch (Exception e){
* e.printStackTrace();
* }finally{
* //一定会执行到,日志处理、关闭操作等
* }
* 注意:catch中的异常类,建议由小到大,最后Exception结尾
*
* JDK1.7 语法
* try{
* //可能会发生异常的代码,一旦到异常,后续不会再执行
* }catch(异常类1 | 异常类2 对象名){
* //处理异常
* }finally{
* //一定会执行到,日志处理、关闭操作等
* }
* 注意:
* 1)、一旦 catch (ArithmeticException | NullPointerException | Exception e)
* Exception最大的,会不让前面出现子类异常信息,强制让你删除 catch (Exception e)
* 2)、精准匹配,往往自定义异常处理方式不一样的
* 3)、比较适用于编译期异常
*
*
* 5.特殊情况
* 1)、允许 try..catch try..finally
* 2)、即使上方出现return,但是finally必执行
5.1 例题
创建一个类ExcetionTest,以及三个int型的属性a,b,c。输入两个数字 进行四则运算。 利用try/catch 捕获 可能会出现的异常,并且输出运算结果
public class ExcetionTest {
int a;
int b;
int c;
public static void main(String[] args) {
ExcetionTest test = new ExcetionTest();
Scanner scanner = new Scanner(System.in);
System.out.print("请输入第一个数字:");
test.a = scanner.nextInt();
System.out.print("请输入第二个数字:");
test.b = scanner.nextInt();
// 加法
try {
test.c = test.a + test.b;
System.out.println("加法结果: " + test.c);
} catch (Exception e) {
System.out.println("加法运算异常: " + e.getMessage());
}
// 减法
try {
test.c = test.a - test.b;
System.out.println("减法结果: " + test.c);
} catch (Exception e) {
System.out.println("减法运算异常: " + e.getMessage());
}
// 乘法
try {
test.c = test.a * test.b;
System.out.println("乘法结果: " + test.c);
} catch (Exception e) {
System.out.println("乘法运算异常: " + e.getMessage());
}
// 除法
try {
test.c = test.a / test.b;
System.out.println("除法结果: " + test.c);
} catch (ArithmeticException e) {
System.out.println("除法运算异常: 除数不能为0!");
} catch (Exception e) {
System.out.println("除法运算异常: " + e.getMessage());
} finally {
System.out.println("除法运算结束");
}
}
}
6 final、finally、finalize区别
* final修饰符、finally捕获异常代码块、finalize()Object类中的方法
* 1.final 修饰类、方法、属性,最终的
* 2.finally 无论是否发生异常,都必执行
* 3.finalize() Object类中的方法,当垃圾收集确定没有对对象的引用时,由对象上的垃圾收集器调用
7.自定义异常
* 自定义异常
* 1.继承Exception类,编译期异常
* 2.继承RuntimeException类,运行期异常
*
* 编译期的自定义异常
* 1.继承extends Exception类
* 2.生成构造方法无参、带String的有参构造方法
* 3.throw new 编译期的自定义异常("异常信息");
* 一旦抛出后,会强制进行处理,要么throws,要么try;一般建议继续向上抛throws
*
* 运行期的自定义异常
* 1.继承 extends RuntimeException类
* 2.生成构造方法无参、带String的有参构造方法
* 3.throw new 运行期的自定义异常("异常信息");
* 一旦抛出后,并不会强制要求处理,直到运行时满足抛出异常的条件后才会由控制台输出异常信息
7.1 例题 - LoginException自定义异常
1.账户或密码不能为空
2.账户与密码不匹配
执行登录业务时,出现以上情况,则抛出自定义异常LoginException
public class LoginException extends Exception{
public LoginException() {
}
public LoginException(String message) {
super(message);
}
}
class UserService {
public static boolean login(Long id,String password) throws LoginException{
if(id==null || password==null || id.equals("null") || password.equals("")){
throw new LoginException("账户或密码不能为空");
}else {
if (id.equals(1L) && password.equals("123")) {
JOptionPane.showMessageDialog(null, "登录成功");
return true;
}
}
throw new LoginException("账户和密码不匹配");
}
public static void main(String[] args) {
try {
UserService.login(3L,"123");
} catch (LoginException e) {
e.printStackTrace();
}
}
}
7.2 例题 - BalanceNotEnoughException自定义异常
一个简易的银行取款操作,定义一个类ExceptionTest,
其中有String id 和double的balance两个属性,以及withdraw()取款方法。
通过withdraw()中的方法判断取出的钱,是否小于等于银行的余额。
通过main方法调用 withdraw()类 ,传入取出的钱,
并且用try-catch捕获异常并且处理,并且在finally块,显示余额。
需要的关键字(try-catch-finally throw throws)
public class BalanceNotEnoughException extends Exception {
public BalanceNotEnoughException() {
}
public BalanceNotEnoughException(String message) {
super(message);
}
}
public class ExceptionTest {
public static void main(String[] args) {
Accoutn accoutn = new Accoutn(1L, "123", 11000);
System.out.println("取款前"+accoutn);
try {
accoutn.withdraw(2000);
} catch (BalanceNotEnoughException e) {
JOptionPane.showMessageDialog(null,e.getMessage());
}
System.out.println("取款后"+accoutn);
}
}
class Accoutn{
private Long id;
private String password;
private double balance;
//取款
public Accoutn withdraw(double money) throws BalanceNotEnoughException{
if(this.balance>=money){
this.balance -= money;
return this;
}
throw new BalanceNotEnoughException("余额不足");
}
public Accoutn() {
}
public Accoutn(Long id, String password, double balance) {
this.id = id;
this.password = password;
this.balance = balance;
}
/**
* 获取
* @return id
*/
public Long getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Long id) {
this.id = id;
}
/**
* 获取
* @return password
*/
public String getPassword() {
return password;
}
/**
* 设置
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取
* @return balance
*/
public double getBalance() {
return balance;
}
/**
* 设置
* @param balance
*/
public void setBalance(double balance) {
this.balance = balance;
}
public String toString() {
return "Accoutn{id = " + id + ", password = " + password + ", balance = " + balance + "}";
}
}