今天学习的异常与异常处理,异常处理大致分为两种,那么先来看一看异常分为几类;异常分为:Error和Exception两种,其父类都是Throwable,然后继承父类的error错误是比较严重的错误,而Exception是通过bubu或异常,让程序可以进行恢复正常运行的。
典型的error:
1.方法递归调用时,会发生栈内存溢出的错误,即StackOverFlowError。
举例看一下:
public class ErrerDemo {
public static void main(String[] args) {
test(); //Exception in thread "main" java.lang.StackOverflowError
}
public static void test() {
test();
}
}
当调用这个test方法的时候就会出现StackOverFlowError异常。这种异常几乎无法改变,因为他会耗尽你内存,最终而结束
2.不断的new对象,会出现堆内存溢出问题,即OutOfMemoryError。
代码举例:
public class ErrorDemo2 {
private static List<String[]> list=new ArrayList<String[]>();
public static void main(String[] args) {
for(int x=0;x<100000;x++) {
list.add(new String[10000]);
//Exception in thread "main" java.lang.OutOfMemoryError
}
}
}
当给list集合不断new新对象的时候,就会出现堆内存溢出问题,就是上边的Exception in thread “main” Java.lang.OutOfMemeryError错误。
现在来看下异常Exception:
Exception 异常的的父类是Throwable,在程序出现异常的时候,我们可以捕捉到异常,可以使程序恢复运行。异常可以分成两类:
1.是检查异常(check),
Throwable Exception以及他的子类,检查异常需要强制使用try catch或者throws一起使用。
2.为检查异常(uncheck),
RuntimeException,或者他的子类
异常的处理:
1.消极处理:这种异常必须手动在方法声明上加上【throws Exception】,但是这种情况弊端比较大,就是如果一个方法在最底层的话,每一次调用的方法都必须在方法声明上加上【throws Exception】,过程比较繁琐,所以大多数不太使用
public class ExceptionDemo {
public static void mian(String[] args) throws Exception{
m1();
}
public static void m1()throws Exception {
m2();
}
public static void m2() throws Exception{
m3();
}
public static void m3() throws Exception {
throw new Exception("捕获异常,,,,,,");
}
}
这个就是说底层的m3方法出现了异常,如果是在方法声明上加【throws Exception】,那么就会出现上述情况,每一个调用的方法都要写【throws Exception】,所以很麻烦。
2.积极处理:这种异常是在可能出现异常的地方加上try...catch代码块。(常常是运行时期异常RuntimeException,必须是RuntimeException或者是他的自类)
语法:
try{
//可能出现异常的代码
} catch(Exception e){
//捕获异常的代码
}
意思就是当可能出现问题的代码块没有出现问题的时候,就会跳过catch语句,如果真的有错误,就会进入catch进行捕捉异常。
代码举例看一下:
public class ExceptionDemo2 {
public static void m1() {
m2();
}
public static void m2() {
m3();
}
public static void m3() {
try {
throw new Exception("捕获异常,,,,,,");
} catch (Exception e) {
System.out.println("出现异常了......");
System.out.println(e.getMessage());
e.printStackTrace();
}
}
public static void main (String[] args) {
m1();
}
}
此处的e.getMessage():捕获异常信息
e.printStackTrace():打印出现异常的地方
主动抛出异常:
throws new 异常 //此处的异常必须是Exception或者他的子类
public class ExceptionDemo3 {
public static void m1(int a) {
if(a<=0) {
throw new RuntimeException("这个a它必须要大于0 !");
}
System.out.println("陈小帅"); //语句1
}
public static void main(String[] args){
try{
m1(0);
}catch(Exception e) { //语句3
System.out.println(e.getMessage()); //语句2
e.printStackTrace();
}
}
}
在这里主动抛出的是RuntimeException异常,就是当m1()的参数大于0的时候,在运行时就不会出现错误,
那么他就会在执行语句1,就会输出【陈小帅】,如果给m1的参数是0或者负数,程序就会跳过语句1,到达语句3,执行catch语句,从而打印语句2.
异常对象的常见方法:
e.getMessage();获取异常信息
e.printStactTrace():打印异常的跟踪信息
异常的传播:
【异常的传播是方法调用的反方向进行的】
好,具体代码展示一下
public class ExceptionDemo4 {
public static void main(String[] args) {
System.out.println(1);
m3();
System.out.println(2); // 1 6 4 3
}
public static void m1() {
System.out.println(3);
throw new RuntimeException("异常的开始....");
}
public static void m2() {
System.out.println(4);
m1();
System.out.println(5);
}
public static void m3() {
System.out.println(6);
m2();
System.out.println(7);
}
}
自定义异常:
class MyException extends Exception{ } 这个是检查异常
class MyException extends RuntimeException{ } 这个是未检查异常
【注意】:
1.与有返回值的方法连用时要注意,
// 有返回值的方法 与 try-catch连用出现的问题
public class Exception5 {
public static int test(){
try {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int r = 1/n;
return r;
} catch (Exception e ) {
System.out.println(e.getMessage());
return -1; // 解决方法1: 在catch也写一个return返回结果
// throw e; // 解决方法2: 把异常重新抛出
}
}
public static void main(String[] args) {
int r = test();
System.out.println(r);
}
}
重写方法与异常声明:
重写方法的时候,子类不能抛出比父类更多类型的异常,比如父类抛出的是RuntimeException异常,子类就不能抛出Exception异常(检查异常),但是可以不抛出异常(默认抛出的数量必父类的少)
以上声明只针对检查异常,如果子类和父类重写throws,不遵守以上声明(一般开发过程中,用为检查异常比较多,所以尽量将检查异常转换成未检查异常。)
【finally关键字】
语法:
```java
try {
...
} catch(Exception e) {
} finally {
// 无论出现异常与否,总会被执行的代码
}
```
如果说try catch中和finally都有return返回值,结果一finally为准
【注意】:如果try中有return,而finally中对try中的return值进行修改的话,结果并不影响try中的return值,所以最终的输出结果是try中的return值。