《java学习笔记》之异常处理机制

异常处理机制


一.为什么要使用异常机制


当程序出现了不正常的情况

  • java把异常信息打印到了控制台,供程序员参考,程序员看到异常信息后,可以对程序进行修改

  • 让程序更加健壮,不会因为异常就停止

二.异常处理机制的基本语法


2.1 异常的形式

public class Test01 {

public static void main(String[] args) {

//异常在java以类的形式存在

//通过"异常类"实例化"异常对象"

NullPointerException nullPointerException =new NullPointerException(“空指针异常”);

System.out.println(nullPointerException);//java.lang.NullPointerException: 空指针异常

ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException =new ArrayIndexOutOfBoundsException(“数组下标越界异常”);

System.out.println(arrayIndexOutOfBoundsException);//java.lang.ArrayIndexOutOfBoundsException: 数组下标越界异常

//mian方法中调用dosome()方法

//因为dosome()方法上声明有:throws ClassNotFoundException

//我们在调用dosom()方法时必须对这种异常进行预先处理

//如果不处理:编译器报错

//编译器报错信息:Error:(19, 15) java: 未报告的异常错误java.lang.ClassNotFoundException; 必须对其进行捕获或声明以便抛出

//dosome();

dosome();

//有两种方法:

//第一种:继续往上抛,因为是main方法调用的,所以在main方法上声明

//第二种方法:使用try-catch对异常进行捕捉

}

//这个方法抛出了一个异常

/*

  • dosom方法在方法声明的时候使用了 throws ClassNotFoundException

  • 这个代码表示dosome()方法在执行的时候,有可能出现ClassNotFoundException异常

  • 叫做类没找到异常,这个异常的父类是Exception,所以ClassNotFoundException是编译时异常

  • */

public static void dosome() throws ClassNotFoundException{

}

}

2.2 怎么处理异常

public class Test02 {

//方法一:继续往上抛,谁调用,谁声明,抛给调用者

//一般不建议在main上方上使用throws,因为这个异常一旦发生了,一定会上抛给JVM,JVM只能终止

//异常处理机制的作用就是增强程序的健壮性。做到异常发生了,也不影响程序的执行

//所以建议main方法的异常建议使用try…catch进行捕捉,就不要上抛了

//public static void main(String[] args) throws ClassNotFoundException{

public static void main(String[] args) {

//第二种:try-catch 捕捉

//捕捉等于把异常拦下了,异常真正的解决了(调用者是不知道的)

try {

dosome();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

public static void dosome() throws ClassNotFoundException{

}

}

2.3 try-catch理解

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.lang.reflect.Field;

public class Test03 {

public static void main(String[] args) {

System.out.println(“main begin”);

//这里使用了try - catch 所以main方法不用再抛异常了

try {

//先执行try,如果有异常就执行 catch

m1();

} catch (Exception e) {//e是一个变量名

//这个分支可以使用e应用,e存储了new出来的异常的内存地址

//catch捕捉后继续的分支

e.printStackTrace();

}

//try…catch 把异常抓住后,这里的代码会继续执行

System.out.println(“main over”);

}

public static void m1() throws Exception {

System.out.println(“m1 begin”);

//这里报错是因为m2抛出了异常,m1调用就要对异常进行处理

m2();

System.out.println(“m1 over”);

}

//抛下面几个异常可以 Exception 是 IOException的父类 IOException是 FileNotFoundException的父类

public static void m2() throws Exception {

//public static void m2() throws IOException {

//public static void m2() throws FileNotFoundException {

System.out.println(“m2 begin”);

//这里报错是因为m3抛了异常,m2调用,要对异常进行处理

m3();

System.out.println(“m2 over”);

}

public static void m3 () throws FileNotFoundException {

System.out.println(“m3 begin”);

new FileInputStream(“D:\day25课堂笔记.txt”);

//如果上面一行代码抛异常了,这里是不会执行的

System.out.println(“m3 over”);

}

}

/*

  • 异常对象有两个重要的方法:

  •     String string = exception.getMessage;    获取异常简单描述学习
    
  •       exception.printStackTrace               打印异常追踪的堆栈信息
    

*/

public class Test04 {

public static void main(String[] args) {

//这里只是new了异常对象,没有抛出,JVM只是认为这是一个简单的对象类

NullPointerException nullPointerException1 =new NullPointerException();

NullPointerException nullPointerException2 =new NullPointerException(“空指针异常”);

System.out.println(nullPointerException1.getMessage());//null

System.out.println(nullPointerException2.getMessage());//空指针异常

System.out.println(nullPointerException1);//java.lang.NullPointerException

System.out.println(nullPointerException2);//java.lang.NullPointerException: 空指针异常

//打印异常堆栈信息

//java后台打印异常堆栈信息的时候,采用了异步线程的方式打印的

//java.lang.NullPointerException

// at caopeng.javase.test.Test04.main(Test04.java:10)

nullPointerException1.printStackTrace();

//java.lang.NullPointerException: 空指针异常

// at caopeng.javase.test.Test04.main(Test04.java:11)

nullPointerException2.printStackTrace();//

//这个在异常信息前输出

System.out.println(“hahaha”);

try {

m1();

} catch (FileNotFoundException e) {

//打印异常堆栈信息

//在实际开发当中,建议使用这个

//这行代码要写上,不然出错了都不知道

e.printStackTrace();

//怎么看异常信息,怎么快速调试?

// 从上往下看,SUN写的就不用看了

/*java.io.FileNotFoundException: C:\Users\A556U\Desktop\文\day34-作业.txt (系统找不到指定的路径。)

at java.base/java.io.FileInputStream.open0(Native Method)

at java.base/java.io.FileInputStream.open(FileInputStream.java:219)

at java.base/java.io.FileInputStream.(FileInputStream.java:157)

at java.base/java.io.FileInputStream.(FileInputStream.java:112)

at caopeng.javase.test.Test04.m3(Test04.java:56)

at caopeng.javase.test.Test04.m2(Test04.java:52)

at caopeng.javase.test.Test04.m1(Test04.java:48)

at caopeng.javase.test.Test04.main(Test04.java:40)*/

}

}

private static void m1() throws FileNotFoundException {

m2();

}

private static void m2() throws FileNotFoundException {

m3();

}

private static void m3() throws FileNotFoundException {

new FileInputStream(“C:\Users\A556U\Desktop\文\day34-作业.txt”);

}

}

2.4 try…catch…finally

public class Test05 {

public static void main(String[] args){

FileInputStream fileInputStream = null;

//捕捉异常

try {

fileInputStream =new FileInputStream(“D:\day25课堂笔记.txt”);

//开始读文件

System.out.println(“开始读文件”);

String s = null;

//这里肯定会抛空指针异常

s.toString();

//那么这里的流就关闭不了了,这样会占用内存

//fileInputStream.close();

System.out.println(“这里会执行吗”);//不会输出

} catch (FileNotFoundException e) {

e.printStackTrace();

}catch (NullPointerException e){

System.out.println(“空指针异常”);

e.printStackTrace();

}

finally {

//finally字句必须和try一起出现,不能单独编写

//在finally后面的语句块一定会执行,即使try中出现异常也会正常运行

System.out.println(“finally 语句块执行”);

try {

fileInputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

2.5 关于finally

//关于finally

public class Test06 {

public static void main(String[] args) {

//没有catch,只有try 和finally

try{

System.out.println(“try…”);

return;

}finally {

System.out.println(“finally”);

}

//Unreachable statement

//不会执行的语句

//System.out.println(“会执行吗”);

/*

try…

finally

*/

//这表明了finally一定会执行

//顺序应该是先try,然后看到return,就跳到finally,finally执行完再到return

}

}

三.自定义异常


3.1怎么自定义异常

/*怎么定义异常?

  • 两步:

  • 第一步:编写一个类继承Exception或者RunException

  • 第二步:提供两个构造方法,一个无参的,一个有参的*/

//死记硬背

public class Test07 extends Exception{

//构造方法,无参

public Test07() {

}

//构造方法,有参

public Test07(String message) {

super(message);

}

}

public class Test08 {

public static void main(String[] args) {

//这里只是尝试new出自定义异常,未抛出

/*Test07 test07 =new Test07();

System.out.println(test07);//caopeng.javase.test.Test07

//打印异常的简单消息

System.out.println(test07.getMessage());//null

//打印异常的堆栈信息

test07.printStackTrace();

//caopeng.javase.test.Test07

// at caopeng.javase.test.Test08.main(Test08.java:6)*/

Test07 test07 =new Test07(“自定义异常”);

System.out.println(test07);//caopeng.javase.test.Test07: 自定义异常

//打印异常的简单消息

System.out.println(test07.getMessage());//自定义异常

//打印异常的堆栈信息

test07.printStackTrace();

//caopeng.javase.test.Test07: 自定义异常

// at caopeng.javase.test.Test08.main(Test08.java:16)

}

}

3.2 抛自定义异常`

如果不自定义异常

/*

1、这个栈可以存储java中的任何引用类型的数据。

2、在栈中提供push方法模拟压栈。(栈满了,要有提示信息。)

3、在栈中提供pop方法模拟弹栈。(栈空了,也有有提示信息。)

4、编写测试程序,new栈对象,调用push pop方法来模拟压栈弹栈的动作。

5、假设栈的默认容量为10.(注意无参构造方法的编写方式)

*/

public class MyStack {

//这个栈可以存储java中的任何引用类型的数据。

//Object类的数组

//假设栈的默认容量为10

private Object[] objects;

//栈帧

//每添加一个元素就+1

//每弹出一个元素就-1

private int index = -1;//表示栈帧指向了顶部元素,就是多加了一个头指针,让栈不为空,因为没有元素的时候,栈帧指向0是不太恰当的

//构造方法

public MyStack() {

this.objects = new Object[10];

}

public MyStack(Object[] objects) {

this.objects = objects;

}

//set 和 get 方法

public Object[] getObjects() {

return objects;

}

public void setObjects(Object[] objects) {

this.objects = objects;

}

public int getIndex() {

return index;

}

public void setIndex(int index) {

this.index = index;

}

//在栈中提供push方法模拟压栈。(栈满了,要有提示信息。)

public void push(Object o){

if (index + 1 > objects.length){

System.out.println(“压栈失败,栈已满”);

return;

}else{

//压栈

index ++;

objects[index] = o;

System.out.println(“压栈” + o + “成功,栈帧指向” + index);

}

}

//在栈中提供pop方法模拟弹栈。(栈空了,也有有提示信息。)

public void pop(){

if (index == -1){

System.out.println(“弹栈失败,栈以空”);

return;

}else{

//弹栈

System.out.println(“弹栈” + objects[index] + “元素成功”);

objects[index] = null;

index --;

System.out.println(“栈帧指向” + index);

}

}

}

自定义异常

//栈操作异常

public class MyStackException extends Exception{

//构造方法

public MyStackException() {

}

public MyStackException(String message) {

super(message);

}

}

/*

1、这个栈可以存储java中的任何引用类型的数据。

2、在栈中提供push方法模拟压栈。(栈满了,要有提示信息。)

3、在栈中提供pop方法模拟弹栈。(栈空了,也有有提示信息。)

4、编写测试程序,new栈对象,调用push pop方法来模拟压栈弹栈的动作。

5、假设栈的默认容量为10.(注意无参构造方法的编写方式)

*/

public class MyStack {

//这个栈可以存储java中的任何引用类型的数据。

//Object类的数组

//假设栈的默认容量为10

private Object[] objects;

//栈帧

//每添加一个元素就+1

//每弹出一个元素就-1

private int index = -1;//表示栈帧指向了顶部元素,就是多加了一个头指针,让栈不为空,因为没有元素的时候,栈帧指向0是不太恰当的

//构造方法

public MyStack() {

this.objects = new Object[10];

}

public MyStack(Object[] objects) {

this.objects = objects;

}

//set 和 get 方法

public Object[] getObjects() {

return objects;

}

public void setObjects(Object[] objects) {

this.objects = objects;

}

public int getIndex() {

return index;

}

public void setIndex(int index) {

this.index = index;

}

//在栈中提供push方法模拟压栈。(栈满了,要有提示信息。)

public void push(Object o) throws MyStackException {

if (index + 1 >= objects.length){

/*System.out.println(“压栈失败,栈已满”);

return;*/

//手动把异常抛出去

throw new MyStackException(“压栈失败,栈已满”);

}else{

//压栈

index ++;

objects[index] = o;

System.out.println(“压栈” + o + “成功,栈帧指向” + index);

}

}

//在栈中提供pop方法模拟弹栈。(栈空了,也有有提示信息。)

public void pop() throws MyStackException {

if (index == -1){

/*System.out.
println(“弹栈失败,栈以空”);

return;*/

//手动把异常抛出去

throw new MyStackException(“弹栈失败,栈以空”);

}else{

//弹栈

System.out.println(“弹栈” + objects[index] + “元素成功”);

objects[index] = null;

index --;

System.out.println(“栈帧指向” + index);

}

}

}

public class MyStackTest {

public static void main(String[] args) {

//创造一个stack对象

MyStack myStack =new MyStack();

//此时里面什么都没有,弹栈试一下

try {

myStack.pop();

} catch (MyStackException e) {

e.printStackTrace();

}

//压栈

//调用push可能会满栈,这里起到了提醒的作业

try {

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

myStack.push(new Object());

} catch (MyStackException e) {

e.printStackTrace();

}

//弹栈

try {

myStack.pop();

myStack.pop();

myStack.pop();

myStack.pop();

myStack.pop();

myStack.pop();

myStack.pop();

myStack.pop();

myStack.pop();

myStack.pop();

myStack.pop();

} catch (MyStackException e) {

e.printStackTrace();

}

}

}

四.方法重写不能比父类抛出更多的异常


/*

  • 之前讲解方法覆盖时

  • 重写后的方法不能比重写之前抛出跟多(更宽泛)的异常,可以更少

  • */

class Animal {

public void dosome(){

}

public void doother() throws Exception{

}

}

class Cat extends Animal{

//编译报错

/*public void dosome() throws Exception{

}*/

//编译正常

/*public void doother() {

}*/

//编译正常

/*public void doother() throws Exception {

}*/

//编译正常

public void doother() throws NullPointerException{

}

}

/*异常中的关键字

  • try

  • catch

  • finally

  • throws 在方法上声明,表示异常上抛给使用者

  • throw 手动抛异常*/

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值