《动力节点视频学习过程中的笔记》
一、 异常
1.什么是异常?异常的作用?
异常以类和对象的形式存在,每一个异常类都可以new一个异常对象。
Exception in thread “main” java.lang.ArithmeticException: / by zero
at Exception01.ExceptionTest01.main(ExceptionTest01.java:7)
JVM将new的异常对象打印输出控制台,增强程序健壮性。
2.异常的继承结构?
用UML图来画继承结构,
UML?
一种统一建模语言,一种图标式语言,只要是面向对象的编程语言,都有UML。一般是软件设计人员使用,画系统架构图。
UML图中描述类和类之间的关系,程序执行的流程,对象的状态等。
画UML图有很多工具,例如:Rational Rose(收费的)、starUML等…
3.异常的分类?
编译时异常(受检异常/受控异常)一般发生的概率比较高,在运行之前要对其进行预处理。
运行时异常(RuntimeException)(未检异常/非受控异常)一般发生的概率比较低。
4.异常的处理
/**doSome方法声明时使用了throws ClassNotFoundException,该异常属于编译时异常,
*调用时必须预处理
**/
public class ExceptionTest01 {
public static void main(String[] args) {
doSome();//这里报错
}
public static void doSome()throws ClassNotFoundException{
System.out.println("hi");
}
}
(1)【异常上抛】在方法声明的位置上,使用throws 关键字,抛给上一级。谁调用我,我就抛给谁。
JAVA中异常发生后如果一直上抛,最终抛给了main方法,main方法继续上抛,抛给JVM,VM知道这个异常发生,只有一个结果。终止java程序的执行。
(2)【异常捕捉】使用try catch语句进行异常的捕捉。
① 语法格式
try {//以上代码出现错误,直接进行catch语句块
}catch (异常名 变量名){
}
异常捕捉之后,后续代码继续执行。
②catch写多个时,从上到下必须遵循从小到大。
③catch后面可以写具体的异常类型,也可以写该异常的父类。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ExceptionTest01 {
// 一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。
// 异常处理机制的作用就是增强程序的健壮性。怎么能做到,异常发生了也不影响程序的执行。所以
// 一般main方法中的异常建议使用try..catch进行捕捉。main就不要继续上抛了。
/*
public static void main(String[] args) throws FileNotFoundException {
System.out.println("main begin");
m1();
System.out.println("main over");
}
*/
public static void main(String[] args) {
// 100 / 0这是算术异常,这个异常是运行时异常,你在编译阶段,可以处理,也可以不处理。编译器不管。
//System.out.println(100 / 0); // 不处理编译器也不管
// 你处理也可以。
/*
try {
System.out.println(100 / 0);
} catch(ArithmeticException e){
System.out.println("算术异常了!!!!");
}
*/
System.out.println("main begin");
try {
// try尝试
m1();
// 以上代码出现异常,直接进入catch语句块中执行。
System.out.println("hello world!");
} catch (FileNotFoundException e){ // catch后面的好像一个方法的形参。
// 这个分支中可以使用e引用,e引用保存的内存地址是那个new出来异常对象的内存地址。
// catch是捕捉异常之后走的分支。
// 在catch分支中干什么?处理异常。
System.out.println("文件不存在,可能路径错误,也可能该文件被删除了!");
System.out.println(e); //java.io.FileNotFoundException: D:\course\01-课\学习方法.txt (系统找不到指定的路径。)
}
// try..catch把异常抓住之后,这里的代码会继续执行。
System.out.println("main over");
}
private static void m1() throws FileNotFoundException {
System.out.println("m1 begin");
m2();
// 以上代码出异常,这里是无法执行的。
System.out.println("m1 over");
}
// 抛别的不行,抛ClassCastException说明你还是没有对FileNotFoundException进行处理
//private static void m2() throws ClassCastException{
// 抛FileNotFoundException的父对象IOException,这样是可以的。因为IOException包括FileNotFoundException
//private static void m2() throws IOException {
// 这样也可以,因为Exception包括所有的异常。
//private static void m2() throws Exception{
// throws后面也可以写多个异常,可以使用逗号隔开。
//private static void m2() throws ClassCastException, FileNotFoundException{
private static void m2() throws FileNotFoundException {
System.out.println("m2 begin");
// 编译器报错原因是:m3()方法声明位置上有:throws FileNotFoundException
// 我们在这里调用m3()没有对异常进行预处理,所以编译报错。
// m3();
m3();
// 以上如果出现异常,这里是无法执行的!
System.out.println("m2 over");
}
private static void m3() throws FileNotFoundException {
// 调用SUN jdk中某个类的构造方法。
// 这个类还没有接触过,后期IO流的时候就知道了。
// 我们只是借助这个类学习一下异常处理机制。
// 创建一个输入流对象,该流指向一个文件。
/*
编译报错的原因是什么?
第一:这里调用了一个构造方法:FileInputStream(String name)
第二:这个构造方法的声明位置上有:throws FileNotFoundException
第三:通过类的继承结构看到:FileNotFoundException父类是IOException,IOException的父类是Exception,
最终得知,FileNotFoundException是编译时异常。
错误原因?编译时异常要求程序员编写程序阶段必须对它进行处理,不处理编译器就报错。
*/
//new FileInputStream("D:\\course\\01-开课\\学习方法.txt");
// 我们采用第一种处理方式:在方法声明的位置上使用throws继续上抛。
// 一个方法体当中的代码出现异常之后,如果上报的话,此方法结束。
new FileInputStream("D:\\course\\01-课\\学习方法.txt");
System.out.println("如果以上代码出异常,这里会执行吗??????????????????不会!!!");
}
}
5.异常的方法
(1)String msg = exception.getMessage();
(2)exception.printStackTrace();异常追踪信息从上往下看,sun公司写的就不看了,主要看自己写的。
public class ExceptionTest02 {
public static void main(String[] args) {
NullPointerException e = new NullPointerException("空指针异常");
String str = e.getMessage();//获取new异常时传入的字符串
System.out.println(str);
e.printStackTrace();//打印异常堆栈追踪信息
}
}
执行结果:
空指针异常
java.lang.NullPointerException: 空指针异常
at Exception01.ExceptionTest02.main(ExceptionTest02.java:6)
6.finally关键字
(1)finally子句:与try、catch一起出现,(可以没有catch,必须有try)最后执行,并且一定会执行,即使try语句块中的代码出现了异常。
(2)finally语句块中一般用来中完成资源的释放/关闭。
(3)以下代码的执行顺序:
try
finally
return
若在finally后面加一条语句,该语句不会执行。
try {
System.out.println("!!");
return;
}finally{
System.out.println("~~");
}
(4)方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!)
return语句一旦执行,整个方法必须结束(亘古不变的语法!)
public class ExceptionTest13 {
public static void main(String[] args) {
int result = m();
System.out.println(result); //100
}
public static int m(){
int i = 100;
try {
// 这行代码出现在int i = 100;的下面,所以最终结果必须是返回100
// return语句还必须保证是最后执行的。一旦执行,整个方法结束。
return i;
} finally {
i++;
}
}
}//结果是100.不是101
反编译之后的效果:
public static int m(){
int i = 100;
int j = i;
i++;
return j;
}
7.final、finally、finalize
(1)final是关键字,表示不可改变的。
(2)finally是关键字,与try联合使用。
(3)finalize是Object类里的一个方法,是标识符。
8.自定义异常
(1)写一个异常class继承Exception/RunTimeException。
(2)写两个构造方法,一个无参,一个有参。
class MyException extends Exception{
public MyException(){
}
public MyException(String s){
super(s);
}
}
有什么作用?
throw new MyException()//手动抛出异常
import java.util.Scanner;
public class ExceptionTest03 {
public static void main(String[] args) {
System.out.println("请输入用户名:");
Scanner a = new Scanner(System.in);
String str1 = a.next();
System.out.println("密码:");
Scanner b = new Scanner(System.in);
String str2 = b.next();
UserService user = new UserService();
try {
user.register(str1, str2);
}catch (MyException e) {
System.out.println(e.getMessage());
}
}
}
class MyException extends Exception{
public MyException(){
}
public MyException(String s){
super(s);
}
}
public class UserService {
private String username;
private String password;
public void register(String username, String password) throws MyException {
/*
if (username.length() >= 6 && username.length() <= 14) {
this.username = username;
this.password = password;
} else {
throw new MyException("用户名不合法");
}
*/
if (username==null||username.length()<6||username.length()>14){
throw new MyException("用户名不合法,长度必须在6-14之间");
}//引用==null的判断最好放在所有条件最前边,放在后边容易出现空指针异常
//写成null==username更好
System.out.println("注册成功!");
}
}
9.方法覆盖时异常相关
重写之后的方法不能比重写之前抛出更多的异常,可以更少。父类不抛,子类不能抛。(RunTImeException可以抛)父类抛了,子类可以不抛,可以抛一样的,可以抛比他小的。