【Java】基础17_异常,throws关键字,throw关键字,自定义异常


1.错误和异常区别

package com.itheima01.throwable;
import java.util.Arrays;
/*
*   错误(Error) : 从程序角度 只能避开,不能解决
*   异常(Exception) : 从程序角度 可以解决的问题
*/
public class ThrowableDemo {
    public static void main(String[] args) {
        //java.lang.OutOfMemoryError: Java heap space
            // OOM : 内存溢出 ,错误
//        int[] array = new int[2_000_000_000];
//        System.out.println(Arrays.toString(array)); //20亿撑不住

        int[] array = {0,1};
        //java.lang.ArrayIndexOutOfBoundsException
        System.out.println(array[1]); //1
    }
}

在这里插入图片描述

package com.itheima02.jvm;
import java.util.ArrayList;
/*
*  throw 关键字
*       1. 效果等同于return,后续代码不再执行
*       2. throw + Throwable对象(异常对象);   return 返回值;
*       3. 运用: 我们一般不使用, JDK方法的设计者 (抛出异常: api设计者 和 使用者交流方式)
*/
public class ThrowDemo {
    public static void main(String[] args) {
//        new ArrayList<String>(-1);
        int[] array = {0,1};
        int element = getElement(array);
        System.out.println(element);
    }

    private static int getElement(int[] array) {
        int index = 2;
        if(index > array.length - 1){
            //访问了数组不存在的索引
//          ArrayIndexOutOfBoundsException e = new ArrayIndexOutOfBoundsException("you are a stupid bird,you access a wrong index:" + index);
//          throw e;
			//下行同上两行
            throw  new ArrayIndexOutOfBoundsException(index);
			//throw new Throwable(""); //也可以,但声明getElement方法后要加throws Throwable
        }
        int element = array[index];
        return element;
    }
}

2.编译异常和运行时异常

在这里插入图片描述

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        String str = "1996-01-01";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        sdf.parse(str); //解析异常

//        FileOutputStream fos = new FileOutputStream("");
//        fos.write(97); //IOException

//       1.  NullPointerException  空指针
        String s = null;
//        System.out.println(s.length());

       // 2. IndexOutOfBoundsException  索引越界
        int[] array = {};
//        System.out.println(array[1]);

        // 3. ClassCastException  类转换

        //4. IllegalArgumentException 非法参数
        new ArrayList<String>(-1);
    }
}

3.处理异常

在这里插入图片描述

package com.itheima03.throwsd;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class ThrowsDemo {
    public static void main(String[] args) throws IOException {
        method01(); //表哥又抛出去叫大哥(jvm),jvm出错又打印终止
    } 
    /*
    *  throws 关键字
    *    1. 用在方法声明上:
    *           修饰符 返回值类型 方法名(参数列表) throws 异常类型(A)
    *
    *    2. 这是处理异常的一种方式: 声明将异常抛出给调用者处理(假手与人)
    *
    *    3. 注意: 这里的异常类型A 必须跟方法里要抛出的异常B一致, 或者A是B的父类 (向上转型)
    *
    *    4. 语法: throws 异常1,异常2{ }
    *
    *    运用: 我们可以在某一方法的设计上先声明抛出异常,可以方法的调用处进行处理
    *           切记有有一环节必须处理, 不然到JVM中, 出现异常就崩溃
    *
    *    我们平时学习为了省事, 如果明知不会错的异常,直接throws
    */
    private static void method01() throws IOException { //交给表哥
        FileOutputStream fos = new FileOutputStream("a.txt");
        fos.write(97);
    }
}

在这里插入图片描述

package com.itheima04.trycatch;
/*
*  try...catch  关键字,像if..else..
*       try{
            //可能会出现异常的代码
        }catch (Exception e){
            //1. 如果出现异常
            //2. 如果能够捕获到该异常
            //3. 在这里写处理异常的方案
        }
*/
public class TrycatchDemo {
    public static void main(String[] args) {
        int[] array = {0,1};
        try{
            int element = array[2];
            System.out.println(element);
        }catch (Exception e){
            e.printStackTrace();//打印异常信息: 打印栈中追溯,案发地点在方法栈中      
            System.out.println("出现异常,并被捕获了");
        }
        System.out.println("程序继续执行");
    }
}

在这里插入图片描述

package com.itheima04.trycatch;
import java.util.Scanner;
/*
*   try...catch运用:
*       1. 如果代码都是由我们自己编写的,我们一般都不会出现异常
*       2. 有些代码需要用户参与编写 (交互: 我们程序输出,用户输入)
*思想: 我们预知代码可能运行结果(如果了包含了异常, 提前try...cath并给出提示或者解决方案)
*/
public class TryCatchDemo02 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个被除数:");
        int a = sc.nextInt();
        System.out.println("请输入一个除数:");
        int b = sc.nextInt();
        try {
            //java.lang.ArithmeticException: / by zero  算术异常
            int result = a/b;
            System.out.println(result);
        }catch (Exception e){
            System.out.println("你个傻鸟,除数不能为0");
        }
        System.out.println("软件继续让你玩");
    }
}
package com.itheima04.trycatch;
/*
      try{
       }catch (NullPointerException e){
           //1. 如果出现了空指针,应该提示...
       }catch (IndexOutOfBoundsException e2){
           //2. 如果出现了索引越界, 应该提示...
       }
       思想: 异常的分类讨论
       执行顺序:
            如果try中代码发生异常, 那么多个catch会从上到下逐一尝试捕获,
            如果被A捕获了,后续的catch不再执行
       注意:
            1. 前面catch中的异常类型 不能 后面catch中的异常类型的父类或者相同 (因为这样的话,后续catch执行不到没有意义)
            2. 后面catch中的异常类型可以是前面的父类
*/
public class TryCatchCatchDemo {
    public static void main(String[] args) {
       try{
           method01(2);
       }catch (NullPointerException e){
           System.out.println("发生了空指针异常");
       }catch (IndexOutOfBoundsException e2){
           System.out.println("发生了索引越界异常");
       }
        System.out.println("代码继续执行");
    }
    //模拟: 这段代码可能有两个异常(一段代码里面不论可能有多少个异常,一次运行最多抛出一个异常)
    private static void method01(int a) {
        if(a == 1){
            throw new NullPointerException("空指针");
        }else if(a == 2){
            throw new IndexOutOfBoundsException("越界异常");
        }else{
            System.out.println("什么事都没发生");
        }
    }
}

在这里插入图片描述

4.finally关键字

package com.itheima04.trycatch;
/*
        try{
        }catch (Exception e){
        }finally {
           // 无论如何,一定最后执行
        }
        作用: (IO流)释放资源
*/
public class FinallyDemo {
    public static void main(String[] args) {
//        method();
       int number =  method2();
        System.out.println(number); //1
    }
	
    private static int method2() {
        int i = 1;
        try{
//          System.exit(0); //拔电源
            return i; //finally会抢夺try...catch中的return执行权,finally会先执行,执行完又回到return 
       //return 安全机制: 把i的值给记录下来了1  //try..catch中一旦有return,后面return不会执行
        }catch (Exception e){ //没有异常,i不会=2
            i = 2;
        }finally {
            i = 3;
            System.out.println("运行 :" + i);
        }
        return i;
    }

    private static void method() {
        try{
            int i = 4/0;
            System.out.println(i);
        }catch (NullPointerException e){
            System.out.println("异常发生了");
        }finally {
            System.out.println("无论如何一定执行");
        }
        System.out.println("程序继续执行");
    }
}

在这里插入图片描述
在这里插入图片描述

5.自定义异常

package com.itheima05.custom;
/*
*   JavaBean : 标准类 (封装)
*       1. private属性
*       2. public get set方法
*       3. public 空参构造,不声明构造会有一个空参构造
*		   写满参构造就得写空参构造
*   封装 :
*      1. private属性 为了不对外直接暴露 -> 安全
*      2. public get set方法
*      方法跟属性最大不同, 方法可以加条件判断(健壮性校验)
*   继承 :自定义异常
*/
public class Student {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age < 0){
//            throw new IllegalArgumentException("你个傻鸟,age没有负数");
            throw new NoAgeException("你个傻鸟,age没有负数");
        }
        this.age = age;
    }
}
package com.itheima05.custom;
/*
* 自定义异常: IllegalArgumentException : 非法参数异常
* NoAgeException : 非法年龄异常(框架: 很多JDK没有的异常,自定义)
*/
public class CustomDemo {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("张三");
//        s.age = -18; // 非法访问,安全隐患,所以private int age;
        s.setAge(-18); //在方法里加安全机制
        System.out.println(s);
    }
}
class NoAgeException extends IllegalArgumentException{
    public NoAgeException(String msg){
        super(msg);
    }
}
package com.itheima06.notice;
import java.io.IOException;
/*
*   现象: 1. 父类 方法中声明编译异常,而子类没有声明编译异常 不会报错
*         2. 父类 方法中未声明编译异常,而子类有声明编译异常 会报错 !!!!!
*
*   解释: 现象2 跟 多态冲突了
*       1.现象2在多态中,编译器只看左边,父类方法没有编译异常,以为没有编译异常,不需要处理
*       2.运行看右边,子类重写的方法运行时有编译异常 (要求: 编译时期必须处理)
*       冲突: 编译异常 绕过了 编译器 (编译器强制报错)
*/
public class NoticeDemo {
    public static void main(String[] args) throws IOException {
        //编译看左边,运行看右边
        Fu fu = new Zi();
        fu.method();
    }
}
class Fu{
    void method() {
    }
}
class Zi extends Fu{
    @Override
    void method() throws RuntimeException{//不报错 //throws IOException编译异常会报错
    }
}

在这里插入图片描述
在这里插入图片描述

package com.atguigu.test03;

import java.util.Scanner;
/*
 * 异常:
 * 	不正常
 *  在某些情况下,因为用户的一些原因,例如:配置问题、错误输入的问题、用户磁盘空间满了等因素,导致程序无法正常运行。
 *  
 *  不是异常:(1)语法错误(2)逻辑错误
 * 
 * Java的程序如果出现异常,并且在代码中,没有做相应的处理,那么程序会“崩溃”,“挂了”
 * 
 * Java如何处理异常?或Java异常处理的过程?
 * (1)当程序运行到某一句时,发生了异常,那么程序会先停下来
 * (2)程序会在这句代码处,查看原因,生成一个合理“异常对象”,然后“抛”出
 * (3)JVM会检测在这句代码的外围,是否有try..catch结构,可以“捕获”它,
 * 如果可以捕获,那么程序再处理完异常后,继续下面的运行,不会崩溃;
 * 如果不能捕获,那么会把这个异常继续抛给“上级”,如果“上级”能处理,那么程序从“上级"处理完的代码后面继续运行;
 * 如果上级也 不能处理,那么继续往上抛,一直到达JVM,那么就“崩溃”
 */
public class TestException {
	public static void main(String[] args) {
//		System.out.println(a);//语法错误		
		int sum = getSum(1,2);
		System.out.println("sum = " + sum);		
			try {
				testInput();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		System.out.println("main的其他代码");
	}
	
	public static void testInput(){
		Scanner input = new Scanner(System.in);
		try {
			System.out.print("请输入一个整数:");
			int num = input.nextInt();
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("输入有误");//这里 只是提醒,没有让他 重新输入
		}		
		System.out.println("其他的代码");
	}
		
	//求两个整数的和
	public static int getSum(int a ,int b){
		return a - b;
	}
}

在这里插入图片描述

2.异常的类型体系结构

package com.atguigu.test03;
/*
 * 所有类的根父类是Object。
 * 枚举的公共父类是Enum,根父类仍然是Object
 * 异常的公共父类是Throwable,根父类仍然是Object
 * 
 * 1、异常的公共父类:java.lang.Throwable
 * (1)只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句“抛”出。
 * (2)只有此类或其子类之一才可以是 catch 子句中的参数类型。 
 * 
 * 2、Throwable又分为两大派别:
 * (1)Error:错误
 * 		一般指严重错误,一般合理的应用程序不应该试图去捕获它。
 *		如果出现这个问题,要么需要升级程序,要么需要升级架构,要么需要升级硬件。
 *		例如:报了一个OutOfMemoryError
 *
 *		经典代表:VirtualMachineError(堆内存溢出OutOfMemoryError,栈内存溢出StackOverflowError)
 * (2)Exception:异常
 * 		一般异常,合理的应用程序应该试图去捕获它。
 * 
 * 3、Exception还可以分为两大类:
 * (1)运行时异常(RuntimeException或它子类):又称为非受检异常
 * 		编译时,编译器是不会提醒你做处理的,只有运行期间,才会发生。
 * 		运行时异常是不建议用try...catch,因为它发生频率太高,而且一般都是很不应该发生的问题。
 * 		例如:空指针异常,数组下标越界异常,类型转换异常等,这些异常完全可以避免掉。
 * 		但是如果实在没有考虑到,也可以通过try...catch处理。
 * 
 * (2)编译时异常,除了RuntimeException系列以外的,都是编译时异常。又称为受检异常。
 * 		编译时,编译器会强制要求程序员编写处理的代码,如果你不编写,那么就编译不通过。
 * 		例如:FileNotFoundException,IOException等
 */
public class TestExceptionType {
	public static void main(String[] args) {
		
	}
}   

3.异常的处理

在这里插入图片描述
解决如上问题,选中main右击Run As - Run Configurations
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.atguigu.test04;
/*
 * 一、异常的处理方式:try...catch
 * 1、语法格式:
 * try{
 * 		可能发生异常的代码
 * }catch(异常类型1  异常对象名){//异常对象名绝大多数都是写e
 * 		处理这个异常的代码
 * }catch(异常类型2  异常对象名){//异常对象名绝大多数都是写e
 * 		处理这个异常的代码
 * }catch(异常类型3  异常对象名){//异常对象名绝大多数都是写e
 * 		处理这个异常的代码
 * }
 * 。。。。
 * 
 * 2、异常对象(e)的常用方法
 * (1)e.printStackTrace();
 * 打印异常的详细信息,包括追踪跟踪信息,即这个异常对象一路经过了哪些方法
 * (2)e.getMessage();
 * 返回异常对象中简单的错误信息提示,其实上面已包含
 * 
 * 3、打印异常/错误信息
 * System.err.println(xx);打印错误信息,红色,下行黑色
 * System.out.println(xx);打印正常信息
 * 
 * 4、多个catch分支,如何匹配和执行的?
 * 从上到下依次判断,一旦有一个满足,后面就不看了。
 * 
 * 建议:如果多个catch中的异常类型有大小包含关系,那么小的在上,大的在下,如果没有大小包含关系,顺序随意。
 * 
 * 5、如果catch,可以捕获try中发生的异常,那么程序,会从try...catch下面的代码继续运行 ,不会崩溃。
 * 	如果catch无法捕获try中发生的异常,那么就会导致当前方法结束,并把异常对象抛出调用者,
 * 如果调用者可以处理,那么从调用者处理代码的后面继续运行,否则继续往上抛,最终到达JVM,程序就崩溃了。
 */
public class TestTryCatch {
	//从命令行接收2个整数,求商
	public static void main(String[] args) {
		try {
			int a = Integer.parseInt(args[0]);//第一个参数赋值给a变量,字符串转为int值
			int b = Integer.parseInt(args[1]);//第二个参数赋值给b变量
			int shang = a/b;
			System.out.println(a +"/" + b + "=" + shang);
		} catch (NumberFormatException e) {
			e.printStackTrace();//标准的
//			System.err.println(e.getMessage());
//			System.out.println(e.getMessage());
		} catch (ArrayIndexOutOfBoundsException e){
			e.printStackTrace();
		} catch (ArithmeticException e){
			e.printStackTrace();
		} catch (Exception e){
			e.printStackTrace();
		} 				
		System.out.println("其他的代码....");
	}
}
package com.atguigu.test04;
/*
 * 二、try..catch的形式二
 * try{
 * 		可能发生异常的代码
 * }catch(异常类型1  异常对象名){//异常对象名绝大多数都是写e
 * 		处理这个异常的代码
 * }catch(异常类型2  异常对象名){//异常对象名绝大多数都是写e
 * 		处理这个异常的代码
 * }catch(异常类型3  异常对象名){//异常对象名绝大多数都是写e
 * 		处理这个异常的代码
 * }
 * 。。。。
 * finally{
 * 		不管try中是否发生异常,也不管catch是否可以捕获异常,这里代码都必须执行
 * }
 * 
 * 一般用于编写释放资源,断开连接等代码
 * 
 * 特殊情况:没有catch部分也行
 * try{
 * 		
 * }finally{
 * 		
 * }
 */
public class TestTryCatchFinally {
	public static void main(String[] args) {
		try {
			int a = 1;
			int b = 0;
			System.out.println(a/b);
		} catch (ArrayIndexOutOfBoundsException e) { //抓不住
			e.printStackTrace();
		} finally{
			System.out.println("最终块");
		}
	}
}
package com.atguigu.test04;

public class TestFinallyReturn {
	public static void main(String[] args) {
		String str = getNum(1);
		System.out.println(str);
	}
	
	public static String getNum(int a){
		try{
			System.out.println(a/0); //异常跳到catch处
			if(a > 0){
				return "正数";
			}else if(a < 0){
				return "负数";
			}else{
				return "零";
			}
		}catch(Exception e){
			return "异常";
		}finally{
			return "最终";
		}
	}
}

在这里插入图片描述

package com.atguigu.test04;
/*
 * finally与return混用:
 * (1)不管try中是否发生异常,也不管catch是否可以捕获异常,也无论try或catch中是否有return。
 * 	finally中的代码都必须执行
 * (2)如果finally中有return,就从finally块的的return回去。
 * (3)如果finally中没有return,那么先把try或catch中该执行的执行完,
 * 在return结束当前方法之前,先走一下finally,然后回去结束当前方法
 */
public class TestFinallyNoReturn {
	public static void main(String[] args) {
		String str = getNum(1);
		System.out.println(str);
	}
	
	public static String getNum(int a){
		try{
			System.out.println(a/0);
			if(a > 0){
				return "正数";
			}else if(a < 0){
				return "负数";
			}else{
				return "零";
			}
		}catch(Exception e){
			System.out.println("exception");
			return "异常"; //最后走
		}finally{ //里面没return
			System.out.println("finally");
		}
	}
}

在这里插入图片描述

package com.atguigu.test04;
/*
 * finally与return混用:
 * (1)不管try中是否发生异常,也不管catch是否可以捕获异常,也无论try或catch中是否有return。
 * 	finally中的代码都必须执行
 * (2)如果finally中有return,就从finally块的的return回去。
 * (3)如果finally中没有return,那么先把try或catch中该执行的执行完(包括把返回值的结果放到要带回调用处的操作数栈的位置)
 * 在return结束当前方法之前,先走一下finally,然后回去结束当前方法.
 * 结论,如果finally中没有return,finally中的代码不影响返回值。
 * finally里一般不写return,用来关闭资源
 */
public class TestFinallyNoReturn2 {
	public static void main(String[] args) {
		int num = getNum(4);
		System.out.println(num);//0,不是30
	}
	
	public static int getNum(int a){
		int result = 10;
		try{
			System.out.println(a/0); //直接跳到catch
			if(a > 0){
				result = 20;
				return result;
			}else if(a < 0){
				result = -20;
				return result;
			}else{
				return result;
			}
		}catch(Exception e){
			System.out.println("exception");
			result = 0;
			return result;
		}finally{
			result = 30;
			System.out.println("finally");
//			return result;//如果有这句,最后一行结果就变成30
		}
	}
}

在这里插入图片描述

4.异常练习

在这里插入图片描述

package com.atguigu.test05;

import java.util.InputMismatchException;
import java.util.Scanner;
/*
 * 1、练习1
从键盘输入两个整数a,b,求两个数的和、差、积、商
并且尝试使用try...catch处理可能发生的异常

快捷键:Alt +Shift  + Z  弹出surround with xxx
 */
public class TestExer {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		try {
			System.out.print("请输入一个整数:");
			int a = input.nextInt();
			
			System.out.print("请输入另一个整数:");
			int b = input.nextInt();
			
			System.out.println("和:" + (a+b));
			System.out.println("差:" + (a-b));
			System.out.println("积:" + (a*b));
			System.out.println("商:" + (a/b));
		} catch (InputMismatchException e) {
			System.err.println("输入错误,应该输入整数");
		} catch (ArithmeticException e) {
			System.err.println("除数不能为0");
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			input.close();//资源关闭
		}
	}
}
package com.atguigu.test05;

import java.util.InputMismatchException;
import java.util.Scanner;
/*
增加要求:如果输入有问题,提示错误信息后重新输入,如果没问题,就不重新输入
 */
public class TestExer2 {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		while(true){
			try {
				System.out.print("请输入一个整数:");
				int a = input.nextInt();//"a"不被int接收,一直在通道中,要读出来丢掉
				
				System.out.print("请输入另一个整数:");
				int b = input.nextInt();
				
				System.out.println("和:" + (a+b));
				System.out.println("差:" + (a-b));
				System.out.println("积:" + (a*b));
				System.out.println("商:" + (a/b));
				break; //一切正常,走一次就行
			} catch (InputMismatchException e) {
				System.err.println("输入错误,应该输入整数");
				String str = input.nextLine();//读取当前行所有内容,我没有接受,就表示丢弃了
				System.out.println(str);
			} catch (ArithmeticException e) {
				System.err.println("除数不能为0");
			} catch (Exception e) {
				e.printStackTrace();
			} 
		}		
		input.close();
	}
}

在这里插入图片描述
在这里插入图片描述

package com.atguigu.test05;
/*
 * (1)try..finally,可以没有catch
 * (2)无论try是否有异常,是否catch可以捕获异常,也无论try和catch有没有return,finally一定走
 */
public class TestExer3 {
	public static void main(String[] args) {
		try{
			return;
		}finally{
			System.out.println("finally");
		}
	}
}

在这里插入图片描述

package com.atguigu.test05;
/*
 * (1)finally里面有return,就从finally的return回去了
 * (2)类初始化:main所在的类要先初始化,才能执行main方法
 * 由①静态变量的显示赋值(这里没有)②静态代码块
 *(3)实例初始化:必须要new对象才会有,这里没有创建TestExer4的对象,所以不走
 */
public class TestExer4 {
	{
		System.out.println("b");
	}
	static{
		System.out.println("a");
	}
	TestExer4(){
		System.out.println("c");
	}
	public static String getOut(){
		try{
			return "1";
		}catch(Exception e){
			return "2";
		}finally{
			return "3";
		}
	}
	public static void main(String[] args) {
		System.out.println(getOut());//3
	}
}

在这里插入图片描述
在这里插入图片描述

5.throws关键字

如下是运行时异常,不加throws也通过
在这里插入图片描述
在这里插入图片描述
如下String类型装不住Object类型
在这里插入图片描述
在这里插入图片描述

package com.atguigu.test06;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
/*
 * 异常处理的方式之一:
 * 		在当前方法中直接用try...catch处理
 * 异常处理的方式之二:
 * 		在当前方法中不处理,扔/抛给调用者处理
 * 
 * throws的好处:
 * (1)throws:告知被调用者,我这个方法可能会抛出哪些异常,使得调用者可以明确的知道应该catch什么异常
 * 如果没有throws,那么调用者就不清楚,只能按照Exception处理,或者根据错误经验来处理。
 * (2)编译时异常,如果在当前方法中不用try..catch处理,编译不通过,那么可以通过throws明确的说明,抛给调用者处理
 * 
 * throws的语法格式:
 * 	【修饰符】 返回值类型  方法名(【形参列表】)throws 异常列表们{
 * }
 * 说明:throws后面可以跟好几个异常,顺序无所谓,每一个异常之间使用,分割
 * 
 * 关于方法重写时,对throws抛出的异常的要求:
 * 	子类重写的方法抛出的异常类型必须<=父类被重写的方法抛出的异常类型。
 * 
 * 例如:Exception > RuntimeException > ArrayIndexOutOfBoundsException
 * 	
 * 整理重写的要求:
 * (1)方法名:相同
 * (2)形参列表:相同
 * (3)返回值类型:
 * 		基本数据类型与void:相同
 * 		引用数据类型:<=
 * (4)修饰符
 * 	  权限修饰符:>= (只一个大于等于)
 * 	其他修饰符:不能是final,private,static
 * (5)抛出的异常类型:<=
 */
public class TestThrows {
	public static void main(String[] args) {
			try {
				divide(1,1);
			} catch (ArithmeticException e) {
				e.printStackTrace();
			} catch (RuntimeException e) {
				e.printStackTrace();
			}
			
			try {
				copy("1.txt","2.txt");
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			Father f = new Son();//多态引用
			try {
				f.method();
			} catch (RuntimeException e) {
				e.printStackTrace();
			}
			
			Father f2 = new Son();
			Object str = f2.test();
	}
	
	public static void divide(int a, int b)throws ArithmeticException,RuntimeException{
		System.out.println(a/b);
	}
	
	public static void copy(String srcFile, String destFile) throws FileNotFoundException{
		FileInputStream fis = new FileInputStream(srcFile);//用来读取srcFile文件的内容
	}
}
class Father{
	public void method()throws RuntimeException{
		//....
	}
	
	public Object test(){
		return null;
	}
}
class Son extends Father{
	@Override
	public void method()throws ArrayIndexOutOfBoundsException{
		//....
	}
		
	@Override
	public String test(){
		return "";
	}
}

6.throw关键字

throw提供了一种把错误信息往回传的途径
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.atguigu.test07;
/*
 * 异常的对象的创建和抛出有两种方式:
 * (1)JVM创建并抛出
 * (2)程序员new出来,然后由throw抛出。
 * 
 * Throwable:
 * 		只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
 * 		类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。 
 * 
 * throw:
 * 	用于手动抛出异常对象。
 * 语法格式:
 * 	throw 程序员new的异常对象;
 * 
 * 可以代替return语句,结束当前的方法
 * 
 * 面试题:throw和throws什么区别?
 * (1)throw用于手动抛出异常对象,是个可执行的语句
 * (2)throws,在方法签名中,声明方法可能抛出什么异常,让调用者来处理这些异常。
 */
public class TestThrow {
	public static void main(String[] args) {
		Account a = new Account(100);
		try {
			boolean flag = a.withdraw(500);
			//如果没有异常,取款成功
			System.out.println("取款成功" + flag);
		} catch (IllegalArgumentException e) {
//			System.out.println(e.getMessage());
			e.printStackTrace();
		} catch (RuntimeException e) {
//			System.out.println(e.getMessage());
			e.printStackTrace();
		}
	}
}
class Account{
	private double balance;
	
	public Account(double balance) {
		super();
		this.balance = balance;
	}

	public boolean withdraw(double money)throws IllegalArgumentException,RuntimeException{
		if(money < 0){
			//System.out.println("取款金额不能小于0");
			throw new IllegalArgumentException("取款金额" +money + "有问题,取款金额不能小于0");
		}
		if(money > balance){
			throw new RuntimeException("余额不足");
		}
		
		balance -= money;
		return true;
	}
}

7.自定义异常

package com.atguigu.test08;
/*
 * 自定义异常:
 * 	 如果系统预定义的异常类型,
 * 		例如:ArrayIndexOutOfBoundsException
 * 			ClassCastException 类型转换异常
 * 			NullPointerException
 * 			ArithmeticException
 * 			InputMisMatchException
 * 			IllegalAugumentException
 * 			....
 *  发现不能准确的表达你当前的异常类型的意思时,你可以选择自定义。
 * 
 * 面试题:列出常见的异常类型,什么情况下会发生这个异常,你如何处理?至少5个 
 * 
 * 1、自定义的要求:
 * (1)必须继承Throwable或它的子类
 * 但是实际开发中,一般继承RuntimeException和Exception
 * (2)建议大家保留两种构造器的形式
 * ①无参构造
 * ②带给父类的message属性赋值的构造器
 * 
 * 2、如何使用自定义异常
 * 只能使用throw语句进行手动抛出。它不能由JVM自动抛出。
 * 
 * 3、建议
 * 大家在自定义异常时,异常的类型名非常重要,见名知意。
 */
public class TestDefine {
	public static void main(String[] args) {
		Account a = new Account(100);
		
		try {
			a.withdraw(-100);
		} catch (MoneyCannotNegativeException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
	}
}

//例如:想要声明一个异常类型,表示金额不能为负数
class MoneyCannotNegativeException extends Exception{

	public MoneyCannotNegativeException() {
		super();
	}

	public MoneyCannotNegativeException(String message) {
		super(message);
	}
	
}

class Account{
	private double balance;
	
	public Account(double balance) {
		super();
		this.balance = balance;
	}

	public boolean withdraw(double money) throws MoneyCannotNegativeException{ //扔出异常,编译异常
		if(money < 0){
			throw new MoneyCannotNegativeException("取款金额" +money + "有问题,取款金额不能小于0");
		}
		if(money > balance){
			throw new RuntimeException("余额不足");
		}
		
		balance -= money;
		return true;
	}
}

在这里插入图片描述
在这里插入图片描述

package com.atguigu.test09;

public class Account {
	private String id;
	protected double balance;
	private double annualInterestRate;
	public Account(String id, double balance, double annualInterestRate) {
		super();
		this.id = id;
		this.balance = balance;
		this.annualInterestRate = annualInterestRate;
	}
	public Account() {
		super();
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public double getBalance() {
		return balance;
	}
	public void setBalance(double balance) {
		this.balance = balance;
	}
	public double getAnnualInterestRate() {
		return annualInterestRate;
	}
	public void setAnnualInterestRate(double annualInterestRate) {
		this.annualInterestRate = annualInterestRate;
	}
	
	public double getMonthlyInterestRate(){
		return annualInterestRate / 12;
	}
	public double getMonthlyInterest(){
		return balance * getMonthlyInterestRate();
	}
	public void withdraw(double money) throws AccountException{
		if(money < 0){
			throw new AccountException("取款金额有误,不能小于0");
		}
		if(money > balance){
			throw new AccountException("余额不足");
		}
		balance -= money;
	}
	public void deposit(double money) throws AccountException{
		if(money < 0){
			throw new AccountException("存款金额有误,不能小于0");
		}
		balance += money;
	}
}
package com.atguigu.test09;

public class AccountException extends Exception{

	public AccountException() {
		super();
	}

	public AccountException(String message) {
		super(message);
	}

}

在这里插入图片描述

package com.atguigu.test09;

public class TestAccount {
	public static void main(String[] args) {
		Account a = new Account("1122", 20000, 4.5/100);
		
		try {
			a.withdraw(30000);
			System.out.println("取款成功:余额," + a.getBalance());
		} catch (AccountException e) {
			System.out.println("取款失败,原因:" + e.getMessage());
		}
		
		try {
			a.withdraw(2500);
			System.out.println("取款成功:余额," + a.getBalance());
		} catch (AccountException e) {
			System.out.println("取款失败,原因:" + e.getMessage());
		}
		
		try {
			a.deposit(3000);
			System.out.println("存款成功,余额:" + a.getBalance());
			System.out.println("月利率:" + a.getMonthlyInterestRate() * 100 + "%");
			System.out.println("年利息:" + a.getBalance() * a.getAnnualInterestRate());
		} catch (AccountException e) {
			System.out.println("存款失败,原因:" + e.getMessage());
		}
	}
}

在这里插入图片描述
在这里插入图片描述

package com.atguigu.test09;

public class CheckAccount extends Account{
	private double overdraft;

	public CheckAccount(String id, double balance, double annualInterestRate, double overdraft) {
		super(id, balance, annualInterestRate);
		this.overdraft = overdraft;
	}

	public CheckAccount() {
		super();
	}

	public double getOverdraft() {
		return overdraft;
	}

	public void setOverdraft(double overdraft) {
		this.overdraft = overdraft;
	}

	@Override
	public void withdraw(double money) throws AccountException {
		if(money <= balance){
			balance -= money;
		}else if(money > balance + overdraft){
			throw new OutOfOverdraftException("超过可透支额度");
		}else{
			overdraft -= money - balance;//超过余额部分
			balance = 0;
		}
	}
	
}
package com.atguigu.test09;

public class OutOfOverdraftException extends AccountException{

	public OutOfOverdraftException() {
		super();
	}

	public OutOfOverdraftException(String message) {
		super(message);
	}

}
package com.atguigu.test09;

public class TestCheckAccount {

	public static void main(String[] args) {
		CheckAccount c = new CheckAccount("1122", 20000, 4.5/100, 5000);
		
		try {
			c.withdraw(5000);
			System.out.println("取款成功,余额:" + c.getBalance() + ",可透支额度:" + c.getOverdraft());
		} catch (AccountException e) {
			System.out.println("取款失败,原因:" + e.getMessage());
		}
		
		try {
			c.withdraw(18000);
			System.out.println("取款成功,余额:" + c.getBalance() + ",可透支额度:" + c.getOverdraft());
		} catch (AccountException e) {
			System.out.println("取款失败,原因:" + e.getMessage());
		}
		
		try {
			c.withdraw(3000);
			System.out.println("取款成功,余额:" + c.getBalance() + ",可透支额度:" + c.getOverdraft());
		} catch (AccountException e) {
			System.out.println("取款失败,原因:" + e.getMessage());
		}
	}

}

在这里插入图片描述
在这里插入图片描述

©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页