异常解析
为什么需要学习异常?
- 1.观察程序的错误
- 2.能够让错误指示程序修改
异常的概述:
异常是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序。简单来说就是程序出现了不正常的情况。
异常本质就是Java当中对可能出现的问题进行描述的一种对象体现
异常的分类:
异常(Exception)的分类
凡是Exception或者是Exception的子类都成为编译时异常,这种是可以解决的,一般编译不通过
凡是RuntimeException或者是RuntimeException的子类都成为运行时异常,这种也是可以解决的,一般都是代码不够严谨或者逻辑错误
异常框架体系结构图
常见异常分类
Throwable类讲解
-
提取保存在堆栈中的错误信息
-
如何查找错误根源:从下往上依次看,先看你能够看懂的,再看别人写的或者是源码的
为什么需要处理异常?
目的:在程序出现问题后,还能够让程序继续执行
JVM(虚拟机)处理异常的方式:
- 1.打印错误信息
a.异常的类名
b.异常信息
c.异常的位置
d.错误的行号 - 2.将程序停止
异常处理的标准格式:
-
1.能够显示声明的异常尽量显示声明,提高程序的可读性
-
2.在最后都必须加上 Exception 作为父类异常,防止程序异常停止,提高程序的安全性
自己处理异常
try…catch
1.try…catch…finally
2.throws
异常处理的格式:
2.1 try…catch…finally
2.2 try {
/
/
只
能
有
一
个
t
r
y
\color{red}{//只能有一个try}
//只能有一个try
可能出现问题的代码;
} catch(异常类名 异常对象) {
/
/
/
/
注
意
c
a
t
c
h
.
.
.
可
以
写
多
个
\color{red}{注意catch{ ... }可以写多个}
////注意catch...可以写多个
异常处理的代码
} finally {
释放未关闭的资源
}
异常处理的执行流程
1.程序执行到错误代码的地方,系统会抛出一个异常对象
ArithmeticException ae = new ArithmeticException("/by zero");
throw ae;//抛出ae对象
2.程序转入catch块与声明的exception进行逐个匹配
3.匹配成功,程序执行 catch代码
4.匹配失败,程序还给JVM处理
注意事项
- 1.try块代码尽量越少越好
- 2.一旦try块代码中出现异常,无论try块后面有多少行代码,都不会被执行
- 3.catch块中异常参数匹配同样满足多态 Exception e = new ArithmeticException("/by zero");
- 4.try块只能够有一个,catch可以有多个,try可以和finally组合,try可以和catch组合,try可以和catch和finally组合
- 5.一般会把Exception作为catch的参数类型放在异常处理格式的最后,Execption作为父类异常参数只能够出现在异常的最后面,先子类后父类
案例:
public static void main(String[] args) {
// TODO Auto-generated method stub
int a=10;
int b=0;
int arr[]=new int[3];
Object obj=null;
Object oj="zhangsan";
try{
arr[3]=5; //出现异常try后面的代码不会执行
obj.equals("");
System.out.println(a/b);
} catch (ArithmeticException e) {
System.out.println("出问题了,除数不能为0");
} catch (ArrayIndexOutOfBoundsException aioobe) {
System.out.println("数组索引越界");
} catch (NullPointerException ne) {
System.out.println("空指针异常");
} catch (Exception e) { //Exception 放在最后
System.out.println("出问题了");
}
}
//只打印//数组索引越界
//解析:出现异常try后面的代码不会执行
throws处理异常(声明异常)
声明异常在下面代码2
为什么有try…catch方式还需要学习throws处理异常?
在开发中,有的时候我们没有权限处理该异常,我们不知道该如何处理异常,我不想处理异常,所以我们可以将异常抛出,抛出给调用者处理
throws处理异常的格式:
[访问权限修饰符] 返回值类型 方法名(参数列表) [throws 异常类名]{
方法体;
[return 返回值];
}
throws的特点
- 1.抛出异常的处理方法千万不能抛出给JVM处理[主方法]
- 2.一般情况,我们把锅甩给方法,这样使用者在掉方法时出错,报错的为方法行,而不是main
- 3.如果一个方法抛出的是一个编译时异常,那么调用者必须处理
- 4.如果一个方法抛出的是一个运行时异常,可以处理也可以不处理,建议处理,提高程序的安全性
- 5.子类重写的方法声明的异常范围小于父类(和方法权限修饰符相反) 子:RuntimeException 父:Exception
- 6.throws表示一种异常发生的可能性,可以声明多个异常类.
前4点的代码
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
method();//把锅甩给方法,调用才报错
}catch(Exception e){
e.printStackTrace();
}
System.out.println("haha bug");//程序依旧执行
}
public static void method()throws Exception{//这个异常是运行时异常,可不处理
int a[]=new int[3];
a[3]=10;
}
后两点代码(声明异常)
//当子类throws Exception 会报错 改为RuntimeException的子类或本身即可
class Fat{
public void show()throws RuntimeException,ParseException//声明多个异常类
{
System.out.println("运行时异常");
}
}
class son extends Fat{
public void show()throws RuntimeException{
System.out.println("运行时异常的本身或者子类");
}
}
throw处理异常
有了throws关键字为什么还要学习throw?
之前我们处理异常都可以try catch,throws,或者规避错误
但对异常进行更灵活的操作,比如在异常部分添加自己定义的输出语句,或者有异常则转发到其他页面要用到throw
throws处理异常的格式:
throw 异常对象;
//throw new Exception("除数不能为0"); //方法1
Exception n=new Exception("出书不为0");//throw抛出的是异常对象
throw n;//方法2
案例:
public static void method() throws Exception{
int a=10;
int b=0;
if(b==0)//throw在方法体内出现
{
//throw new Exception("除数不能为0"); //方法1
Exception n=new Exception("出书不为0");//throw抛出的是异常对象
throw n;//方法2
}
Runtime.getRuntime().exit(0);
System.out.println(a/b);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
method();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("asd");//依然可以执行
}
打印信息:
java.lang.Exception: 出书不为0
asd
at com.ljx.exception_te.Exception_04.method(Exception_04.java:26)
at com.ljx.exception_te.Exception_04.main(Exception_04.java:36)
自定义异常类
自定义异常格式
1、运行时异常 继承 RuntimeException
编译时异常 继承 Exception
2、书写两个构造方法
无参构造方法
带 message 参数的构造方法
案例:分数必须在0~100分之间
需求: 自定义分数异常
public class Exception_06 {
public static void main(String[] args) {
double score=474;
Teacher t=new Teacher();
try {
t.checkScore(score);//当成绩不在0-100之间时抛出异常
} catch (ScoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Teacher{
public boolean checkScore(double s) throws ScoreException{
if(s>100||s<0)
throw new ScoreException("分数异常");//异常打印的行数
return true;
}
}
class ScoreException extends Exception{
private static final long serialVersionUID = 1L;
public ScoreException(){
}
public ScoreException(String s){
super(s);
}
}
打印结果:
com.ljx.exception_te.ScoreException: 分数异常
at com.ljx.exception_te.Teacher.checkScore(Exception_06.java:34)
at com.ljx.exception_te.Exception_06.main(Exception_06.java:23)
异常的笔试题
代码题
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(show());
}
public static int show(){
int x=1;
try{
x++;
return x++;
}finally{
++x;
System.out.println(x);
}
}
解析:在try语句中,在执行return语句时,要返回的结果2已经准备好了 ,接着x++=3
此时,程序转到finally执行。
在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果(使用栈保存返回值)
打印时先执行show方法,打印4 后执行main打印2
关于finally
finally修饰的代码块一定会被执行,
除非在执行到finally之前程序异常退出或者调用了系统退出的方法Runtime.getRuntime().exit(0);或者System.exit(0);
finally的作用:
* finally用于释放资源,在IO流操作和数据库操作中会见到。
IO流的连接,数据库的连接,网络连接等等
finally相关的面试题
简述final,finally和finalize的区别。
参考final关键字篇
断言
assert <boolean表达式>
当表达式为True程序继续执行
捕获控制台的异常信息,保存在文件中
Str转成int 出现异常,写个函数保存出现异常信息,(异常信息中包含时间)要求可追加
import java.io.*;
import java.sql.Date;
import java.text.*;
import java.util.Calendar;
import java.util.Properties;
public class T_10 {
public static void main(String[] args) throws FileNotFoundException {
String string="123a";
String s="exception.log";
try {
int ints =Integer.parseInt(string);
} catch (NumberFormatException e) {
e.printStackTrace();//这个函数也可以传入一个OutputStream类型的对象参数
//改变一下标准的输出设备,利用万能流printStream将标准输出写入文件
System.setOut(new PrintStream(new FileOutputStream(new File(s),true),true));
e.printStackTrace(System.out);
}
//系统信息的持久化
// outputSystemInfo();
//加入时间:
writeInFile(s);
}
private static void writeInFile(String s) {
//加入时间:
Calendar calendar=Calendar.getInstance();
Date date=new Date(calendar.getTimeInMillis());
String string=new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss").format(date);
try {
BufferedWriter bo = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(s),true)));
bo.write(string);
bo.newLine();
bo.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//将系统信息持久化的方法
public static void outputSystemInfo() {
Properties pro=System.getProperties();
try {
System.setOut(new PrintStream("properties.log"));
} catch (FileNotFoundException e) {
System.out.println("创建文件失败");
}
pro.list(System.out);
}
}