当程序出现了不正常的情况
-
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 手动抛异常*/