异常
笔记总结参考于黑马程序员 Java基础进阶篇(异常)
父类:Throwable
类
子类:Error
类
Error
类描述的是在运行过程中非常严重且不可以处理的错误。
如:常见的两种严重错误
//例1
public class Test {
public static void main(String[] args) {
while (true){
arrayList.add("abc");
}
}
}
/*报错信息:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 即内存溢出的严重错误*/
//例2
public class Test {
public static void main(String[] args) {
show();
}
public static void show(){
show();
}
}
/*报错信息:Exception in thread "main" java.lang.StackOverflowError 栈内存溢出的严重错误*/
子类:Exception
类
Exception
类描述出现一些简单的且可以处理的错误。且分为两类:编译期异常和运行期异常
图示
编译期异常(语法错误不算在内)
Exception
的儿子(非RuntimeException
):书写代码还没运行的时候就开始报错,如果这种异常存在时无法生成class
文件的
看代码中两个例子:
public class Test {
public static void main(String[] args) {
String time = "1991-01-02";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date prase = simpleDateFormat.parse(time); //这里有编译错误,但Typora没显示
System.out.println(prase);
}
}
//抛出异常 throws ParseException
public class Test throws ParseException {
public static void main(String[] args) {
String time = "1991-01-02";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date prase = simpleDateFormat.parse(time); //这就没问题了
System.out.println(prase);
}
}
/*同理,IO流也是有编译期异常的*/
FileInputStream fis = new FileInputStream("abc.txt");//FileNotFoundException
运行期异常
RuntimeException
以及他的儿子:书写代码的过程中,是不会报错的,可以编译出class
文件,可以运行,但是运行的时候报错
看代码中两个例子:
// 例1
public class Test {
public static void main(String[] args) throws ParseException {
String s = null;
// null 怎么可以掉对象呢 但是不报错 运行的时候才报错
boolean equals = s.equals("");
System.out.println(equals);
}
}
/*报错信息:Exception in thread "main" java.lang.NullPointerException 空指针异常*/
// 例2
public class Test {
public static void main(String[] args) throws ParseException {
int[] arr = {1,2,3};
System.out.println(arr[100]);
}
}
/*报错信息:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100 数组索引越界异常*/
为什么要分开编译期和运行期异常呢
编译期异常的设计理念:在程序员写代码的时候,有一些地方容易出错,且程序员都经常不注意,所以Java设计编译期异常,引起程序员注意。
throws
处理方式:Java程序员了解到这个地方容易出错,就检查了一遍,请求jvm
让代码编译通过。
public class Test throws ParseException {
public static void main(String[] args) {
String time = "1991-01-02";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date prase = simpleDateFormat.parse(time);
System.out.println(prase);
}
}
try-catch
处理方式:throws
只起到一个“提示虚拟机”的作用,如果没检查好,以后运行的时候依然会报错。
举例某个场景:我们在编译期的时候检查不出来,后续是否报错的。因为有可能以后的程序员运行起来,用户输入一些错误。
public class Test{
public static void main(String[] args) {
Scanner sc = new Scanner();
String pattern = sc.next();
String str = "2018-09-23";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
try{
Data d = sdf.parse(str);
}catch(Exception e){
System.out.println("请输入正确的格式");
}
}
}
运行期异常的设计理念:这些是给用于去准备的,比如1/0操作,,当出现问题的时候,不至于程序崩溃,而是可以继续执行问题代码以下的程序;
只用try-catch
处理方式,不用throws
方式,因为没效果;
int i = 1/0;
System.out.println(i);//会报错
java
是如何默认处理异常的
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
at 刘东生.practice.Test.main(Test.java:12)
//异常的类型:ArrayIndexOutOfBoundsException 一般通过异常类型可以知道那里犯错
//异常的原因 100
// 异常出现的位置:Test.java:12
// 报错之后 程序立刻终止
既然我们知道程序出现异常会中止程序,那如果程序中一段代码出现异常,但是我仍想执行下面代码的内容,如果执行,这就需要try-catch
去处理异常了
try-catch
处理异常
格式
try{
//可能出现问题的代码
}catch(Exception e){
//处理异常
}
比如 处理上面那段索引越界的代码
注意:catch(//这里头写的代码可以是父类Exception)
,但是括号里头不能写其他类的比如NullPointerException e
异常,否则捕捉不到(所以为了避免捕捉不到异常,直接写Exception
即可); 同时注意e.printStackTrace();
这段代码,这样写可以知道异常报错的信息;如果第一个异常被捕捉到了,接下来的异常如例子中下面的空指针异常是不会被捕捉的。
public class Test {
public static void main(String[] args) throws ParseException {
try {
int[] arr = {1,2,3};
System.out.println(arr[100]);
String s = null;
boolean equals = s.equals("");
System.out.println(equals);
} catch (ArrayIndexOutOfBoundsException e) { //相当于 new ArrayIndexOutOfBoundsException();
e.printStackTrace(); // 一般都这样写,这样写的话可以知道异常报错的信息
}
System.out.println(10000);
System.out.println(10000);
System.out.println(10000);
}
}
/*输出内容:java.lang.ArrayIndexOutOfBoundsException: 100
at 刘东生.practice.Test.main(Test.java:13)
10000
10000
10000 */
假如我想获取导致异常的原因是啥如何做呢?这里就用到了e.getMessage()
方法
public class Test {
public static void main(String[] args) throws ParseException {
try {
int[] arr = {1,2,3};
System.out.println(arr[100]);
} catch (ArrayIndexOutOfBoundsException e) {
String message = e.getMessage();
System.out.println(message);
}
System.out.println(10000);
System.out.println(10000);
System.out.println(10000);
}
}
/*输出内容:100
10000
10000
10000 */
源码分析
public Throwable{
public Throwable(String message) {
detailMessage = message; //这里赋值
}
public String getMessage() {
return detailMessage;
}
}
//构造 new ArrayIndexOutOfBoundsException()对象出来
// e.getMessage(); --> "100"
Class ArrayIndexOutOfBoundsException extends Throwable{
public ArrayIndexOutOfBoundsException(String s){
super(s);
}
}
自定义一个异常场景
比如:程序中不允许出现年龄为负数,如果年龄为负数,就需要报错一个异常。
底层代码:
public class Students {
private int age;
public Students(){}
public void setAge(int age) {
if(age<0){
throw new AgeOutOfBoundsException(age+"");
}
this.age = age;
}
}
//自定义异常
public class AgeOutOfBoundsException extends RuntimeException{
public AgeOutOfBoundsException(){}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
程序员写逻辑时候的代码:
public class test {
public static void main(String[] args) {
Students students = new Students();
students.setAge(-10);
}
}
//运行结果显示
/*Exception in thread "main" Test.AgeOutOfBoundsException: -10
at Test.Students.setAge(Students.java:8)
at Test.test.main(test.java:6)*/
这里再文字解释以下 -10 如何得到的。首先-10 先回传到setAge
方法中,然后经过这个 if(age<0){throw new AgeOutOfBoundsException(age+"");}
判断方法 ,将 -10 转换为字符串 “-10” 传给AgeOutOfBoundsException()
方法,AgeOutOfBoundsException()
方法通过有参构造方法中的super(message)
经过父类RuntimeException
,一直传到最后的Throwable()
方法,这个最终父类方法有两个 Throwable(String message)
和 getMessage()
(上面源码分析可以知道),将导致异常的信息返回。