示例一
要点
1、什么是异常,java提供异常处理机制有什么用?
1)程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常
2)java语言是很完善的语言,提供了异常的处理方式:
JVM把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对程序进行修改,让程序更加的健壮。
异常的作用:增强程序的健壮性。
2、java语言中异常是以什么形式存在的呢?
1)异常在java中以类的形式存在,每一个异常类都可以创建异常对象。
3、异常对应的现实生活中是怎样的?
火灾(异常类):
2008年8月8日,小明家着火了(异常对象)
2008年8月9日,小刚家着火了(异常对象)
2008年9月8日,小红家着火了(异常对象)
类是:模板。
对象是:实际存在的个体。
实例
public static void main(String[] args){
int a = 10;
int b = 0;
//实际上JVM在执行到此处的时候,会new异常对象:new ArithmeticException("/ by zero" );
//并且JVM将new的异常对象抛出,打印输出信息到控制台了。
int c = a / b;
System.out.println(a + "/"+ b +"=" + c);
//我观察到异常信息之后,对程序进行修改,更加健壮。
/*
int a = 10;
int b = 2;
if(b == 0){
System.out.println("除数不能为0");
return;
}
//程序执行到此处表示除数一定不是0
int c = a / b;
System.out.println(a + "/"+ b + "=" + c);
*/
//通过“异常类”实例化“异常对象”
NumberFormatException nfe = new NumberFormatException("数字格式化异常!");
//java.Lang.NumberFormatException:数字格式化异常!
System.out.println(nfe);
//通过“异常类”创建异常对象
NullPointerException npe = new NullPointerException("空指针异常发生了!");
//java.Lang.NullPointerException:空指针异常发生了!
System.out.println(npe);
}
示例二
要点
1、异常的继承结构
Object
Object下有Throwable(可抛出的)
Throwable下有两个分支:
Error(不可处理,直接退出JVM)和Exception(可处理的)
Exception下有两个分支:
Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进处理)
RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不管)
2、编译时异常和运行时异常,都是发生在运行阶段。编译阶段异常是不会发生的。
3、编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,
因为只有程序运行阶段才可以new对象,异常的发生就是new异常对象.
4、编译时异常和运行时异常的区别?
编译时异常发生概率较高需要在运行之前进行预处理,运行时异常发生概率较低不需要在运行之前进行预处理。
5、编译时异常还有其他名字: 受检异常(CheckedException)、受控异常
运行时异常还有其它名字: 未受检异常(UnCheckedException)、非受控异常
6、Java语言中对异常的处理包括两种方式:
第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级(调用者)。
异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。
第二种方式:使用try..catch语句进行异常的捕捉并处理。

实例
public class ExceptionTest02 {
public static void main(String[] args) {
// 第一种处理方式:在方法声明的位置上继续使用: throws,来完成异常的继续上抛。抛给调用者。
/*
public static void main(String[] args) throws ClassNotFoundException {
doSome();
}
*/
//第二种处理方式: try...catch进行捕捉。
//捕捉等于将异常拦下来真正解决(调用者是不知道的)
public static void main(String[] args) {
try {
doSome();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// main方法中调用doSome()方法
//因为doSome()方法声明位置上有: throws ClassNotFoundException
//我们在调用doSome()方法的时候必须对这种异常进行预先的处理。
//如果不处理,编译器就报错。
//编译器报错信息: Unhandled exception: java.lang.ClassNotFoundException
// doSome();
}
/**
* doSome 方法在方法声明的位置上使用了: throws ClassNotFoundException
*这个代码表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常。
*这个异常直接父类是: Exception,所以ClassNotFoundException属于编译时异常。
* @throws ClassNotFoundException
*/
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome!!!");
}
示例三(try...catch、throws)
要点
1、只要异常没有捕捉,采用抛出异常的方式,此方法的后续代码不会执行
另外需要注意,try语句块中的某一行出现异常,该行后面的代码不会执行
2、throws 后面也可以写多个异常,使用逗号隔开
3、可以直接抛出该抛出异常类对象的父对象异常类对象
4、catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型。
catch可以写多个。建议catch的时候,精确的一个一个处理,这样有利于程序的调试。
catch写多个的时候,从上到下,必须遵守从小到大。
实例
public class ExceptionTest03 {
//一般不建议在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/e 这是算术异常,这个异常是运行时异常,你在编译阶段,可以处理,也可以不处理,编译器不管。
//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("文件不存在,可能路径错误,也可能该文件被删除了! ");
} catch(IOException e){
System.out.println("读文件报错了!");
}
//try...catch处理完异常后,这里的代码会继续执行
System.out.println("main over");
}
private static void m1() throws FileNotFoundException {
System.out.print1n("m1 begin");
m2();
//以上代码出异常,这里是无法执行的。
System.out.println("m1 over") ;
}
//抛别的不行,抛ClassCastException说明你还是没有对FileNotFoundException进行处理
//private static void m2() throws ClassCastException{
//抛FileNotFoundException的父对象I0Exception,这样是可以的,因为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();
//以上如果出现异常,这里是无法执行的!
System.out.println("m2 over");
}
private static void m3() throws FileNotFoundException {
//调用SUN jdk中某个类的构造方法。
//创建一个输入流对象,该流指向一个文件。
/*
编译报错的原因是什么?
第一:这里调用了一个构造方法:FileInputStream(String name)
第二:这个构造方法的声明位置上有: throws FileNotFoundException
第三:通过类的继承结构看到:FileNotFoundException父类是I0Exception,IOException的父类是Exception
最终得知,FileNotFoundException是编译时异常。
错误原因?编译时异常要求程序员编写程序阶段必须对它进行处理,不处理编译器就报错。
*/
new FileInputStream( "D: \\course\\\\javaSE.txt");
System.out.println("如果以上代码出异常,这里会执行吗????????????????不会!!! ");
}
}
示例四(getMessage()、printStackTrace())
要点
1、异常对象有两个非常重要的方法:
获取异常简单的描述信息:
String msg = exception.getMessage();
打印异常追踪的堆栈信息:
exception.printStackTrace();(一般都是使用它)
2、我们以后查看异常的追踪信息,我们应该怎么看,可以快速的调试程序呢?
异常信息追踪信息,从上往下一行一行看。
但是需要注意的是: SUN写的代码就不用看了(看包名就知道是自己的还是SUN的)。
主要的问题是出现在自己编写的代码上。
实例
pub1ic class ExceptionTest04 {
public static void main(String[] args) {
//这里只是为了测试getMessage()方法和printStackTrace()方法。
//这里只是new了异常对象,但是没有将异常对象抛出,JVM会认为这是一个普通的java对象。
NullPointerException e = new NullPointerException( "空指针异常fdsafdsafdsafds");
//获取异常简单描述信息:这个信息实际上就是构造方法上面String参数。
String msg = e.getMessage(); // 空指针异常fdsafdsafdsafds
System.out.println(msg);
//打印异常堆栈信息
// java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的。
e.printStackTrace();
try {
m1();
} catch (FileNotFoundException e) {
//打印异常堆栈追踪信息! ! !
//在实际的开发中,建议使用这个。养成好习惯!
//e.printStackTrace();
/*
java.io.FileNotFoundException: C:\jetns-agent.jar(系统找不到指定的文件。)
at java.base/java.io.FileInputStream.open(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FilenputStream.<init>(FileInputStream.java:155)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)
at com.bjpowernode.javase.exception.ExceptionTest09.m3(Except ionTest09.java:31)
at com.bjpowernode.javase.exception.ExceptionTest09.m2(ExceptionTest09.java:27)
at com.bjpowernode.javase.exception.ExceptionTest09.m1(ExceptionTest09.java:23)
at com. bipowernode.javase.exception.ExceptionTest09.main(ExceptionTest09.java:14)
因为31行出问题导致了27行
27行出问题导致23行
23行出问题导致14行。
应该先查看31行的代码。31行是代码错误的根源。
*/
}
//这里程序继续执行,程序try...catch处理了异常,很健壮,服务器不会因为遇到异常而宕机。
System.out.println("He11o Wor1d!");
}
private static void m1() throws FileNotFoundException {
m2();
}
private static void m2() throws FileNotFoundException {
m3();
}
private static void m3() throws FileNotFoundException {
new FileInputStream(name: "C:\\jetns-agent.jar");
}
}
示例五(finally)
要点
关try.. catch中的finally子句:
1、在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
finally子句必须和try一起出现,不能单独编写。
2、finally语句通常使用在哪些情况下呢?
通常在finally语句块中完成资源的释放/关闭。因为finally中的代码比较有保障。
即使try语句块中的代码出现异常, finally中代码也会正常执行,除非退出JVM虚拟机。
3、try finally,没有catch可以吗?可以。
try不能单独使用。
try finally可以联合使用。
finally中的代码一般会执行,除非退出JVM虚拟机,return语句最后执行,return语句执行方法必然结束。
4、System.exit(0) 退出JVM虚拟机,程序执行到此就结束了。
实例
public class ExceptionTest05 {
public static void main(String[] args) {
FileInputStream fis = null; //声明位置放到try外面,这样在finally中才能用。
try {
//创建输入流对象
fis = new FileInputStream(name: "D:\\course\\02-JavaSE\\document");
//开始读文件....
String s = null; .
//这里一定会出现空指针异常!
s.toString();
System.out.println("he11o world!");
//流使用完需要关闭,因为流是占用资源的。
//即使以上程序出现异常,流也必须要关闭!
//放在这里有可能流关不了。
//fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
} catch(NullPointerException e) {
e.printStackTrace();
} finally {
System.out.println("hello浩克! ");
//流的关闭放在这里比较保险。
// finally中的代码是一定会执行的。
//即使try中出现了异常!
if (fis != null) { //避免空指针异常!
try {
// close()方法有异常,采用捕捉的方式。
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("hello kitty!");
}
}
实例
public class ExceptionTest06 {
public static void main(String[] args) {
/*
以下代码的执行顺序:
先执行try...
再执行finally...
最后执行return(return语句只要执行方法必然结束。)
try {
System.out.println("try...");
return;
} finally {
// finally中的语句会执行。能执行到。
System.out.println("finally...");
}
//这里不能写语句,因为这个代码是无法执行到的。
//System.out.println( "Hello world!");
}
finally面试题
程序输出结果
/* 以下程序输出result是多少??? */ public class ExceptionTest07 { public static void main(String[] args) { int result = m(); System.out.println(result); //100 } /*
java语法规则(有一些规则是不能破坏的):
java中有两条这样的规则:
方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法! )
return语句一旦执行,整个方法必须结束(亘古不变的语法! )
*/
public static int m(){
int i = 100;
try {
// 这行代码出现在int i = 100;的下面, 所以最终结果必须是返回100
// return语句还必须保证是最后执行的,一旦执行,整个方法结束。
return i;
} finally {
i++;
}
}
}
/*
反编译之后的效果
public static int m(){
int i = 100;
int j=i;
i++;
return j;
}
*/
final、finally、finalize有什么区别??
final finally finalize有什么区别?
final关键宇
final修饰的类无法继承
final修饰的方法无法覆盖
final修饰的变量不能重新赋值。
finally关键宇
和try一起联合使用。
finally语句块中的代码是必须执行的。
finalize标识符
是一个object类中的方法名。
这个方法是由垃圾回收器GC负责调用的。
自定义异常
要点
1. SUN提供的JDK内置的异常是不够用的。在实际的开发中,很多业务出现异常之后,JDK中没有相应的异常来处理。
所以需要程序员自定义异常。
2. Java中怎么自定义异常呢?
第一步:编写一个类继承Exception或RuntimeException.
第二步:提供两个构造方法,一个无参数的,一个带有String参数的。
实例
//自定义栈操作异常
public class StackOperationException extends Exception{
public StackOperationException(){}
public StackOperationException(String msg){
super(msg);
}
}
//栈:后进先出
public class Stack{
//使用数组存储数据
//栈可以存储多个引用类型的元素
Object[] elements;
//指向栈顶元素上方的一个帧.
int index;
//栈默认的初始化容量是5
//Constructor
Stack(){
this(5);
}
Stack(int max){
elements = new Object[max];
}
//栈应该对外提供一个压栈的方法
public void push(Object element) throws StackOperationException{
/*
elements[index] = element;
index++;
*/
if(index==elements.length){
//异常
throw new StackOperationException("栈已满!");
}
elements[index++] = element;
}
//栈应该对外提供一个弹栈的方法
public Object pop() throws StackOperationException{ //栈顶的元素往外弹
/*
index--;
return elements[index];
*/
if(index==0){
throw new StackOperationException("栈已空!");
}
return elements[--index];
}
}
异常与方法覆盖
重写之后的方法不能比重写之前的方法抛出更多或是更宽泛的异常,可以更少
class Animal {
public void doSome(){
}
public void doOther() throws Exception{
}
class Cat extends Animal {
//编译正常。
public void doSome() throws RuntimeException{
}
/*
//编译报错。
public void doSome() throws Exception{
}
//编译正常。
public void doOther() {
}
//编泽正常。
public void doOther() throws Exception{
}
*/
//编译正常。
public void doOther() throws NullPointerException{
}
}