1.异常的概念和分类
异常指程序运行过程中出现的非正常现象,例如用户输入错误、除数为零、需要处理的文件不存在、数组下标越界等。
在Java的异常处理机制中,引进了很多用来描述和处理异常的类,称为异常类。异常类定义中包含了该类异常的信息和对异常进行处理的方法。
异常的分析
public class Test{public static void main(String[] args) {int i=1/0; //除数为0System.out.println(i);}
}

Java是采用面向对象的方式来处理异常的。处理过程:
1. 抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给JRE。
2. 捕获异常:JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。
/*** 异常:程序在执行的过程出现的非正常情况,异常一旦发生必须进行处理,否则将导致程序中断执行。* Java中的异常分类:* java.lang.Throwable* --java.lang.Error:严重错误* --java.lang.Exception:异常(例外)* ---java.lang.RuntimeException:运行时异常(不需要显示捕获处理)* ----java.lang.ArithmeticException:算术异常(除零出现异常)* -----java.uitl.InputMismatchException:输入不 匹配异常* ----checked Exception:检查异常(必须显示捕获处理,否则无法通过编译)* java处理异常的机制:* 1.try...catch..finally* try{* //可能出现异常的代码;* }catch(异常的类型 e){* //异常处理* }...* }finally{* //一定会被执行的代码* }*2.throws...throw*/
import java.util.InputMismatchException;
import java.util.Scanner;public class Test1 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);try {System.out.println("请输入第一个数:");int num1 = scanner.nextInt();//java.uitl.InputMismatchException:输入不 匹配异常System.out.println("请输入第二个数:");int num2 = scanner.nextInt();//java.uitl.InputMismatchException:输入不 匹配异常int result = num1/num2;//java.lang.ArithmeticException:算术异常System.out.println("result="+result);}catch(ArithmeticException e) {System.out.println("除数不能为零!");e.printStackTrace();//打印堆栈跟踪信息}catch(InputMismatchException e) {System.out.println("输入不匹配,请输入数字!");e.printStackTrace();}System.out.println("程序正常结束!");}
}

异常分类
Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception。
Exception又分为RuntimeException:运行时异常、CheckedException:已检查异常
Error:是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。
Exception:Exception是程序本身能够处理的异常,如:空指针异常(NullPointerException)、数组下标越界异常(ArrayIndexOutOfBoundsException)、类型转换异常(ClassCastException)、算术异常(ArithmeticException)等。
Java异常类的层次结构图

2.常见简单异常的解决方法
RuntimeException运行时异常
常见的运行时异常:RuntimeException
1.java.lang.ArithmeticException:算术异常
2.java.uitl.InputMismatchException:输入不 匹配异常
3.java.lang.NullPointerException:空指针异常
4.java.lang.ArrayIndexOutOfBoundsException:数组下标越界
5.java.lang.StringIndexOutOfBoundsException: 字符串下标越界
6.java.lang.ClassCastException:类型转换异常
7.java.lang.NumberFormatException:数字转换异常
Checked Exception检查时异常
1. IOException
2. FileNotFoundException
3. ClassNotFoundException
4. PassException
5. NullPointException
/*** 常见的运行时异常:RuntimeException* 1.java.lang.ArithmeticException:算术异常* 2.java.uitl.InputMismatchException:输入不 匹配异常* 3.java.lang.NullPointerException:空指针异常 **** 4.java.lang.ArrayIndexOutOfBoundsException:数组下标越界**** 5.java.lang.StringIndexOutOfBoundsException: 字符串下标越界 **** 6.java.lang.ClassCastException:类型转换异常 **** 7.java.lang.NumberFormatException:数字转换异常 ***** 日期:2019年7月*/
public class TestRuntimeException {public static void main(String[] args) {
// //空指针异常
// String str = null;
// str.length();
// //数组下标越界
// int[] nums = new int[5];
// System.out.println(nums[5]);
// //字符串下标越界
// String str2 = "hello";
// System.out.println(str2.charAt(8));//类型转换异常
// Animal animal = new Dog();
// Cat cat =(Cat)animal;String str3 = "abc";int i =Integer.parseInt(str3);//Integer.parseInt(String str):将字符串转换为整数System.out.println(i);}
}
class Animal{
}
class Dog extends Animal{
}
class Cat extends Animal{
}

/*** 常见的运行时异常:RuntimeException* 1.java.lang.ArithmeticException:算术异常* 2.java.uitl.InputMismatchException:输入不 匹配异常* 3.java.lang.NullPointerException:空指针异常 **** 4.java.lang.ArrayIndexOutOfBoundsException:数组下标越界**** 5.java.lang.StringIndexOutOfBoundsException: 字符串下标越界 **** 6.java.lang.ClassCastException:类型转换异常 **** 7.java.lang.NumberFormatException:数字转换异常 **** ...* 如何避免异常:通过严谨的判断防止潜在的运行时异常发生。*/
public class TestRuntimeException2 {public static void main(String[] args) {//空指针异常String str = null;if(str!=null) {str.length();//空指针异常,试图访问空对象的属性或方法}//数组下标越界int[] nums = new int[5];int index = 5;if(index<nums.length) {System.out.println(nums[index]);}}
}
异常的处理方式有两种:使用“try/catch”捕获异常、使用“throws”声明异常。
3.异常处理方式之一__捕获异常
捕获异常是通过3个关键词来实现的:try-catch-finally。用try来执行一段程序,如果出现异常,系统抛出一个异常,可以通过它的类型来捕捉(catch)并处理它,最后一步是通过finally语句为异常处理提供一个统一的出口,finally所指定的代码都要被执行(catch语句可有多条;finally语句最多只能有一条,根据自己的需要可有可无)。

捕获异常关键字(try catch finally)
try-catch 组合
用try来执行,如果出现异常,系统抛出异常,可以通过catch来捕捉并处理它
一个try语句必须带有至少一个catch语句块或一个finally语句块
注意事项
当异常处理的代码执行结束以后,不会回到try语句去执行尚未执行的代码。
import java.util.Scanner;public class TestTryCatch {public static void main(String[] args) {Scanner input =new Scanner(System.in);try {System.out.println("请输入被除数:");int numA=input.nextInt();System.out.println("请输入除数:");int numB=input.nextInt();int result=numA/numB;System.out.println(numA+"/"+numB+"="+result);}catch(ArithmeticException e) {//ArithmeticException e = new InputMismatchException 不成功//catch(Exception e) {//相当于Exception e=new ArithmeticException()多态的表示形式,父类引用指向了子类 //ArithmeticException算术异常e.printStackTrace();}System.out.println("程序结束,谢谢您的使用");}
}

try-finally 组合
finally 是无论是否产生异常,都执行的代码,但是有一种情况 finally 不执行,即退出 Java 虚拟机。
import java.util.Scanner;public class TestTryFinally {public static void main(String[] args) {Scanner input =new Scanner(System.in);try {System.out.println("请输入被除数:");int numA=input.nextInt();System.out.println("请输入除数:");int numB=input.nextInt();int result=numA/numB;System.out.println(numA+"/"+numB+"="+result);//退出java虚拟机System.exit(0);}finally {System.out.println("finally中的代码");}}
}

try-catch-finally 组合
程序首先执行可能发生异常的try语句块。如果try语句没有出现异常则执行完后跳至finally语句块执行;如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。catch语句块可以有多个,分别捕获不同类型的异常。catch语句块执行完后程序会继续执行finally语句块。finally语句是可选的,如果有的话,则不管是否发生异常,finally语句都会被执行。
public class TestTryCatchFinally {public static void main(String[] args) {
// //1.try..catch
// try {
// int result = 1/1;
// System.out.println(result);
// }catch(Exception e) {
// e.printStackTrace();
// }
// //2.try...finally
// try {
// System.out.println("try中的代码..");
// int result = 1/0;
// }finally {
// System.out.println("finally中的代码...");
// }//3.try...catch...finallytry {System.out.println("try中的代码..");int result = 1/0;}catch(Exception e) {System.out.println("catch中的代码...");}finally {System.out.println("finally中的代码...");}}
}

注意事项
1. 即使try和catch块中存在return语句,finally语句也会执行。是在执行完finally语句后再通过return退出。
2. finally语句块只有一种情况是不会执行的,那就是在执行finally之前遇到了System.exit(0)结束程序运行。
4.异常的处理方式之二:声明异常(throws子句)
声明异常的关键字 throws
方法名的后面,用于声明该方法可能会产生一个异常如果方法声明的是 Exception 类型的异常或者是 Checked Exception 异常,要求方法的调用处必须做处理。
(1)继续使用 throws 向上(方法的调用处)声明
(2)使用 try-catch-finally 进行处理
如果声明的是 RuntimeException 类型的异常,那么方法的调用处可处理可不处理。
继承关系中的声明异常
1) 父类的方法声明了 Exception 类型的异常,子类在重写方法时,可以声明也可以不声明。但是如果子类重写 后的方法使用super 关键字调用父类的方法,那么要求必须对异常进行处理。
2) 如果父类的方法没有异常,那么子类的方法如果一定会有 Exception 或 Checked 异常,要求子类必须自己使用 try-catch 处理,或者给父类方法加上异常的声明
3) 如果子类在重写父类的方法时,产生的异常是RuntimeException 异常时,那么可以不用处理
throw 抛出异常对象
在捕获一个异常前,必须有一段代码先生成异常对象并把它抛出。这个过程我们以手工做,也可以由 JRE 来实现,但是他们调用的都是 throw 子句。
throws 与 throw
(1)throws 用于声明方法可能会产生的异常类型
throw 手动抛出异常对象
(2) throws 写在方法名称后面
throw 用于写在方法里
import java.io.File;
import java.io.IOException;
/*** throws与throw* 通过throws声明异常:跟在方法声明的后边,用于告知方法的调用者该方法有可能存在异常。* 方法的调用者可以使用try...catch...finally捕获异常或者使用throws继续讲异常声明出去。* 通过throw抛出异常:放在方法的内部,用于抛出异常,经常与throws结合使用。* throws与throw区别* 1.位置不同:throws放在方法声明的后边,用于声明该方法可能出现的异常,throw放在方法的内部,用于抛出具体的异常对象。* 2.类型不同:throws后跟声明异常的是异常的类型,throw后根具体的异常对象。*/
public class TestThrows {public static void test()throws Exception{}public static void test2()throws Exception{File file = new File("D:/aa.txt");try {file.createNewFile();//创建文件IOException属于检查异常,必须进行处理才能通过编译。}catch(IOException e) {e.printStackTrace();throw e;//抛出异常,后边跟异常对象}}public static void main(String[] args) {/*throws Exception{*/
// try {
// test();
// }catch(Exception e) {
// e.printStackTrace();
// }}}
5.自定义异常
1.在程序中,可能会遇到JDK提供的任何标准异常类都无法充分描述清楚我们想要表达的问题,这种情况下可以创建自己的异常类,即自定义异常类。
2.自定义异常类只需从Exception类或者它的子类派生一个子类即可。
3.自定义异常类如果继承Exception类,则为受检查异常,必须对其进行处理;如果不想处理,可以让自定义异常类继承运行时异常RuntimeException类。
4.习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另一个是带有详细信息的构造器。
自定义异常类
/*** 自定义异常:可能会遇到JDK提供的任何标准异常类都无法充分描述清楚我们想要表达的问题,这种情况下可以创建自己的异常类,即自定义异常类* 实现步骤:* 1.编写一个类继承exception* 2.编写该类的构造方法,并在构造方法中调用父类(Exception)中的构造方法为消息赋值。* 3.可以通过getMessage()方法获取消息信息。*/
public class AgeException extends Exception{public AgeException(String message) {super(message);//调用父类的构造方法}
}
自定义异常类的使用
public class Person {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) throws AgeException{if(age>0&&age<150) {this.age = age;}else {throw new AgeException("年龄必须在0-150之间");//年龄不符合要求,抛出异常}}@Overridepublic String toString() {return "person [name="+name+",age="+age+"]";}public static void main(String[] args) {Person person = new Person();person.setName("zhangsan");try {
// person.setAge(20);person.setAge(-20);}catch(AgeException e) {System.out.println(e.getMessage());//获取消息信息// e.printStackTrace();}System.out.println(person);}
}

使用异常机制的建议
1.要避免使用异常处理代替错误处理,这样会降低程序的清晰性,并且效率低下。
2.处理异常不可以代替简单测试---只在异常情况下使用异常机制。
3.不要进行小粒度的异常处理---应该将整个任务包装在一个try语句块中。
4.异常往往在高层处理(先了解!后面做项目会说!) 。