Throwable类是Java语言中所有错误和异常的超类。
Error类 :表示的是错误
错误就相当于程序得了一种不治之症,一旦程序发生Error,我们只能修改自己的代码
Exception:编译期异常
顾名思义,就是在我们写代码期间所报的异常,在开发集成工具中代码就会变红,编译不通过
RuntimeException:运行时异常
可以通过编译,但运行期间会发生的异常,一旦发生这种异常,JVM中断程序的运行
发生异常JVM会做两件事情:
1,会根据异常产生的原因而创建一个异常对象,这个异常对象包含了异常产生的信息(内容,原因,位置)
2,没有进行异常处理 try-catch,那么JVM就会把异常抛出给方法的调用者
throw 关键字
-
作用:可以使用throw关键字在指定的方法抛出指定的异常
-
注意:1,throw关键字必须写在方法的内部
-
2,throw关键字后边new的对象,必须Exception或者是Exception的子类对象
-
3,throw关键字抛出指定的异常对象,就必须处理这个异常对象
throw关键字后边创建的是RuntimeException或者它的子类对象,我们可以不处理,默认交给JVM处理(打印异常对象,中断程序)
throw关键字后边创建的是编译异常(写代码期间)我们必须这个异常,要么throws抛出给调用者,要么try-catch
eg:
public class demo {
public static void main(String[] args) {
int[] arr={12,34,1};
int index=3;
//因为NullPointerException,ArrayIndexOutOfBoundsException都是运行时的异常,所以我们可以不处理
//如果是编译时异常,不处理编译不会通过
mother(arr,index);
}
/**
* 以后(工作中)我们首先必须对方法传递过来的参数进行合法必校验
* 如果 参数不合法,那么我们就必须使用抛出异常的方式,告知方法的调用者,传递的参数有问题
* @param arr
* @param index
*/
private static void mother(int[] arr, int index) {
if(arr==null){
throw new NullPointerException("传递过来的数组是空的");
}
if(arr.length<=index){
throw new ArrayIndexOutOfBoundsException("传递过来的数组索引大于等于长度了");
}
}
}
throws关键字:
-
异常处理的第一种方式,交给别人处理
作用: -
当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象
-
可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理,最终交给JVM处理–》中断处理
-
使用格式:在方法声明时使用
-
修饰符 返回值类型 方法名(参数列表) throws AAException,BBException…{
-
throw new AAException(“产生的原因”);
-
throw new BBException(""产生的原因);
-
}
-
注意:
-
1,throws关键字必须写在方法声明处
-
2,throws关键字后边声明的异常必须是Excetion或者是Exception的子类
-
3,throws方法内部如果抛出了多个异常,那么throws后边必须也声明多个异常
-
如果抛出的多个异常对象有子类关系,抛出父类异常即可
-
4,调用了一个声明抛出异常的方法,我们就必须要处理声明的异常
-
要么继续使用throws声明抛出异常,交给方法调用者处理,最终交给JVM处理
-
要么try-catch自己处理
eg:
public class demo01 {
public static void main(String[] args) throws IOException {
String path = "c:\\a.twt";
getFilePath(path);
}
private static void getFilePath(String path) throws IOException {
//判断字符串是否以“.txt”结尾的
if (!path.endsWith(".txt")) {
throw new IOException("文件名有误");
}
if (!path.equals("c:\\a.txt")) {
throw new FileNotFoundException("找不到文件异常");
}
}
}
try…catch:异常处理的第二种方式,自己处理异常
格式:try{
可能产生异常的代码
}catch{
异常的处理逻辑,异常对象之后 怎么处理异常对象
一般在工作中,会把异常的信息记录到一个日志中
}
注意:
1,try中可能会抛出多个异常对象,那么就可以使用多个Catch来处理这些异常对象
2,如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try…catch之后的代码
如果try中没有异常,那么就不会执行Catch中异常的处理逻辑,执行完try中的代码,继续执行try…catch之后的代码
public class Demo02 {
public static void main(String[] args) {
String path="c:\\a.tx";
try {
getFilePath(path);
}catch (IOException e){
/*
public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误的原因)
public String toString(); 获取异常的类型和异常描述信息(不用)
public void printStackTrace():打印异常的跟踪栈信息并输出到控制台。
*/
//e.printStackTrace();
System.out.println(e.toString());
System.out.println(e.getMessage());
System.out.println("发生了异常");
}finally {
//无论是否有异常产生,最终都会执行的代码
//一般都是关闭资源的操作
System.out.println("最终要执行的代码!");
}
System.out.println("木木木木木");
}
private static void getFilePath(String path) throws IOException {
if (!path.endsWith(".txt")){
throw new IOException("找不到文件,可能文件后缀有误!");
}
}
}
自定义异常:使用帮忙文档我们可以看到无论是Exception类还是RuntiemException类都有大量的子类,我们可以模仿它们的子类定义我们自己想要异常类
eg:
package cn.ping;
/**
* 自定义异常
* 必须要通过继承Exception或其子类来自定义异常类
*/
public class RegisterException extends Exception {
public RegisterException(){
super();
}
public RegisterException(String massage){
super(massage);
}
}
package cn.ping;
import java.util.Scanner;
/**
* 测试自定义异常
*/
public class demo04 {
public static void main(String[] args) {
String[] name = {"张三", "李四", "王五", "田七"};
Scanner sc = new Scanner(System.in);
System.out.println("请输入你要注册的狗名:");
String userName = sc.next();
try {
mother(name, userName);
} catch (RegisterException re) {
System.out.println(re.toString());
}
}
private static void mother(String[] name, String userName) throws RegisterException {
for (String s : name) {
if (s.equals(userName)) {
throw new RegisterException("你注册的用户名已经存在了");
}
}
System.out.println("注册成功");
}
}
异常的注意事项及其在父类子类之间的关系:
******注意事项:
- 运行时异常被抛出可以不处理,即不捕获也不声明抛出
- 如果fianlly有return语句,永远返回finally中的结果,避免这种情况
- 如果父类抛出多个异常,子类重写父类方法时抛出和父类相同的异常或者是父类异常的子类或者不抛出异常
- 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不声明抛出
- 在try/catch后可以追加finally代码块中,其中的代码一定会被执行,通常用于资源回收
publi**c class demo03 {
public static void main(String[] args) {
System.out.println(getNumA());
}
/**
* 如果finally有return语句,永远返回finally中的结果,避免这种情况
* @return
*/
private static int getNumA() {
int a=10;
try{
return a;
}catch(Exception e){
return a;
}finally {
a=100;
return a;
}
}
}
/** 如果父类抛出多个异常,子类重写父类方法时抛出和父类相同的异常或者是父类异常的子类或者不抛出异常
* 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不声明抛出*/
class Fu{
public void mother1() throws NullPointerException{}
public void mother2() throws Exception{};
public void mother3() throws IndexOutOfBoundsException{}
public void mother4(){}
}
class Zi extends Fu{
//子类重写父类方法时抛出和父类相同的异常或者是父类异常的子类或者不抛出异常
public void mother1(){};
public void mother2() throws FileNotFoundException{}
public void mother() throws IndexOutOfBoundsException{}
//父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不声明抛出
// public void mother4 throws Exception{}; 报错
public void mother4(){
}
}
扩展:因为多态的原因,在某个方法参数是父类,但父类的对象只是引用的子类的对象的例:Object obj=new String();这个时候在方法中使用到父类被子类重写后的方法,假如子类抛出的异常类型可以大于父类抛出的异常类型,那么如果这个时候某个方法中catch(子类异常类型>异常类型>父类异常类型) ,则会报错