JavaSE异常处理(异常分类、异常实际作用)
目录
1.异常的基本概念
什么是异常:程序执行过程中的不正常情况
异常的作用:增强程序的健壮性
异常在java中以类的形式存在,每一个异常类都可以创建异常对象
2.异常的分类
2.1异常的层次结构
可以使用UML图来描述异常的继承结构
UML是一种统一建模语言,图标式语言,可在面向对象的编程语言中使用,用来描述类与类之间的关系,程序的执行流程,对象的状态等。Java软件开发中,软件设计师、系统分析师、架构师设计类,java软件开发人员必须能够看懂
常用软件:Rational Rose、startUML…
Object下有Throwable
Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)
2.2异常的分类
Exception下有两个分支:
(1)Exception的直接子类:编译时异常(受检异常、受控异常、CheckedException)
(2)RuntimeException:运行是异常(未受检异常、为受控异常、UncheckedException)
2.2.1编译时异常
要求程序员在编写阶段必须预先对这些异常预先进行处理,如果不处理编译器会报错
编译时异常一般发生的概率你较高
2.2.2运行时异常
在编写阶段程序员可以预先处理,也可以不管
运行时异常一般发生的概率比较低
2.2.3异常的处理方法
- 在方法声明的位置上,使用throws关键字(调用者会接收异常)
-
使用try…catch语句进行异常的捕获(调用者并不知道异常发生并被解决了)
注意:在java中异常发生后如果一直上抛,会抛给main方法,main方法抛给JVM,JVM只能终止程序的执行
public static void main(String[] args) throws ClassNotFoundException { //不建议在主方法上继续上抛 doSome(); } public static void main(String[] args){ try{ doSome(); }catch (ClassNotFoundException e){ e.printStackTrace(); //e引用保存的内存地址是那个new出来的异常对象的没存地址 } }
注意:
- 异常没有捕捉,而采取上抛的方式,异常发生后,该方法的后续代码不会执行
- try语句块中的,某一行出现异常,该行后面的代码不会执行
- try…catch捕捉异常后,后续代码可以执行
-
编译时异常和运行时异常都发生在运行阶段,因为只有程序再运行阶段才可以new对象
(异常的发生就是在new对象) - 如何选择上抛还是捕获:如果希望调用者来处理,选择throws上抛
2.3try、catch和finally
2.3.1深入try…catch
- catch后面的小括号中的类型可以是具体的异常类型,也可以是异常类型的父类
- catch可以写多个,建议精确的一个一个处理,这样有利于程序的调试
- catch写多个是,从上到下,必须遵守异常类从小到大的关系
try{ FileInputStream fis = new FileInputStream("D:\\scripts\\IdeaProjects") fis.read(); }catch(FileNotFoundException e){ System.out.println("文件不存在"); }catch(IOException e){ e.printStackTrace(); }
JDK8新特性
try{ }catch(FileNotFoundException | IOException e){ e.printStackTrace(); }
2.3.2 finally关键字
通常在finally语句块中完成资源的释放、关闭
finally中的代码比较有保障,是“一定”会执行的
即使try语句块中的代码出现异常,finally中的代码也会正常执行
2.3.2.1 finally的使用
try不能单独使用,try、finally可以联合使用:以下代码先执行try…再执行finally…最后执行return(方法结束)
try{ System.out.println("try..."); return; }finally{ System.out.println("finally..."); }
public class ExceptionTest{ public static void main(String[] args){ FileInputStream fis = null;//声明位置放在try外面,这样在finally中才能使用 try{ FileInputStream fis = new FileInputInputStream("D:\\stripts") String s = null
s.toString(); //fis.close();流用完需要关闭,即使程序异常也需要关闭。但这里执行不到关闭流 }catch(FileNotFoundException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); }finally{ //流的关闭放在这里比较保险 if(fis != null){ try{ fis.close(); }catch(IOException e){ e.printStackTrace(); } } } }
try{ System.out.println("try..."); System.exit(0); //退出JVM后,finally语句中的代码将不再执行 }finally{ System.out.println("finally..."); }
2.3.2.2 finally面试题
public class ExceptionTest{ public static void main(String[] args){ int result = m(); System.out.println(result); //100 } public static int m(); int i = 100; try{ return i; }finally{ i++; } }
通过反编译工具:DJ Java Decompiler
public static int m(){ int i =100; int j = i; i++; return j; }
Java语法规则结论:
- 方法体中的代码必须遵循自上而下的顺序依次逐行执行
- return语句一旦执行,整个方法必须结束
2.4getMessage和printStackTrace
try{ }catch(FileNotFoundException e){ //打印异常堆栈追踪信息。实际开发中,建议使用这个 e.printStackTrace(); //获取异常简单的描述信息 String msg = e.getMassage(); } System.out.println("HelloWorld");//捕获异常后,程序不耽误执行,服务器不会遇到异常而宕机
2.4.1getMEssage()
public class ExceptionTest(){ public static void main(String[] args){ NullPointerException e = new NullPointerException("空指针异常"); String msg = e.getMessage(); System.out.println(msg);//空指针异常 //这里只是new了异常对象,并没有将异常对象抛出,JVM会认为只是一个普通的java对象 e.printStackTrace(); } }
2.4.2printStackTrace()
如何查看异常的追踪信息,从而快速调试程序呢?
异常堆栈追踪信息从上往下一行一行的看,SUN写的代码不需要检查,问题出在自己编写的代码上
java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印
3.如何自定义异常
SUN提供的JDK内置异常在实际开发中不够用,可以自定义异常类
步骤:
- 编写一个类继承Exception或者RuntimeException
- 提供两个构造方法,一个无参数的,一个带有String参数的
public class MyException extends Exception{//编译时异常 public MyException{ } public MyException(String s){ super(s); } } //public class MyException extends RunTimeException{}//运行时异常
public class ExceptionTest{ public static void main(String[] args){ //创建异常对象,灵位手动抛出 MyException e = new MyException("芜湖~~"); e.printStackTrace();//打印异常堆栈信息 Striong msg = e.getMessage();//获取简单异常信息 System.out.println(msg); } }
4.异常在实际开发中的作用
重点:自定义异常类,在程序中使用
4.1数组模拟压栈弹栈
public class MyStackOperationException extends Exception{ public MyStackOperationException{ } public MyStackOperationException(String s){ super(s); } }
public class MyStack { private Object[] elements; private int index; public MyStack() { this.elements =new Object[10]; this.index = -1; } public void push(Object obj) throws MyStackOperationException{ if(index >=elements.length-1){ throw new MyStackOperationException("压栈失败,栈已满!") } index++; elements[index]=obj; System.out.println("压栈"+obj+"成功,栈帧指向"+index); } public void pop() throws MyStackOperationException{ if(index<0){ throw new MyStackOperationException("栈已空!") } System.out.println("弹栈"+elements[index]+"元素成功"); index--; System.out.println("栈帧指向"+index); } public Object[] getElements() { return elements; } public void setElements(Object[] elements) { this.elements = elements; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } }
public class MyStackTest { public static void main(String[] args) { MyStack stack = new MyStack(); // 压栈 try { stack.push(new Object()); stack.push(new Object()); stack.push(new Object()); stack.push(new Object()); stack.push(new Object()); stack.push(new Object()); stack.push(new Object()); stack.push(new Object()); stack.push(new Object()); stack.push(new Object()); // 这里栈满了 stack.push(new Object()); } catch (MyStackOperationException e) { // 输出异常的简单信息。 System.out.println(e.getMessage()); } // 弹栈 try { stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); // 弹栈失败 stack.pop(); } catch (MyStackOperationException e) { System.out.println(e.getMessage()); } } }
4.2用户注册
public class IllegalNameException extends Exception { public IllegalNameException() { } public IllegalNameException(String message) { super(message); } }
public class UserService { /**
* 用户注册
* @param username 用户名
* @param password 密码
* @throws IllegalNameException 无效
*/ public void register(String username, String password) throws IllegalNameException { if (null == username || username.length() < 6 || username.length() > 14) { throw new IllegalNameException("用户名不合法"); } System.out.println("注册成功,欢迎"+username); } }
public class Tset { public static void main(String[] args) { UserService userService = new UserService(); try { userService.register("日天家的猫猫","1234578"); } catch (IllegalNameException e) { System.out.println(e.getMessage()); } } }
5.方法覆盖与异常
重写之后的方法不能比重写之前的方法抛出更多的异常,可以更少
实际开发中方法覆盖时一般不做修改,直接复制
6.总结异常中的关键字
- try
- catch
- fianlly
- throws 在方法声明的位置上使用,表示上报异常信息给调用者
- throw 手动抛出异常
7.final、fianlly与finalize的区别
final 关键字
- fianl修饰的类无法继承
- final修饰的方法无法覆盖
- fianl修饰的变量无法重新复制
finally 关键字
- 与try一起联合使用
- finally语句块中的代码时不需执行的
finalize 标识符
- 是一个Object类中的方法名
- 有垃圾回收器GC负责调用
本文地址:https://blog.csdn.net/RTyinying/article/details/107896903
上一篇: java基础知识(赋值运算符,算术运算符和比较运算符)
下一篇: jdk9新特性学习