什么是异常?
java
什么是异常?java提供异常程序有什么用?
以下程序执行过程中出现了不正常情况,而这种不正常情况叫做异常
java是很完善的语言,提供了异常的处理方式,程序执行过程中出现了不正常情况,
java把信息打印到控制台上,程序员看到了可以修改
什么是异常? 程序运行中不正常的情况
java提供的异常程序有什么用? 增加程序的茁壮性
java中异常以什么方式存在呢?
异常在java中以类和对象的形式存在,每一个异常类都可以创建异常对象
UML图
什么是UML?有什么用?
UML是一种统一建模语言。
一种图标式的语言(画图的)。只要是面向对象的编程语言,都有UML。
一般画UML图的都是软件架构师或者说是系统分析师这些级别的人使用的,软件设计人员使用UML
在UML图中可以描述类和类之间的关系,程序执行的流程,对象的状态等。
在java软件开发当中,软件分析书/设计师设计好了软件
异常继承图
Object
Object下有两个分支:
- Error(不可处理,直接退出JVM)和
- Exception(可处理的)
Exception下有两个分支:
- Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须 预先对这些一场进行处理,如果不处理编译器报错,因此得名编译时异常)
- RuntimeException:运行时异常(在编写程序阶段程序员可以须预先处理,也可以先不管,都行)
异常的分类
-
编译时异常和运行时异常,都是在发生在运行阶段,编译阶段异常是不会发生的,编译时异常因为什么而得名?
因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象 -
编译时异常和运行时异常的区别?
编译时异常一般发生的概率比较高
运行时异常一般发生的概率比较低
对于一些发生率较高的异常,需要在运行之前对他进行预处理
- 假设java中没有对异常进行划分,没有分为编译时异常和运行时异常,假设所有异常都需要在编写程序阶段对其进行预处理,将是怎样的效果?
这样写的话,程序将会绝对的安全,但是是程序员会十分累,代 码到处都是处理异常的代码
-
编译时异常又被称为受检异常,还有叫做受控异常
-
运行时异常又被称作未受检异常,还有叫做未受控异常
-
再次强调:所以一场都是发生在运行阶段的
-
Java语言中对异常的处理包括两种方式:
-
第一种:在方法声明的位置上,使用throws关键字(抛给上一级) 谁调用我,我就抛给谁,抛给上一级
-
第二种:使用try…catch语句进行异常的捕捉
这件事发生了,谁也不知道,因为我给抓住了
思考:
异常发生之后,如果我选择了上抛,跑黑了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种方式。
-
-
Java如果异常发生之后一直上抛,最终抛给了main方法main方法继续向上抛,抛给了调用者JVM,JVM知道了这个异常发生,只有一个结果,终止java程序的执行
public static void main(String[] args) {
/*
程序执行到此处抛出了ArithmeticException异常
底层new出了一个ArithmeticException异常对象
然后跑出了,由于是main方法调用了100/0,
所以这个异常ArithmeticException抛给了main方法,
main方法没有处理,自动将这个异常抛给了JVM
JVm最终终止了程序的执行
*/
/*
ArithmeticException异常继承RuntimeException,属于运行时异常,
在编写程序阶段不需要对这种异常进行预先处理
*/
System.out.println(100/0);
//HelloWorld没有执行
System.out.println("HelloWorld");
}
代码:(重点,仔细看)
public static void main(String[] args) {
/*
main方法中使用doSome()方法
因为doSome()方法的声明位置上有:throws ClassNotFoundException
所以我们在调用这个方法的时候必须对这种异常进行预先的处理
如果不处理,编译器就报错
编译器报错的信息:Unhandled exception: java.lang.ClassNotFoundException
*/
doSome();
}
/**
* doSome方法在方法声明的位置上使用了 throws ClassNotFoundException
* 这个代码表示doSome()方法在执行过程中,可能会抛出ClassNotFoundException异常。
* 叫做类没有找到异常,这个异常的直接父类是:Exceptio,所以ClassNotFoundException属于编辑时异常
* @throws ClassNotFoundException
*/
public static void doSome() throws ClassNotFoundException{
}
-
处理异常的第一种方式:
在方法声明位置上使用throws关键字抛出,谁调用这个方法,我就跑给谁。跑给调用者来处理。
-
处理异常的第二种方式:
使用try…catch语句对异常进行捕捉
这个异常不会上报,自己把这个事儿给处理了
异常抛到此处为止,不会再上抛了
-
一般不建议在main方法上使用throws,因为这个异常如果真正发生了,一定会抛给JVM,JVM只有终止。
-
异常处理机制的作用就是增强程序的奖状行。怎么能做到,异常发生了也不影响他的执行,所以一般main方法中的异常建议使用try…catch进行捕捉,就不要再上抛了。
try…catch
只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行,另外要注意,try语句块中的某一行出现异常,该行后面的代码不会执行,try…catch代码捕捉之后,后面的代码可以执行
一个方法体当中的代码出现异常后,如果上报的话,此方法结束。
在以后的开发中处理编译时异常,应该上报还是捕捉呢,怎么选?
如果希望调用者来处理,选择throws上报
/*深入try ... catch
* 1.catch小括号里面可以写具体的异常类型,也可以写父类型
* 2.catch可以写多个.建议catch的时候,精确的一个一个处理,这样有利于程序的调试
* 3.catch写多个的时候,从上到下,必须遵守从小到大.
* 4.catch里面可以使用或,
* */
public class Test04 {
public static void main(String[] args) {
/* try {
FileInputStream fls = new FileInputStream("C:\\Users\\14505\\Desktop\\1.txt");
System.out.println("以上出现问题,不执行");
} catch (FileNotFoundException e) {
System.out.println("文件不存在");
}*/
try {
FileInputStream fls = new FileInputStream("C:\\Users\\14505\\Desktop\\1.txt");
System.out.println("以上出现问题,不执行");
} catch (Exception e) {//多态:Exception e = new FileNotFoundException ;
System.out.println("文件不存在");
}
}
异常常用的两个方法
-
String msg = new exception.getMessage();
-
exception.printStackTrace();
/*
异常对象有两个非常重要的方法:
获取异常简单的描述信息:
String msg = new exception.getMessage();
打印异常追踪的堆栈信息:
exception.printStackTrace();
*/
public class Test05 {
public static void main(String[] args) {
//这里只是测试getMessage()方法和printStackTrace()方法
//这里只是new了异常对象,但是没有将异常对象抛出,JVM会认为这只是一个普通的java对象
NullPointerException e = new NullPointerException("空指针异常");
//获取异常简单描述信息:这个信息实际上就是构造方法上面String方法参数
String s = e.getMessage();
System.out.println(s);
e.printStackTrace();//打印异常堆栈信息
System.out.println("HelloWorld");
}
}
使用exception.printStackTrace();打印出的异常的信息,我们应该怎样看才能快速调试?
异常信息追踪信息:从上往下一行一行的看
需要注意的是:SUN公司给的信息就不用看了(看包名就知道是自己的还是SUN公司的)。主要的问题出现在自己的代码上
在实际开发中,catch中要加上e.printStackTrace();,不然出问题也不知道
finally语句
关于try…catch中的finally子句:
-
在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中出现了异常。且finally子句必须与try一起出现,不能单独编写。
-
finally语句通常使用在哪些情况下呢?
通常finally语句块中完成资源的释放/关闭
因为finally中的代码比较有保障
即使try语句中的代码出现异常,finally中的代码也会正常执行
try{ return; }finally{ //finally中的语句会执行,能够执行到 } //这里的语句无法执行到,不能写
以上代码执行顺序:
先执行finally
在执行finally
最后执行return(return语句只要执行,方法必然结束)
一旦推出JVM就不会执行了
面试题代码:
public static void main(String[] args) { System.out.println(test()); } /* java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做) java中有一条这样的语法规则: 方法体中用的代码必须遵循自上而下的顺序依次执行 java中另一条语法规则: return语句一旦执行,整个方法必须结束 */ public static int test(){ int i =100; try { //这条代码出现在int i=100下面,所以最终结果必须是返回100 //return语句必须保证是最后执行的。一旦执行,整个方法必然结束 return i; }finally { i++; } }
final、finally、finalize()有什么区别?
-
final是一个关键字,表示最终的,不变的
final修饰的类无法继承,final修饰的方法无法覆盖
-
finally也是一个关键字,和try联合使用,使用在异常处理机制中
finally语句块中的代码是必须执行的
-
finalize()是Object中的一个方法,作为方法名出现,所以finalize是标识符,这个方法由垃圾回收器调用
自定义异常
定义:
/*
1.SUN公司提供的异常肯定是不够用的,在实际的开发中有很多业务,这些业务出现异常后,
JDK中都是没有的,和业务挂钩的。那么异常类我们程序员可以自定义吗?
可以
2.Java中怎样自定义类呢?
两步:
第一步:编写一个类继承Exception或者RuntimeException。
第二部:提供两个构造方法,一个无参数的,一个有参数的。
死记硬背
*/
public class Test07 extends Exception{//编译时异常
public Test07(){
}
public Test07(String s){
super(s);
}
}
使用:
public static void main(String[] args) {
//创建异常对象
Test07 e= new Test07("用户名不能为空");
//打印异常堆栈信息
e.printStackTrace();
//获取简单描述信息
System.out.println(e.getMessage());
}
PS:用throw可以抛出异常
重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少。
总结异常中的关键字:
-
try
-
catch
-
finally
-
throws 在方法生命位置上使用,表示上报异常信息给调用者
-
throw 手动抛出异常!
异常作业
首先定义一个异常类:
public class MyException extends Exception {
public MyException(){}
public MyException(String s){
super(s);
}
}
用户名信息类:
public class UserService {
public static void get(String userName) throws MyException {
/*
userName==null不如写成 null==userName ,免得手欠少写一个=
*/
if(userName==null||userName.length()<6||userName.length()>14||userName==null){
throw new MyException("用户名长度不符");
}
//程序能够执行到此处,说明用户名合法
System.out.println("欢迎"+userName);
}
}
最后测试类:
public class Application {
public static void main(String[] args) {
UserService u = new UserService();
Scanner s = new Scanner(System.in);
System.out.println("请输入用户名");
String userName= s.next();
try {
u.get(userName); //这里可能会产生异常
System.out.println("请输入密码");
String userPassword= s.next();
System.out.println("注册成功!");
System.out.println(userName.length());
} catch (MyException e) {
System.out.println(e.getMessage());
}
}
}