异常,即不正常,我们的代码出现的编译或者运行时的错误。本文,将带你了解Java的异常机制的基础语法,为以后的学习和开发打好基础。
异常体系结构
Throwable 类是 Java 语言中所有错误或异常的超类。其下主要分为两种类型:Error、Exception。
辨析错误(Error)和异常(Exception):
Error:程序在运行期间发生了某种错误(XxxError)
,Error错误通常没有具体的处理方式,程序将会结束运行。Error错误的发生往往都是系统级别的问题,都是jvm所在系统发生的,并反馈给jvm的。我们无法针对处理,只能修正代码。
Exception:指程序在编译、运行期间发生了某种异常(XxxException)
,我们可以对异常进行具体的处理。若不处理异常,程序将会结束运行。所有的异常类是从 java.lang.Exception 类继承的子类。其有两个主要的子类:IOException 类和 RuntimeException 类。
类比理解:
用代码理解Error和Exception:
// 异常的产生演示如下:
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr[0]);
System.out.println(arr[3]);
// 该句运行时发生了数组索引越界异常ArrayIndexOutOfBoundsException,由于没有处理异常,导致程序无法继续执行,程序结束。
System.out.println("over"); // 由于上面代码发生了异常,此句代码不会执行
}
// 错误的产生演示如下:
public static void main(String[] args) {
int[] arr = new int[1024*1024*100];
//该句运行时发生了内存溢出错误OutOfMemoryError,开辟了过大的数组空间,导致JVM在分配数组空间时超出了JVM内存空间,直接发生错误。
}
throwable类
方法:
String getMessage()
对异常信息的详细描述String toString()
对异常信息的简短描述void printStackTrace()
将异常信息追踪到标准的错误流
使用示例:
public class ExceptionDemo4 {
public static void main(String[] args) {
method();
}
private static void method() {
try {
System.out.println(2 / 0);
} catch(ArithmeticException e) {
//String getMessage() : 异常原因
System.out.println(e.getMessage());
//String toString(): 异常类型和原因
System.out.println(e.toString());
//void printStackTrace(): 异常类型原因和位置
e.printStackTrace();
}
}
}
编译时期异常
定义:
- 编译期间就检查异常是否发生,如果有异常,则编译不通过;
体系结构:
快速理解编译时异常
public class Main {
public static void main(String[] args) throws Exception { //本方法也没有处理异常,只能继续向外抛
function(); //调用该方法,就要处理该方法的异常
}
public static void function() throws Exception { //本方法没有(或没有能力)处理异常
throw new Exception(); //产生、制造异常
}
}
特性:
程序语法正确,但因为外在的环境条件不满足引发。例如:用户错误及I/O问题,程序试图打开一个并不存在的远程Socket端口。这不是程序本身的逻辑错误,而很可能是远程机器名字错误(用户拼写错误)。对商用软件系统,程序开发者必须考虑并处理这个问题。Java编译器强制要求处理这类异常,如果不捕获这类异常,程序将不能被编译。
常见编译时异常:
SQLException
IOexception
FileNotFoundException
ClassNotFoundException
EOFException
IllegaArguementException
运行时期异常
定义:
- 运行时期才检查程序是否有异常,有异常则程序终止。
快速理解运行时异常
public class Main {
public static void main(String[] args) {
function();
}
public static void function() {
throw new RuntimeException(); //产生、制造异常,运行时异常不用向外抛
}
}
体系结构:
特性:
- 是哪些可能在Java虚拟机正常运行期间抛出的异常的超类。
- 方法内部抛出的异常时运行异常(throw new XxxException),那么在方法的申明上,不需要throws语句。这样设计的原因可能是:运行时异常一般是不会发生的,如果发生了,需要程序员停止程序并修改源代码。
- 这意味着程序存在bug,如数组越界,0被除,入参不满足规范…这类异常需要更改程序来避免,Java编译器强制要求处理这类异常。
常见运行时异常:
StringIndexOutOfBoundsException、
ArrayIndexOutOfBoundsException、
ArithmeticException、
IllegaArguementException、
NullPointException
异常的处理
在开发中,建议使用“try…catch….finallay”,自己检测和捕获异常;而不建议使用“throw、throws”向外抛出异常。
异常的捕获和处理
异常的捕获和处理的三种方式
1、try……catch……
try{
可能出现异常的代码块;
}catch(异常类型){
处理异常的代码块;
}
2、多个catch……
try{
可能出现异常的代码块;
}catch(异常类型){
处理异常的代码块;
}catch(异常类型){
处理异常的代码块;
}
多个catch的顺序:平级之间没有顺序关系,如果有子父类,父类异常必须放在后面
3、try……catch……finally……
try{
可能出现异常的代码块;
}catch(异常类型){
处理异常的代码块;
}catch(异常类型){
处理异常的代码块;
}finally{
代码块: 不管你try代码块里面的内容是否有异常,我finally代码中的内容都会被执行。往往用做释放资源的事情
}
try-catch
法则:
try 代码后不能既没 catch 块也没 finally 块。
初次尝试
public class Main {
// 快速理解try-catch
private static void method() {
try {
String s = null;
System.out.println(s.length());
} catch (NullPointerException e) {
System.out.println("出现空指针了");
}
try {
int[] arr = new int[5];
System.out.println(arr[8]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("出现数组越界了");
}
}
// 优化以上的异常处理
public static void method02() {
try {
String s = null;
System.out.println(s.length());
} catch (ArrayIndexOutOfBoundsException e) { //具体的异常
System.out.println("出现数组越界了");
} catch (NullPointerException e) {
System.out.println("出现空指针了");
} catch (Exception e) { //Exception可以接收任何类型的异常
System.out.println("出现异常了");
}
}
public static void main(String[] args) {
method();
// method02();
}
}
try-catch-finally
快速理解使用方式
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
method();
}
public static void method() {
FileWriter fw = null;
try {
System.out.println(2 / 0); //try中一旦发生异常,其后的代码将不会再执行,直接跳转到catch语句开始执行;
fw = new FileWriter("a.txt");
fw.write("hello");
fw.write("world");
//System.out.println(2 / 0);
fw.write("java");
//fw.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放资源
try {
if(fw != null) {
fw.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
异常的抛出
当我们不想处理异常,或者没有能力处理的时候,我们可以选择抛出异常,谁调用方法谁处理异常。
throw 与throws两个关键字:
- throw关键字是用于方法内部的,throws是用于方法声明上的。
- throw关键字是用于方法内部抛出一个异常对象的,throws关键字是用于在方法声明上声明抛出异常类型的。
- throw关键字后面只能有一个异常对象,throws后面一次可以声明抛出多种类型的异常。
throw和throws在功能上的区别:
- throws:处理异常的方式,是在本方法不能够处理才向外抛,由调用者处理该异常;
- throw:制造异常的方式,是开发者注意到某句代码可能发生异常,而主动向外抛的异常方式。throw后面必须是“new 一个异常类”,这个异常类必须是Exception或者其子类。
- 注意:如果抛出(throw)的是编译时期异常,必须在方法声明处抛出(throws);
快速理解throw和throws
public class Main {
public static void main(String[] args) {
int[] arr = null;
int i = getArray(arr);
System.out.println(i);
}
public static int getArray(int[] arr) {
int i = arr[arr.length-1]; //发生异常语句
return i*2;
}
}
/* 发生异常:
Exception in thread "main" java.lang.NullPointerException
at Main.getArray(Main.java:12)
at Main.main(Main.java:8)
*/
public class Main {
public static void main(String[] args) throws Exception { //抛出异常,main方法抛出的异常由JVM处理
int[] arr = null;
int i = getArray(arr);
System.out.println(i);
}
public static int getArray(int[] arr) throws Exception { //抛出异常
if(arr == null) {
throw new Exception("数组不存在,为null"); //抛出异常
}
int i = arr[arr.length-1]; //发生异常语句
return i*2;
}
}
/*运行结果:
Exception in thread "main" java.lang.Exception: 数组不存在,为null
at Main.getArray(Main.java:10)
at Main.main(Main.java:5)
*/
自定义异常类
写一个类去继承Exception或者RuntimeException,然后实现多个构造即可;
快速理解自定义异常的使用
/* 用自定义异常类实现
* 写一个方法,接受考试成绩,如果考试成绩在0-100之间则属于正常,否则属于异常
*/
public class Main {
public static void main(String[] args) {
try {
checkScore(110);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void checkScore(int score) throws Exception {
if(score < 0 || score > 100) {
throw new MyException("考试成绩不符合要求"); //
}
System.out.println("考试成绩符合要求");
}
}
//如果继承Exception就是编译时异常,如果继承RuntimeException就是运行时异常;
class MyException extends /*RuntimeException*/ Exception{
//使用工具直接生成:"source","Generatre xxXx"
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}