Alt + Insert(Fn + Enter):在idea中点击包,按快捷键,创建类
异常:就是程序出现不正常的情况。程序在执行过程中,出现非正常的情况,最终会导致JVM的非正常停止
注意:语法错误不算在异常体系中
异常体系:
Throwable | Error | 严重问题 例:内存溢出 (无需操作,因为代码解决不了,要解决只能加内存) |
Exception | RuntimeException 运行时异常 例:空指针异常、数组索引越界异常 | |
其他 注意:其他的都是继承自Exception,为编译时异常,必须修改,不然编译不了 |
注意:
继承自RuntimeException为运行时异常
继承自Exception为编译时异常
但RuntimeExceptio又继承自Exception
编译时异常和运行时异常:
javac.exe 编译时异常:是在编译成class文件时必须要处理的异常(也称受检异常)
java.exe 运行时异常(非受检异常)
异常的执行流程:
当代码出现异常,就会改行代码后创建一个异常对象
例:new ArrayIndexOutofBoundsException();
首先会看,程序中有没有自己处理异常的代码
如果没有,交给本方法的调用者处理(例:main方法的调用者为JVM虚拟机)
最终这个异常会交给虚拟机默认处理
虚拟机默认处理异常的方式:
1.讲异常信息以红色字体展示在控制台上(异常信息包含:异常名称、原因、位置等)
2.停止程序运行(哪里出异常就会在哪里停止,且后面的代码都不会执行)
声明异常:throws
不处理异常,直接交给调用者处理,即JVM,作用是说代码可能存在这个问题
格式:throws 异常类名
位置:在方法声明的后面
例:public void mm throws Exception(){ }
注意:
运行时异常可以省略不写
编译时异常必须声明,即必须写
为什么编译时异常必须写呢?
javac.exe 编译时异常:是在编译成class文件时必须要处理的异常(也称受检异常)
抛出异常对象:throw
格式:throw new 异常();
注意:这个格式是在方法内的,表示当前代码手动抛出一个异常对象(意味着可以调用对象的方法),下面的代码不再执行
意义:
1.在方法中,若传递的参数有误,没有再运行下去的必要,则采取抛出处理,表示让该方法结束运行
2.告诉调用者方法中出现了问题
psvm{
int[ ] arr = null;
p( arr );}
public static void p(int[ ] a ){
if (arr == null){
//sout(参数不能为null)-------调用者无法判断是打印成功还是报错
throw new NullpointException();-----if参数为null时,手动创建异常,并抛给调用者jvm
}else{
a.fori { sout( a[i] ) } }
若改成
try{
p(arr)
}catch(NullpointException e ){
sout(参数不能为null);
}
sout(xxx);---------------使用了trycatch后面的代码能正常运行
trycatch:
常见问题:
1.如果try中没有遇到问题,怎么执行?
try内和try外执行,catch不执行
2.如果try中遇到问题,try下面的代码还会执行吗?
try内,出现问题的语句后的代码都不执行,catch和try外都执行
3.如果出现的问题没有被捕获,那么程序如何运行?
默认交给调用者,即jvm
4.同时出现多个异常怎么处理?
try{
String line = sc.nextline();
int age = Integer. parseInt(line); ①
sout(age);
sout(2/0); ②
}catch(NumberFormatException e ){
sout(格式异常)}
sout(xxx)
情况一:
当①出现问题,会被catch到,try内①后的代码不执行,try外是正常执行
情况二:
当①正确,②出了问题,但未catch到,默认交给调用者处理,即jvm,且try外不执行。
情况二--优化方式:再加多一个catch
}catch(NumberFormatException e ){
sout(格式异常)
}catch(ArithmeticException e ){
sout(数学异常)
}
注意:多个catch中有子父类关系,父类必须放在最后,否则全部都被父类接收了
为什么不统一全部用Exception去catch?
以后使用会正对不同的异常,有不同的处理
Throwable的成员方法:
最大的异常,是Exception和Error的父类(意味着方法子类都可以使用)
public String getMessage() | 返回比throwable的详细消息字符串(错误原因) |
public String toString() | 返回此可抛出的简短描述(异常名+错误原因) |
public void printStackTrace() | 把异常的错误信息输出在控制台(字体为红色)(常用) |
注意:public void printStackTrace()
错误信息:异常名+错误原因+位置
虽然效果和报错一样,但是try后的代码仍然可以运行
try{ int[ ] a = {1,2,3}
sout(a[10]);//底层会自动创建 new ArrayIndexOutofBoundsException();然后赋值给e
}catch(ArrayIndexOutofBoundsException e ){
e.printStackTrace();----------再调用e的方法
}
sout(xxx)----------正常执行
domain----Student
方法中
例:setAge(int age){
if(10<age<18){
this.age = age;
}else{
throw new Exception("年龄超范围了");----此处有个疑问:为什么不能直接输出sout,throw的优势再哪里呢?
因为sout可能会被使用到,就比如返回值是int 你返回个-1可能会被使用,也就是所说的 调用者无法判断是否出错 而报异常无需返回值,直接就可以抛异常处理
}}
测试类中:
while(true){
String a = sc.next();
try{
int age = Integer.parseInt(a);
s.setAge(age);-----只要出现问题,break就执行不到
break;
}catch(NumberFormatException e ){
sout(请输入整数)
continue;
}catch(Exception e){
sout(年龄超范围了)
continue;
}
sout(xxx)
}
自定义异常
目的:为了让异常信息更加见明知意
格式:
类名 extends RuntimeException(常用) / Exception(){
serialCersionUID----后面会讲
空参构造
有参构造(String s)
}
例如:
例:setAge(int age){
if(10<age<18){
this.age = age;
}else{
throw new Exception("年龄超范围了");}
此处的 Exception是一个大类,且容易导致catch到try里的其他同类型的错误
另外,当new Exception("年龄超范围了");
再try catch(Exception e){
sout(e.toString) = 异常名+年龄超范围了
}