1)运行时异常: 程序运行的时候才出现的异常,什么空指针异常,数组越界,用try catch,主要是在运行的时候需要进行处理,点击运行按钮出现后的异常;
RuntimeException体系包括错误的类型转换,数组越界访问和尝试访问空指针等等,可以被try catch捕获,也可以交给JVM来进行处理(代码中什么也不写,最后程序继续向下执行)
尤其是运行时异常,最后不进行处理,那么最后会交给JVM来进行处理,最后就是程序异常终止
2)非运行时异常:没有运行的时候编译时期程序就会报错,有红线,用try catch捕获或者throws声明,主要是在编译的时候进行处理,没有运行程序的时候出现的异常
非runtimeException一般是外部错误,也就是受查异常,必须被try catch进行捕获cloneNotFoundException,所以说如果出现了受查异常,那么程序必须要进行处理掉这个异常才能够进行运行
一:异常的抛出
1)之前写的异常都是由程序运行或者是编译自动进行抛出的,当然也是可以通过自己写代码手动进行抛出异常
2)进行编写程序的时候,程序发生了错误,用户不想处理这个异常,那么此时就要将错误的信息告诉告诉方法调用者,这就叫做异常的抛出
3)可以通过throw关键字,抛出一个指定的异常对象,将错误信息告诉调用者:
throw new XXXException("异常产生的原因");
1)throw必须写在方法内部
2)抛出的对象必须是Exception或者是Exception的子类对象
3)如果抛出的是RunTimeException或者是RunTimeException的子类,那么可以不用处理,直接交给JVM处理,程序会在这里面直接进行终止
4)抛出的是编译时异常,用户必须进行处理否则无法通过编译
5)异常一旦进行抛出,后面的代码就不会执行6)要是直接throw new Exception();默认是受查异常
二)异常的捕获:
异常的捕获,就是异常的具体处理方式,主要有两种:
异常声明throws以及try catch进行捕获处理
2.1)异常的声明:throws
1)它这种写法是处于方法声明时候在参数列表之后,当方法中出现抛出编译时异常的时候,用户不想要处理这个异常,那么就可以借助throws将异常抛给方法的调用者来进行处理,即使当前方法不处理异常,那么提醒方法的调用者来进行处理异常
2)但是throws并没有处理异常,最后想要进行处理异常还是要通过try catch
注意:
1)throws必须 在方法的参数列表之后
2)声明的异常必须是Exception以及Exception的子类
3)方法内部如果说抛出了多个异常,throws之间必须跟多个异常类型,之间用,进行分隔开,如果说抛出的多个异常类型具有具有父子类关系,那么直接声明父类就可以了
4)当我们进行调用抛出异常的方法的时候,调用者必须对该异常进行处理,或者说使用throws来进行声明,声明到到main方法之后,最后是交给JVM来进行处理的,程序会异常终止
2.2)用try catch来进行捕获异常:一旦出现异常,进入到对应的catch语句块里面,catch语句块后面的代码会立即执行
1)我们的throws其实本质上来说并没有针对异常来进行处理,而是将异常抛出给异常方法的调用者,由调用者来进行处理,如果说真是想要对异常来进行处理,那么就通过try-catch来进行真正的处理
2)try代码块中放的是可能出现异常的代码,catch代码块中存放的是出现异常后的处理行为,finally是用于代码块的善后处理工作,一般是在最后面执行;
3)所以说catch一定要有对应的异常类型
4)在JAVA中,所有抛出异常的类型都是一个类,这些类都是java.lang包底下的类,是不需要我们进行手动导入的,可以认为这是一个异常对象
1,不进行处理异常,就发现程序会终止在出现异常的地方,后面不会再继续执行 因为程序会把异常直接交给JVM来进行处理,这样的处理结果是,程序会抛出异常 并且不会再继续向下执行 int[] arr1={1,2,3}; System.out.println(arr1[0]); System.out.println(arr1[3]); System.out.println("hello"); 2,但是此时当程序进行用try catch来进行包裹异常的时候程序会自己在catch中处理异常 这样处理的结果是程序会自动向下执行 但是一旦try中发现异常的语句,就会立即跳到catch语句里面 try之后代码块的语句不会执行,catch执行完毕之后会继续向下自动执行 程序并不会终止 int[] arr1={1,2,3}; try{ System.out.println(arr1[0]); System.out.println(arr1[4]);//程序执行到这里,立即跳转到catch语句 System.out.println("我爱我的家"); }catch(ArrayIndexOutOfBoundsException e) //这里面的ArrayIndexOutOfBoundsException不可以换成其他的异常 //否则还是会交给JVM进行处理 { } System.out.println("我爱我的祖国"); 最终我们打印的结果是1,我爱我的祖国
try{ System.out.println(10/0); }catch(NullPointerException e){ System.out.println("这里面出现了空指针异常"); } } System.out.println(1); 比如说这种情况,这里面没有捕捉到对应的异常,那么最后这个异常最终就会交给JVM来进行处理 所以这里面的1不会执行
try{ // 将可能出现异常的代码放在这里 }catch(要捕获的异常类型 e){ // 如果try中的代码抛出异常了,此处catch捕获时异常类型与 try中抛出的异常类型一致时,或者是try中抛出异常的基类时就会被捕获到 // 对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码 }[catch(异常类型 e){ // 对异常进行处理 }finally{ // 此处代码一定会被执行到 }] // 后序代码 // 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行 // 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行 注意: 1. []中表示可选项,可以添加,也可以不用添加 2. try中的代码可能会抛出异常,也可能不会
try { int[] array=null; System.out.println("我是中国人"); array[9]=10; }catch(Exception e){ System.out.println("此时发生了异常"); }
此时发生了向上转型,父类引用引用子类对象,由于父类引用了不同的子类对象,调用一个异常打印栈,此时就发生了多态绑定,运用到了多态的思想
1)try语句块里面抛出异常位置之后的代码不会继续执行
2)如果说抛出的异常类型和catch中的异常类型不匹配,那么异常不会被成功捕获,也就不会被处理,那么会继续往外抛异常,直到JVM进行终止程序
3)try语句块中可能会抛出多个不同的异常对象,况且必须用多个catch来进行捕获,即多个异常,多次捕获
4)我们在进行捕获异常的时候,如果说你捕获的不是你抛出的,那么最后就会直接交给JVM来进行处理,只要最后交给JVM来进行处理,那么最后就会立即终止程序
5)catch也可以有多个,finally常常用于最后的善后工作,例如释放资源,无论是否发生异常,finally的代码块最终一定会被调用到,一旦异常类型不匹配,catch是不可以进行捕获的
int[] arr1={1,2,3,4,5,6,7}; try{ arr1=null; System.out.println("hehe"); System.out.println(arr1[5]); System.out.println("heihei"); }catch(ArrayIndexOutOfBoundsException e) { e.printStackTrace(); System.out.println("此时发生了数组越界异常·"); }catch (NullPointerException e) { e.printStackTrace(); System.out.println("此时发生了空指针异常"); } 最终打印结果的值是hehe 此时发生了空指针异常
1)多个异常还可以同时进行捕获,但是这种写法不推荐,因为会影响代码的可读性
String str1="hello world"; try{ File file=new File("D:/text.html"); }catch(NullPointerException|ArrayIndexOutOfBoundsException e){ System.out.println("此时程序中出现了异常"); }finally { System.out.println("我是finally中的语句"); } } try{语句块}catch(异常1|异常2 e){ }
2)在进行捕获异常的时候,如果说出现了父子类关系,在catch语句块出现异常的顺序就是子类异常在前面,父类异常在后面,否则就会导致父类异常可以进行捕获所有子类异常,子类异常后面永远也不会执行
1)因为此时的Exception是所有异常类的父类,那么如果说你此时都交给他了,那么后面的这些子类都没有存在意义了
2)但是如果说把Exception放到最后面写,意思就是都解决不了再让我解决
Scanner scanner=new Scanner(System.in); try{ int num= scanner.nextInt(); System.out.println(10/num); }catch(InputMismatchException e) { e.printStackTrace(); System.out.println("输入错误"); }catch (ArithmeticException e) { e.printStackTrace(); System.out.println("算数异常,可能0作为了除数"); }finally{ scanner.close(); System.out.println("finally代码块最终执行了"); } 0 算数异常,可能0作为了除数 finally代码块最终执行了
示例代码:用try回收资源
try(Scanner scanner=new Scanner(System.in)){ int num= scanner.nextInt(); System.out.println(10/num); }catch(InputMismatchException e) { System.out.println("此时发生了输入错误"); }catch(ArithmeticException e) { System.out.println("此事发生了算数异常,可能0作为了分母"); } }
如果此方法中没有合适的处理异常的方式,异常就会沿着调用栈向上进行传递
public static void func(int n) { System.out.println(10/n); } public static void main(String[] args) { try{ func(0); }catch(ArithmeticException e) { System.out.println("此时发生了算数异常"); } } 最终交给了main函数来进行处理
但是如果说一直向上传递都没有合适的方法去处理异常(main函数里面都没有try Catch)那么最终就会交给JVM来进行处理(和我们最开始没有使用try catch是一样的)
public static void func(int n) { System.out.println(10/n); } public static void main(String[] args) { func(0); System.out.println(123); } 这个程序最终什么结果都不会进行打印,咱们的func处理不了这个异常,J就会向上传递,让main方法来进行处理,此时main方法也没有办法处理这个异常,那么直接交给JVM来进行处理,程序会终止 public static int func() { int a=10; try{ return a; }catch(ArithmeticException e) { e.printStackTrace(); }finally{ System.out.println("1"); return 20; } } public static void main(String[] args) { int num=func(); System.out.println(num); } 最终打印结果是1 20,此时异常有func方法交给了main方法,main方法捕获了这个异常并进行了处理
public static int func(int x) { if(x==0) { throw new ArithmeticException("hh"); } return 1; //return x/10; } public static void main(String[] args) { int x=func(0); System.out.println(x); } 无论返回多少,程序啥都不会进行打印
当一个代码中出现了受查异常,必须显式进行处理,如果一段代码可能会出现受查异常,那么也需要进行处理;
public static void main(String[] args) throws FileNotFoundException { File file=new File("d:/22"); Scanner scanner=new Scanner(file); System.out.println(scanner.nextLine()); }
1)使用try catch进行包裹
public static String readFile() { Scanner scan=null; try{ File file=new File("d:/22"); scan=new Scanner(file); }catch(FileNotFoundException e) { e.printStackTrace(); } return scan.nextLine(); } public static void main(String[] args) { String str=readFile(); System.out.println(str); }
2)在方法名后面加上异常说明,相当于将处理动作交给上级调用者
public static String readFile() throws FileNotFoundException { File file=new File("d:/22"); Scanner scanner=new Scanner(file); return scanner.nextLine(); } public static void main(String[] args) throws FileNotFoundException { String str=readFile(); }
三)异常总结:
四)自定义异常:
1)针对于自定义异常来说,可以快速定位到程序所出现的错误
2)一个自定义异常继承了Exception就被称为受查异常,继承于RuntimeException就被称为非受查异常
static class MyException extends Exception{ public MyException(String message) { super(message); //不提供构造方法默认就是用不带有参数的 } } static class MyException1 extends RuntimeException public MyException1(String message) { super(message); } } public static void func1(int x){ if(x==0) { try { throw new MyException("这是我自己抛出的异常"); //也可以在方法后面加上MyException验证异常调用栈交给向上处理 } catch (MyException e) { e.printStackTrace(); } } } public static void func2(int x) { if(x==0){ throw new MyException1("x==0");//不需要进行try catch进行包裹 } }
实例1:实现一个简单的用户登录功能
static class NameException extends RuntimeException{
public NameException(){
}
public NameException(String message)
{
super(message);
}
}
static class PasswordException extends RuntimeException
{
public PasswordException(){
}
public PasswordException(String message)
{
super(message);
}
}
private static final String name="李佳伟";
private static final String password="12503487";
public static void login(String name, String password) throws NameException, PasswordException {
if(!test.name.equals(name))
{
throw new NameException("您输入的用户名错误");
}
if(!test.password.equals(password))
{
throw new PasswordException("您输入的密码是错误的");
}
System.out.println("登陆成功");
}
public static void main(String[] args) {
try {
login("李佳伟","12503487");
} catch (NameException e) {
e.printStackTrace();
} catch (PasswordException e) {
e.printStackTrace();
}
}
示例2:使用while循环来进行类似于恢复异常的处理行为,它将不断重复,直到程序不在抛出异常
public static void main(String[] args) {
int i = 0;
while (i < 15) {
try {
if (i < 10) {
throw new UnsupportedOperationException("i现在还小于10");
}
} catch (UnsupportedOperationException e) {
e.printStackTrace();
System.out.println("第" + i + "次");
i++;
}
}
}
import java.io.FileNotFoundException;
import java.io.IOException;
public class HelloWorld {
public static void TestDemo()
{
System.out.println("执行这个方法");
}
public static void main(String[] args) {
((HelloWorld)null).TestDemo();
}
public static void run()
{
try{
//这里面做了一些事情
} catch(FileNotFoundException e)
{
System.out.println("发生文件找不到异常");
}
catch (IOException ex)
{
System.out.println("发生了IOException");
}catch (java.lang.Exception e)
{
System.out.println("发生了异常");
}
}
//这里面无论语句发生了什么异常,最终只能有一个catch语句快执行,他们是构成父子类关系的,只能抛出一个异常,只能捕获一个异常
}