异常指的就是程序在运行时出现错误时通知调用者的一种机制.我们在编写代码的过程中,遇到过许多的异常,比如
1.
System.out.println(10 / 0);
// 执行结果: //0异常
Exception in thread "main" java.lang.ArithmeticException: / by zero
2.
int[] arr = {1, 2, 3};
System.out.println(arr[100]);
// 执行结果 //数组越界异常
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
3.
int[] arr=null;
System.out.println(arr[0]);
//执行结果 //空指针异常
Exception in thread "main" java.lang.NullPointerException
异常分为受查异常和非受查异常,受查异常就是我们说的编译异常,非受查异常就是运行异常.
运行时异常:都是RuntimeException及其子类异常,比如NullPointerException,IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常(编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException,SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
在Java里面,我们借助关键字throw,抛出一个指定的异常对象,将错误信息反馈给调用者。如果出现异常但是我们没有手动抛出的时候,其实是JVM检测到后帮我们抛出的。
public class exception {
public static void test(int a){
if(a==1){
throw new NullPointerException();
}
}
public static void main(String[] args) {
test(1);
}
}

| 注意事项: 1.throw必须写在方法体的内部 2.抛出的必须是Expection或者Expection的子类对象。 3.如果抛出的是运行时异常或者是其子类,那么就可以不用管,交给JVM处理就好 4.如果你抛出的是一个受查异常,也就是编译时异常,那你就必须要手动的进行异常的声明,不然程序连编译都过不去 5.异常一旦抛出,其后面的代码就不会执行了 6.当我们没有解决这个异常的时候,我们就会把这个异常交给JVM处理,一旦交给JVM程序就奔溃了 |



异常的捕获主要有两种:异常的声明throws,以及try - catch捕获处理
throws处在方法声明的参数列表之后,当方法中抛出编译时异常,此时用户不想处理该异常,就可以借助throws声明一下这个异常,然后让方法的调用者去处理。即当前方法不处理异常,提醒方法的调用者处理.


| 1.声明的异常必须是Expection或者Expection的子类. 2.方法内部如果抛出了多个编译时异常,那么参数列表后面throws需要声明多个异常,之间用逗号隔开. 3.方法将编译时异常用throws进行声明之后,那么就需要我们的调用者去进行处理了。如果调用者也不想处理,那就继续用throws进行声明。都没有人处理,最后交给JVM处理. |
对于throws而言,它其实对异常没有进行真正的处理,而是将其甩给了调用者,然后如果就这样一层层的甩出去的话,最终还是会交给到JVM的手上进行处理。如果想处理异常,就需要使用try - catch.
public class exception {
public static void test(int a) throws CloneNotSupportedException {
if(a==1){
throw new CloneNotSupportedException();
}
if(a==2){
throw new NullPointerException();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
try{
test(2); //try当中放入可能会有异常的代码,比如这里的test()
}catch (NullPointerException e){
System.out.println("捕获到了NullPointerException"); //catch对异常进行捕获并处理
}
System.out.println("捕获异常之后执行的代码");
}
}
如果你try-catch捕获到的异常与你catch中定义的不是同一个类型,那照样还是处理不了,会交给JVM
public class exception {
public static void test(int a) throws CloneNotSupportedException {
if(a==1){
throw new CloneNotSupportedException();
}
if(a==2){
throw new NullPointerException();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
try{
test(2);
}catch (CloneNotSupportedException e){
System.out.println("捕获到了NullPointerException");
}
System.out.println("捕获异常之后执行的代码");
}
}



如果我们要捕获的多个异常之间存在父子类关系,那一定是子类在前,父类在后。因为父类异常类包含所有的子类异常类,所以你把父类写在前面,会把所有有关的异常都会进行捕获,那么后面写的子类的捕获也就没有任何的意义了。

当try当中存在多个异常的时候,从上往下执行谁先抛出异常就捕获哪个异常,一次只能捕捉到一个异常


对于受查异常来说,当try当中没有抛出catch这个受查异常的时候,这里检测不到就会报错
public static void main(String[] args) throws CloneNotSupportedException {
int[] arr=null;
try{
System.out.println(10/0);
System.out.println(arr.length); // try当中没有CloneNotSupportedException
}catch (NullPointerException e){
e.printStackTrace();
System.out.println("捕获到了NullPointerException");
}catch(CloneNotSupportedException e){
e.printStackTrace();
System.out.println("捕获到了CloneNotSupportedException");
}
System.out.println("捕获异常之后执行的代码");
}
}

try块和之前的throw手动抛异常一样,try块中抛出异常的位置之后的代码是不会执行的


finally 表示最后的善后工作, 例如释放资源,无论是否存在异常, finally 中的代码一定都会执行到.
public static void main(String[] args) throws CloneNotSupportedException {
Scanner sc=new Scanner(System.in);
try{
System.out.println(10/0);
}catch (ArithmeticException e){
System.out.println("捕获到了ArithmeticException");
} catch (NullPointerException e){
e.printStackTrace();
System.out.println("捕获到了NullPointerException");
}finally {
sc.close();
System.out.println("执行finally代码部分");
}
System.out.println("捕获异常之后执行的代码");
}
}

| throw 与 throws 的区别? throw是直接抛出一个异常,多用于抛出自定义类型的异常,抛出的异常会直接被JVM处理,此时程序也会结束执行。throws是声明一个异常,此时只是让方法本身不用去处理这个异常,而让调用者去处理,如果调用者也不处理继续使用throws最终会被JVM处理,throws可以让程序暂时编译层面上不会报错。 |
| 1.程序先执行 try 中的代码 2.如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配 3.如果找到匹配的异常类型, 就会执行 catch 中的代码 4.如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者 5.无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行) 6.如果上层调用者也没有处理的了异常, 就继续向上传递 7.一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止. |
public class exception {
public static void fun() throws CloneNotSupportedException {
String s1 = null;
s1.length();
}
public static void main(String[] args) throws CloneNotSupportedException {
try{
fun();
}catch (NullPointerException e) {
e.printStackTrace();
}
}
}


| 1.顶层类 Throwable 派生出两个重要的子类, Error 和 Exception 2.其中 Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现,除了告知用户并使程序终止之外, 再无能无力. 这种情况很少出现,异常是产生后程序员可以通过代码进行处理,使程序继续执行. 3.异常就是一个类,分为编译时异常和运行时异常,编译时异常也叫作受查异常,运行时异常叫做非受查异常 |
Java中虽然已经给我们提供了很多的异常类,但是考虑到开发过程中的遇到的一些特殊的异常情况,此时需要我们自己去定义这么一个异常类。
public class UserNameException extends Exception{
public UserNameException(String message){
super(message);
}
}
public class PasswordException extends Exception{
public PasswordException(String message){
super(message);
}
}
public class Login {
public static String uname = "zs";
public static String upassword = "123";
public static void logininfo(String name, String password) throws UserNameException, PasswordException {
if (!uname.equals(name)) {
throw new UserNameException("用户名出错了");
}
if (!upassword.equals(password)) {
throw new PasswordException("密码出错了");
}
System.out.println("登录成功");
}
public static void main(String[] args) {
try {
logininfo("z", "123");
} catch (UserNameException e) {
e.printStackTrace();
} catch (PasswordException e) {
e.printStackTrace();
}
}
}
