黑马程序员技术交流社区

标题: 【石家庄分校】“异常”小结 [打印本页]

作者: 冰中晓晓    时间: 2018-8-1 10:06
标题: 【石家庄分校】“异常”小结
本帖最后由 冰中晓晓 于 2018-8-1 10:15 编辑

异常

异常概念:指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
       在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处
       理异常的方式是中断处理
        异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行
异常体系:异常的根类是 java.lang.Throwable ,其下有两个子类:
java.lang.Error与 java.lang.Exception ,平常所说的异常指 java.lang.Exception
Throwable体系://体系最顶层
|___|__Error:(错误)严重错误//严重问题,不能处理的错误
|_____Exception:异常表示异常//可以处理异常
   |         ,( 编译时期异常) 在编译时期,就会检查,如果没有处理异常,则编译失败
   |
   |_____:RuntimeExeption异常, (运行时期异常)在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)
异常的分类:
// 异常的体系结构
java.lang.Throwable        // 体系最顶层
   |_ Error                      // 错误
   |_ Exception               // 编译时异常
          |_ RuntimeException// 运行时异常
错误(Error):不能捕获处理的严重问题. 绝症
     必须将程序停下来, 修改代码才能解决
     错误的类名都是 "XxxError" 方式
异常(Exception):可以捕获处理的问题. 发烧感冒吃个药就好了
     程序执行起来后, 如果有合适的处理方式, 即使发生异常, 程序也能处理该异常并继续运行
     异常的类名都是 "XxxException" 方式
1. 编译时异常:
      编译时期就会发生的异常, 必须在编译时期处理
2. 运行时异常:
      编译时正常, 运行时才会发生的异常
异常产生的过程:
     1. 当执行的代码发生异常操作时, JVM会创建一个对应的异常类对象, 包含异常的内容, 原因, 位置
                 如 new ArrayIndexOutOfBoundsException(), new NullPointerException()
      2. 如果执行代码的方法没有对异常进行 try...catch 处理, 则会向该方法调用处的方法抛(向上层抛). 如果所
               有方法(包括main()方法)都没有 try...catch 处理异常, 则该异常会被JVM按照默认的处理方式处理
      3. JVM对于异常的默认处理方式是:
                 1. 将异常信息(内容, 原因, 位置)打印到控制台
                 2. 终止当前的程序
异常关键字: throw制造异常
throw关键字作用:
        在方法中抛出指定的异常对象
格式:
        throw new 异常类名("异常原因字符串");
         // 示例:
         throw newNullPointerException("传递的参数为空");
         throw newArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
注意:
      1. throw 必须写在方法的内部
      2. throw 后面new的异常对象, 必须是 Exception 或 Excetion的子类 的对象
      3. 一个方法内部 throw 了一个异常对象, 则该方法可以分为2种情况来处理该异常:
               如果 throw 的是"运行时异常"(RuntimeException及其子类)对象, 那么可以不处理, 交给JVM处理
               如果 throw 的是"编译时异常"(Exception及其子类), 则必须处理:
                      处理方式1: throws 抛出
                      处理方式2: try...catch 捕获
异常的处理方式1: throws声明抛出异常
     异常处理的第一种方式:
      throws, 声明抛出 (方法自己不处理, 交给方法调用者处理)
      作用: 告诉方法的调用者, 调用此方法有可能发生异常, 需要在编写代码时处理
格式:
[Java] 纯文本查看 复制代码
      修饰符 返回值类型 方法名() throws 异常类名1, 异常类名2, ... {
          }
                        // 示例
                    public static void read(String filename) throws FileNotFoundException {
                             if (!"a.txt".equals(filename)) {
                                       throw new FileNotFoundException("路径不对");
                    }
             }
注意:
       1. throws 必须写在方法声明上
       2. throws 后面的异常类名, 一般是 Exception 或 Exception的子类
           (RuntimeException及其子类也行, 但是没有什么意义)
        3. 方法内部如果抛出了多个异常对象, throws 后也必须声明多个异常
如果抛出的异常对象有子父类关系, 那么直接声明父类异常即可
4. 调用了一个带有 throws 声明抛出异常的方法, 就必须处理该异常:
     要么继续声明 throws 抛出
     要么 try...catch 捕获处理异常

异常处理方式2: 捕获异常
try...catch:
     捕获并处理异常 (方法内部自己处理异常, 不交给别人)
  
  
  
格式:
  

代码:
try{
// 可能产生异常的代码
    } catch (异常类名 变量名) {
// 处理异常的代码
// 一般会将异常信息存储到日志中
   }
...
} catch (异常类名变量名) {
// 处理异常的代码
// 一般会将异常信息存储到日志中
     }
[Java] 纯文本查看 复制代码
public class Test {
public static void main(String[] args) {
try {
readFile("dsf");
} catch (IOException e) {
Throwable中的3个异常处理方法
知识点:
总结:
补充:
5分钟练习: 测试Throwable的方法
// 捕获到异常, 输出友好的信息
System.out.println("文件路径错误");
// System.out.println("您的输入有误");
}
// 程序依然可以继续运行
System.out.println("程序依然可以继续运行");
}
public static void readFile(String filename) throws IOException {
// 判断路径
if (!"c:\\a.txt".equals(filename)) {
// 路径不对
throw new IOException("文件路径错误");
}
System.out.println("路径正确");
}
}

注意:
1. try 中可能会抛出多种异常, 就可以写多个 catch 分别处理每种异常
2. 如果 try 中产生了异常, 就会从产生异常的那一行代码直接跳转到对应的 catch 中执行处理代码, 然后继续
执行try...catch 之后的其他代码; 如果 try 中没有产生异常, 那就不会执行 catch , 执行完 try 中的代码后,
继续执行try...catch 之后的其他代码
补充:
      // JDK 7增加
try{
// 可能发生异常的代码
  } catch (异常类型1 | 异常类型2 | 异常类型3 | ... 异常对象名) {
// 处理任意一个异常的代码
    }
try{
// 可能发生异常的代码
    } catch (NullPointerException |ArrayIndexOutOfBoundsException e) {
// 处理任意一个异常的代码
    }
Throwable中的3个异常处理方法
java.lang.Throwable
// 成员方法
String getMessage(): 异常的信息. 没有原因返回null
String toString(): 异常的类型和原因信息
void printStackTrace(): 使用标准错误输出流打印异常信息
代码示例:
[Java] 纯文本查看 复制代码
                                public class Test {
                                        public static void main(String[] args) {
                                                // 调用方法, 使用try catch捕获
                                                try {
                                                        readFile("sdf");
                                                } catch (IOException e) {
                                                        // getMessage(): 获取异常的简短原因信息
                                                        System.out.println(e.getMessage()); // 文件路径错误
                                                        // toString(): 获取异常的类名:原因
                                                        System.out.println(e.toString()); // java.io.IOException: 文件路径错误
                                                        // printStackTrace(): 将异常的完整信息打印到控制台, 该方法不会终止程序
                                                        e.printStackTrace(); // 红色文字
                                                }
                                        System.out.println("程序仍然可以继续运行");
                                }
                                public static void readFile(String filename) throws IOException {
                                        if (!"c:\\a.txt".equals(filename)) {
                                                throw new IOException("文件路径错误");
                                        }
                                        System.out.println("文件路径正确");
                                }
                        }
finally代码块
格式:
try{
// 可能发生异常的代码
} catch(异常类型异常变量名) {
// 处理异常
}finally {
// 无论是否发生异常, 是否捕获, 最后都会执行的代码.
/// 通常在这里执行释放资源的操作
  }
注意:
1. finally 必须和 try...catch 一起使用
2. finally 一般用于释放资源 (IO流时用到)

[size=14.6667px]补充:
[Java] 纯文本查看 复制代码
// IO流操作时经常会这么写
FileReader fr = null;
try {
fr = new FileReader("d:\\a.txt");
int ch = fr.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close(); // 释放资源
} catch (IOException e) {
e.printStackTrace();
}
}
}

异常注意事项1: 捕获多个异常的3种方式
捕获多个异常:
1. 多个异常分别 try...catch 处理
// 1. 多个异常分别try...catch处理
try{
// 可能发生异常的代码
} catch (异常类型变量名) {
// 处理异常
   }
try{
// 可能发生异常的代码
} catch (异常类型变量名) {
// 处理异常
     }

2. 一个 try 多个 catch
      // 2. 一个try多个catch
try{
// 可能发生异常的代码
}catch (异常类型1 变量名){ // 子类异常在上
// 处理异常1
}catch (异常类型2 变量名){ // 父类异常在下
// 处理异常2
   }

如果异常存在继承关系, 子类异常在上, 父类异常在下
3. 多个异常, 一次捕获一次处理
用Exception多态捕获
//3.
try{
// 可能发生异常的代码
// 可能发生异常的代码
// 可能发生异常的代码
// 可能发生异常的代码
// 可能发生异常的代码
}catch (Exception e){ // 父类异常多态接收
// 处理异常
    }
运行时异常, 可以不抛出 throws 也不捕获 try catch, 交给JVM处理

异常注意事项2: finally中有return语句
如果finally 代码块中有 return 语句, 则永远返回 finally 中的 return 语句的值
   应该避免在 finally 中写 return 语句
[Java] 纯文本查看 复制代码
try {
return a;
} catch() {
return a;
} finally {
a += 10;
return a;
}
异常注意事项3: 子父类继承重写方法时的异常要求
子父类继承关系下, 子类重写父类带有throws的方法
  
  
  
  
1. 如果父类抛出多个异常, 子类重写父类方法时可以有3种方式:
a: 抛出和父类相同的异常
b: 抛出父类异常的子类
c: 不抛出异常
2. 父类方法没有抛出异常, 子类重写父类该方法时也不可抛出异常
此时子类产生该异常, 只能捕获处理, 不能声明抛出
注意:
父类异常时什么样,子类异常就什么样


自定义异常类:
如果Java提供的异常类不足以满足我们的需求, 我们也可以自己定义异常类
定义编译时异常: 继承 Exception
定义运行时异常: 继承 RuntimeException

[Java] 纯文本查看 复制代码
为了在抛出异常时, 显示一些提示信息, 我们可以定义2个构造, 一个无参, 一个有String参数
// 自定义编译时异常
public class RegisterException extends Exception {
public RegisterException() {
super();
}
public RegisterException(String message) {
super(message);
}
}
// 自定义运行时异常
public class RegisterException extends RuntimeException {
public RegisterException() {
super();
}
public RegisterException(String message) {
super(message);
}
}








欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2