一、异常exception
1、什么是异常,以及Java提供的异常处理机制
程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常
java语言提供了异常的处理方式,如果程序执行过程中出现了不正常情况,
java把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对程序进行修改,让程序更加的健壮
2、异常以类和对象的形式存在
异常在Java中以类的形式存在,每一个异常类都可以创建异常对象
// 通过“异常类”实例化“异常对象”
NumberFormatException nfe = new NumberFormatException("数字格式化异常!");
// java.lang.NumberFormatException: 数字格式化异常!
System.out.println(nfe);
// 通过“异常类”创建“异常对象”
NullPointerException npe = new NullPointerException("空指针异常发生了!");
//java.lang.NullPointerException: 空指针异常发生了!
System.out.println(npe);
3、遇到异常,Java会自己new对象
/*
程序在这里除以0,
发生了ArithmeticException异常,
底层new了一个ArithmeticException异常对象,
然后抛出了,由于是main方法调用了100 / 0,
所以这个异常ArithmeticException抛给了main方法,
main方法没有处理,将这个异常自动抛给了JVM。VM最终终止程序的执行。
ArithmeticException 继承 RuntimeException,属于运行时异常。
在编写程序阶段不需要对这种异常进行预先的处理。
*/
System.out.println(100 / 0);
// 这里的HelloWorld没有输出,没有执行。
System.out.println("Hello World!");
二、异常处理机制
1、异常的处理结构
Throwable继承自Object超类
// Throwable(可抛出的) 不管是错误还是异常都是可以抛出的
Error和Exception继承自Throwable
// Error是错误类,只要有错误发生,Java程序只有一个结果,就是终止程序执行,退出jvm
// 错误是不能处理的
// Exception是异常类
Exception分为:Exception的直接子类、RuntimeException
编译时异常
所有Exception的直接子类,都叫做编译时异常。编译时异常不是在编译阶段发生的
编译时异常是表示必须在编写程序的时候预先对这种异常进行处理,如果不处理编译器报错。
运行时异常
所有的RuntimeException及子类都属于运行时异常。运行时异常在编写程序阶段,你可以选择处理,也可以不处理。
2、编译时异常和运行时异常的区别
编译时异常发生概率高,编译时异常又被称为受检异常或者受控异常
运行时异常发生概率低,运行时异常又被称为未受检异常或者未受控异常
注意::所有异常都是发生在运行阶段的
3、异常处理的两种方式
1)第一种方式:
在方法声明位置上,使用throws关键字看,抛给上一级(异常的上抛)
谁调用我就抛给谁
注意:一般不建议抛给main方法,main方法中最好使用try catch
public class ExceptionTest04 {
public static void main(String[] args) {
// 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!!!!");
}
}
// 第一种:使用throw关键字
public class ExceptionTest04 {
// 抛给调用者
public static void main(String[] args) throws ClassNotFoundException{
doSome();
}
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome!!!!");
}
}
注意注意:throws抛异常时可以抛出该异常,也可以抛出该异常的父类异常,也可以抛出所有异常
// 抛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{
1)第二种方式:
使用try... catch语句进行异常的捕捉(异常的捕捉)
注意:Java中 异常发生之后如果一直上抛,最终抛给了main方法,main方法继续向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果:终止java程序的执行。
// 第二种try...catch
public static void main(String[] args) {
try {
// 尝试
doSome();
} catch (ClassNotFoundException e) {// e是为这个异常取的名字
// catch是捕捉到异常之后走的分支
System.out.println("类没有发现异常");
e.printStackTrace();
}
}
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome!!!!");
}
}
注意注意:只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行。另外需要注意,try语句块中的某一行出现异常,该行后面的代码不会执行
4、try...catch的深入了解
1)catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型,也可以抛出Exception
2)catch可以写多个。建议catch的时候,精确的一个一个处理。这样有利于程序的调试
3)catch写多个的时候,从上到下,必须遵守从小到大
public class ExceptionTest07 {
public static void main(String[] args) {
try {
//创建输入流
FileInputStream fis = new FileInputStream("D:document\\风格.pdf");
//读文件
fis.read();
} catch(FileNotFoundException e) {
System.out.println("文件不存在!");
} catch(IOException e){
System.out.println("读文件报错了!");
}
}
}
// JDK8的新特性
// 可以 或 异常,这个异常或者那个异常
try {
//创建输入流
FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
// 进行数学运算
System.out.println(100 / 0);
// 这里这些异常可以 或
} catch(FileNotFoundException | ArithmeticException | NullPointerException e) {
System.out.println("文件不存在?数学异常?空指针异常?都有可能!");
}
5、上抛和捕捉怎么选择
如果希望调用者来处理,就使用上抛。其他情况使用捕捉
6、异常对象常用方法
获取异常简单的描述信息:
String msg = exception.getMessage();
打印异常追踪的堆栈信息:
exception.printStackTrace();
// 这里只是为了测试getMessage()方法和printStackTrace()方法。
// 这里只是new了异常对象,但是没有将异常对象抛出。JVM会认为这是一个普通的java对象。
NullPointerException e = new NullPointerException("空指针异常");
// 获取异常简单描述信息:这个信息实际上就是构造方法上面String参数。
String msg = e.getMessage(); //空指针异常
System.out.println(msg);
// 打印异常堆栈信息
// java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的。
e.printStackTrace();
7、try catch中finally关键字
1)
在finally自居中的代码时最后执行的,并且一定会执行的,即使try语句块中的代码出现异常
必须和try catch一起使用
2)finally语句通常使用在哪些情况下
通常在finally语句块中完成资源的释放/关闭。
因为finally中的代码比较有保障。即使try语句块中的代码出现异常,finally中代码也会正常执行。
3)退出jvm之后finally就不执行了
System.exit(0);
public class ExceptionTest10 {
public static void main(String[] args) {
FileInputStream fis = null; // 声明位置放到try外面。这样在finally中才能用。
try {
// 创建输入流对象
fis = new FileInputStream("D:\\JavaSE进阶-01-面向对象.pdf");
// 开始读文件....
String s = null;
// 这里一定会出现空指针异常!
s.toString();
System.out.println("hello 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!");
}
}
三、自定义异常
1、为什么自定义异常
SUN提供的JDK内置的异常肯定是不够的用的
在实际的开发中,有很多业务,这些业务出现异常之后,JDK中都是没有的和业务挂钩的。那么异常类我们可以自己定义
2、怎么定义异常
第一步:编写一个类继承Exception或者RuntimeException
第二步:提供两个构造方法,一个无参数的,一个带有String参数的
// 就是这样的结构,这样写就行,根据sun公司的源代码来这样写
public class MyException extends Exception{ // 编译时异常
public MyException(){
}
public MyException(String s){
super(s);
}
}
/*
public class MyException extends RuntimeException{ // 运行时异常
}
*/
public class ExceptionTest15 {
public static void main(String[] args) {
// 创建异常对象(只new了异常对象,并没有手动抛出)
MyException e = new MyException("用户名不能为空!");
// 打印异常堆栈信息
e.printStackTrace();
// 获取异常简单描述信息
String msg = e.getMessage();
System.out.println(msg);
}
}
3、怎么使用自定义异常
trow手动抛出异常
// 先定义一个异常
/**
* 栈操作异常:自定义异常
*/
public class MyStackOperationException extends Exception{ // 编译时异常
public MyStackOperationException(){
}
public MyStackOperationException(String s){
super(s);
}
}
// 一个模拟栈的类
// 其中的一个方法
/**
* 压栈的方法
* @param obj 被压入的元素
*/
public void push(Object obj) throws MyStackOperationException {
if(index >= elements.length - 1){
/* 栈满了 这也算是一个异常,那我们就可以自定一个异常类来这个让我们使用
以前的写法
System.out.println("压栈失败,栈已满");
return;
*/
// 创建异常对象
//MyStackOperationException e = new MyStackOperationException("压栈失败,栈已满!");
// 手动将异常抛出去!
//throw e; //这里捕捉没有意义,自己new一个异常,自己捉,没有意义。栈已满这个信息你需要传递出去。
// 合并
throw new MyStackOperationException("压栈失败,栈已满!");
}
index++;
elements[index] = obj;
System.out.println("压栈" + obj + "元素成功,栈帧指向" + index);
}
标签:--,System,public,catch,println,JavaSE,异常,机制,out From: https://www.cnblogs.com/hyy-0/p/17621849.html