文章目录
七.异常处理
(1)异常概述
error问题情况:
①:栈溢出:报错情况
②:堆溢出:报错情况
public class ErrorTest {
public static void main(String[] args){
//1.栈溢出:报StackOverflowError
//main(args);
//2.堆溢出:报OutOfMemoryError
//Integer[] arr=new Integer[1024*1024*1024];
}
}
(2)异常体系结构
java.lang.Throwable
java.lang.Error:一般不编写针对性的代码进行处理
java.lang.Exception:可以进行异常的处理
编译时异常:(checked):
运行时异常:(unchecked)
(3)常见异常
/* 编译时异常:(checked):
* 例:IoException
* ClassNotFoundException
* FileNotFoundException
* 运行时异常:(unchecked)
* 例:NullPointerException 空指针异常
* ArrayIndexOutOfBoundsException 数组角标越界
* ClassCastException 类型转换异常
* NumberFormatException 数字格式异常
* InputMismatchException 输入不匹配
* ArithmeticException 算数异常
*/
* ************************运行时异常********************************
* 1.NullPointerException:空指针异常
*
* int[] arr=null;
* System.out.println(arr[3]);
*
* String str="abc";
* str=null;
* System.out.println(str.charAt(3));
*
* 2.ArrayIndexOutOfBoundsException:数组角标越界
* int[] arr=new int[10];
* System.out.println(arr[10]);
*
* String str="abc";
* System.out.println(str.charAt(3));
*
* 3.ClassCastException:类型转换异常
* Object obj=new Date();
* String str=(String)obj;
*
* 4.NumberFormatException:数字格式异常
* String str="123";
* str="abc";
* int num=Integer.parseInt(str);
*
* 5.InputMismatchException:输入不匹配
* Scanner scanner=new Scanner(System.in);
* int score=scanner.nextInt();
* System.out.println(score);
*
* 6.ArithmeticException:算数异常
* int a=10;
* int b=0;
* System.out.println(a/b);
(4)异常的处理:抓抛模型
过程一:“抛”:程序正在执行时,一旦出现异常,会在异常代码处生成一个对应异常类的对象。并将此对象抛出
一旦抛出对象以后,其后的代码就不再执行
过程二:“抓”:可以理解为异常的处理方式:①try-catch-finally ②throws
(5)异常处理机制1:try-catch-finally
/**
*
* try-catch-finally的使用:
* try{
* //可能出现异常的代码
* }catch(异常类型1 变量名1){
* //处理异常的方式1
* }catch(异常类型2 变量名2){
* //处理异常的方式2
* }catch(异常类型3 变量名3){
* //处理异常的方式3
* }
* .....
* finally{
* //一定会执行的代码
* }
*
* 1.finally是可选的。
* 2.使用try将可能出现异常的代码包装起来,在执行过程中,一旦出现异常,
* 就会自动生成一个异常类的对象,根据此对象的类型,去catch中匹配
* 3.一旦try中的异常对象匹配到某一个catch,就进入catch中处理异常。
* 一旦处理完成,就跳出当前的try-catch结构(在没有写finally的情况下)。继续执行其后的代码。
* 4.catch中的异常类型,如果没有子父类关系,谁声明在上无所谓,如果满足字符类关系,则要求子类一定声明在父类之
* 上,否则报错。
* 5.常用的异常对象说明方式:①:String getMessage() ②:printStackTrace()
* 6.在try结构中声明的变量,在出了try结构以后,就不能被调用
* 7.try-catch-finally结构可以嵌套
*
*/
public class ExceptionTest{
public void test1(){
String str="123";
str="abc";
int num=0;//如果try结构外要使用,现在try外声明(需要赋值,万一try中未赋值上,相当于没初始化)
try {
num = Integer.parseInt(str);//出现异常
//出现异常后续代码不执行,所以hello------1不执行
System.out.println("hello------1");
//不是错误的类型,不执行
}catch(NullPointerException e){
System.out.println("出现空指针异常,不要着急......");
}catch(NumberFormatException e){
System.out.println("出现数值转换异常,不要着急......");//处理异常
//①:String getMessage()
System.out.println(e.getMessage());
//②:printStackTrace()
e.printStackTrace();
}
//try外使用num
System.out.println(num);
//处理完成继续执行后续代码,这里hello------2是执行的
System.out.println("hello------2");
}
}
编译时异常处理例子:
①:使用try-catch-finally处理编译异常时,使得程序在编译时就不再报错,但是运行时仍可能报错
相当于使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现
②:开发中,由于运行时异常很常见,所以我们通常就不针对运行时异常编写try-catch-finally
针对于编译时异常,我们说一定要考虑异常的处理
try-catch-finally中finally的使用:
1.finally是可选的
2.finally中声明的一定是可执行代码,即使catch中又出现异常,try中有return语句,catch有return语句等情况
3.像数据库连接,输入输出流,网络编程Socket等资源,JVM是不能自动回收的,我们需要自己手动进行资源的 释放。此时的资源释放的操作就要放在finally中。
public int method(){
try{
int[] arr=new int[10];
System.out.println(arr[10]);
//上面出异常,此return不执行,则需要在在下方也写一个return
return 1;
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
//这里也需要return
return 2;
}finally {
System.out.println("我一定会被执行");
//如果finally中有return则返回finally的值(体现出一定被执行)
return 3;
}
}
(6)异常处理机制2:throws
/**
* 异常处理方式二:throw+异常类型:
*
* 1.“throw+异常类型”写在方法的声明处,指明此方法执行时,可能会抛出的异常类型
* 一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象
* 满足throw后异常类型时,就会被抛出。异常代码后面的代码就无法被执行
*
* 2.try-catch-finally:真正将异常处理掉
* throws的方式:只是将异常抛给了方法的调用者,并没有正在把异常处理掉
*
*/
public class ExceptionTest2 {
public static void main(String[] args){
// try {
// method2();
// } catch (IOException e) {
// e.printStackTrace();
// }
method3();
}
//可以写一个方法来处理异常,处理完毕可以直接在main中调用
public static void method3(){
try {
method2();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void method2()throws IOException{
method1();
}
public static void method1() throws FileNotFoundException, IOException {
File file =new File("hello.txt");
FileInputStream fis=new FileInputStream(file);
int data= fis.read();
while(data!=-1){
System.out.println((char)data);
data=fis.read();
}
fis.close();
}
}
(7)重写方法异常抛出的规则
/**
* 方法重写的规则之一:
* 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
*
*
*
*
*
*/
public class OverrideTest {
public void display(SuperClass s1){
try {
s1.method();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SuperClass{
public void method() throws IOException{
}
}
class SubClass extends SuperClass{
//重写方法throws的异常类型比父类中的小,Exception权限大,所以不可以
public void method() throws FileNotFoundException /*Exception*/{
}
}
(8)开发中,两种方法的选择
1.如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类中重写 的方法中有异常,必须使用try-catch-finally方式处理
2.执行的方法a中,先后又调用了另外几个方法,这几个方法是递进关系执行的。我们建议这几个方法用throws的方式 进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理
(9)手动抛出异常
关于异常对象的产生:①:系统自动生成的异常对象
②:手动生成一个异常对象,并抛出throw(并非throws)
public class StudentTest {
public static void main(String[] args){
try {
Student s1=new Student();
s1.regist(-1001);
System.out.println(s1);
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
class Student{
private int id;
public void regist(int id) throws Exception{
if(id>0){
this.id=id;
}else{
// System.out.println("输入数据非法!");
//手动抛出一个异常对象
// throw new RuntimeException("输入数据非法!");//运行时异常,只在运行时出异常
throw new Exception("输入数据非法!");//编译时异常,需要编译前进行处理
}
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
'}';
}
}
(10)用户自定义异常类
/**
* 如何自定义异常类?:
* 1.继承于现有的异常结构:RuntimeException,Exception
* 2.提供全局常量serialVersionUID
* 3.提供重载的构造器
*
*
*/
public class MyException extends RuntimeException {
static final long serialVersionUID = -7034897190745766939L;
public MyException() {
}
public MyException(String message) {
super(message);
}
}
public void regist(int id) throws Exception{
if(id>0){
this.id=id;
}else{
// System.out.println("输入数据非法!");
//手动抛出一个异常对象
// throw new RuntimeException("输入数据非法!");//运行时异常,只在运行时出异常
// throw new Exception("输入数据非法!");//编译时异常,需要编译前进行处理
//在要抛异常的地方使用
throw new MyException("不能输入负数");
}
}