JAVA--异常
java具有健壮性。
1. GC 垃圾回收 无用对象(堆内存/元空间)
2. 异常处理机制---> 一段流程出现异常 不影响其它程序的正常执行
不正常的现象
1. 错误 Error
public static void main(String[] args) {
int[] array = new int[1024 * 1000 * 1000];
System.out.println(array);
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.javasm.exception.Demo.main(Demo.java:15)
public class Error extends Throwable
错误无法处理的。程序只能终止。都是与虚拟机内存/内核有关系的,
==2. 异常 Exception==
System.out.println(1/0);
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.javasm.exception.Demo.main(Demo.java:19)
总结:
相同点: 程序里面的不正常的现象 都继承了Throwable。
不同点:
Error: 所有的错误父类。无法处理 程序只能终止。
Exception: 所有异常的父类 利用异常处理机制 可以处理 所有的异常。
1. 常见异常
//数据(用户传来的数据是合法的)
//都是程序写代码不够严谨导致
//ArithmeticException 除数为0
//NullPointerException 变量值为null
//ArrayIndexOutOfBoundsException 数组索引越界
//ClassCastException 类型转换异常
//ParseException 解析异常 求租金
处理方式: 2种
1. 捕获 try...catch...finally 真正处理异常的方式
try{
//有可能出现异常的代码块
}catch(异常类型 对象名称){//捕获一个具体的异常对象
//处理异常对象功能
}
//多个catch块
[finally{
//不管程序里面是否出现异常 finally代码块功能 肯定会被执行的
//物理资源的释放 close
}]
//锁释放
try{
//上锁
}finally{
//释放锁
}
2. 抛出 throws 把异常抛出给调用者(上级)---->表示没有能力处理 (消极处理)
在方法的签名后面 使用throws抛出具体的异常类。
2. 运行时异常
RuntimeException ==不允许在代码里面 对任意的一个运行时异常执行处理 提前预判==
public static void main(String[] args) {
demo1();
//简单字符串的比较
String str = "abc";
System.out.println("abc".equals(str));
}
private static void demo1() {
int[] array = {1, 2, 3};
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
System.out.println(array[3]);
//代码里面出现异常 如果不处理 当前(main程序)线程终止
}
常用的方法:
Throwable(String message)
Throwable(String message, Throwable cause) ---> 异常信息的传递
1. void printStackTrace() 将异常信息输出到控制台
2. String getMessage() 获得具体的异常信息字符串
try{
//有可能出现异常的代码
}catch(异常类 异常对象){
//1. System.out.print()
//2. 异常对象.printStackTrace();
//3. System.out.print(异常对象.getMessage())
//4. return 数据;
//5. 异常+日志: 将异常信息存储到(不同级别)日志文件中 info warn error debug
//log4j/log4j2 self4j logback...
//6.异常信息的传递 throw --->将低级别异常对象传递到高级别的异常对象中 Casued by:
}finally{
}
//代码里面出现异常 如果不处理 当前(main程序)线程终止
private static int demo1() {
int[] array = {1, 2, 3};
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
//try...catch...finally
try {
System.out.println(array[3]);
} catch (ArrayIndexOutOfBoundsException a) {
// System.out.println("数组 索引越界,索引的范围: 0-" + (array.length - 1));
//在catch 一定要写代码 不能捕获异常 什么也不做
// a.printStackTrace();
//System.err.println(a.getMessage());
//return -1;
} finally {
System.out.println("肯定会执行的代码。。。。");
}
return 1;
}
多个catch块
public static void main(String[] args) {
//用户录入一些数据
Scanner input = new Scanner(System.in);
System.out.println("录入一个字符串:");
String s = input.nextLine();
try {
if (str.equals(s)) {
System.out.println("true");
} else {
System.out.println("false");
}
System.out.println(3 / 1);
//在try 虽然有多个catch块 但是 有且只执行一个catch
//在try里面 异常之后的代码不会被执行的
//一定要区分哪些代码是稳定代码 哪些非稳定代码
} catch (NullPointerException e) {
e.printStackTrace();
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
input.close();
}
System.out.println("其他代码。。。。");
}
try {
if (str.equals(s)) {
System.out.println("true");
} else {
System.out.println("false");
}
System.out.println(3 / 1);
//在try 虽然有多个catch块 但是 有且只执行一个catch
//在try里面 异常之后的代码不会被执行的
//一定要区分哪些代码是稳定代码 哪些非稳定代码
} catch (NullPointerException | ArithmeticException | ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
// } catch (Exception e) {
// e.printStackTrace();
} finally {
input.close();
}
3. 编译时异常
检测到异常。 checked Exception 必须要处理
private static long getMoney(String borrowTime, String backTime) {
if (borrowTime == null || backTime == null) {
//应该结束
System.out.println("参数不能为null");
System.exit(-1);
}
//字符串的数据不能直接进行算术运算 (数值型)
//将字符串时间转换成数值类型的数据----> 时间间隔
//1. 将string转java.util.Date ---> 格式化字符串时间 java.text.SimpleDateFormat
SimpleDateFormat dateFormat = new SimpleDateFormat(PATTEN);
//编译时异常(检测到异常)---> 必须要处理
Date borrowDate = null;
Date backDate = null;
try {
borrowDate = dateFormat.parse(borrowTime);
backDate = dateFormat.parse(backTime);
} catch (ParseException e) {
//System.out.println("字符串时间数据肯定是少于pattern格式规定的内容");
e.printStackTrace();
// try {
// throw new Exception("字符串时间数据肯定是少于pattern格式规定的内容", e);
// } catch (Exception e1) {
// e1.printStackTrace();
// }
}
//2. 将Date对象转换成数值类型的数据
long borrowDateTime = borrowDate.getTime();//获得当前日期毫秒数
long backDateTime = backDate.getTime();
//将2个时间的间隔 转换成小时
return Math.abs((borrowDateTime - backDateTime) / 1000 / 3600);
}
4. throw
在方法体里面: throw new 异常类();
1. 控制流程 遇见throw 程序结束 return;
public static void main(String[] args) {
//求任意2个整数 相除结果
int num1 = 10;
int num2 = 1;
System.out.println(divide(num1, num2));
userLogin(null, null);
}
private static boolean userLogin(String name, String pass) {
// if (name == null || pass == null) {
// return false;
// }
// if (name == null || pass == null) {
// throw new NullPointerException("用户名或者密码不能为null");
// }
Objects.requireNonNull(name, "用户名不能为null");
Objects.requireNonNull(pass, "密码不能为null");
return true;
}
//除数不能为0
private static double divide(int num1, int num2) {
//提前预判数据
if (num2 == 0) {
//System.out.println("除数不能为0");
//System.exit(-1); //java项目中有意义
throw new ArithmeticException("除数不能为0");
}
return num1 / num2;
}
异常信息的传递: try/==catch==
try {
borrowDate = dateFormat.parse(borrowTime);
backDate = dateFormat.parse(backTime);
} catch (ParseException e) {
//实现异常信息的传递: throw
//Exception: 也是一个编译时异常
try {
throw new Exception("字符串时间数据肯定是少于pattern格式规定的内容", e);
} catch (Exception e1) {
e1.printStackTrace();
}
}
java.lang.Exception: 字符串时间数据肯定是少于pattern格式规定的内容
at com.javasm.exception.ExceptionDemo3.getMoney(ExceptionDemo3.java:49)
at com.javasm.exception.ExceptionDemo3.main(ExceptionDemo3.java:25)
Caused by: java.text.ParseException: Unparseable date: "2021-05-17 12:00"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.javasm.exception.ExceptionDemo3.getMoney(ExceptionDemo3.java:43)
... 1 more
Exception in thread "main" java.lang.NullPointerException
at com.javasm.exception.ExceptionDemo3.getMoney(ExceptionDemo3.java:56)
at com.javasm.exception.ExceptionDemo3.main(ExceptionDemo3.java:25)
throw vs throws
throws: 处理异常的一种方式
在方法的签名后面 throws 抛出多个异常类。自己可能没有能力处理 抛出给上级(调用者)
5. 自定义异常类
一般都是与throw结合使用。
模拟用户支付:
public class UserPayDemo {
//用户余额
private static double balance = 1000;
public static void main(String[] args) {
double totalMoney = 2000;
System.out.println("需要支付:" + totalMoney);
try {
pay(totalMoney);
} catch (BalanceException e) {
e.printStackTrace();
}
System.out.println("账户余额:" + balance);
}
private static void pay(double totalMoney) throws BalanceException {
// if (totalMoney > balance) {
// System.out.println("账户余额不足的");
// return;
// }
if (totalMoney > balance) {
throw new BalanceException("账户余额不足,无法扣除");
}
balance -= totalMoney;
}
}