JavaSE基础七----<异常>常见的异常,异常处理机制,自定义异常
Posted 小智RE0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaSE基础七----<异常>常见的异常,异常处理机制,自定义异常相关的知识,希望对你有一定的参考价值。
广义上讲,所有不正常的状况都可以归类为异常;
实际上,在Java语言中的异常,指的是在程序执行时出现的异常;
可分为两类:
- Error: Java虚拟机无法解决的严重问题。如:JVM系统内部错误、内存耗尽;一般不编写针对性的代码进行处理。
- Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理;使得程序可以继续运行下去;
常见的异常
- 1.数组下标越界 java.lang.ArrayIndexOutOfBoundsException
//1.数组下标越界 java.lang.ArrayIndexOutOfBoundsException
//数组长度为10;这里并没有a[10]这个下标索引;
int[] a=new int[10];
a[10]=13;
- 2.空指针异常 java.lang.NullPointerException
//2.空指针异常 java.lang.NullPointerException
//字符串s1存入了null
String s1=null;
s1.concat("123");
- 3.数据类型转换异常 java.lang.ClassCastException
//3.数据类型转换异常 java.lang.ClassCastException
//例如向下转型
Object o="123";
Integer s2=(Integer)o;
- 4.数据格式化异常 java.lang.NumberFormatException
//4.数据格式化异常 java.lang.NumberFormatException
//例如给Integer中传入一个内容非数字的字符串"我"
new Integer("我");
- 5.算术异常 java.lang.ArithmeticException
//5.算术异常 java.lang.ArithmeticException
//例如用5除以0
int a=5,b=0;
System.out.println(a/b);
异常的体系
Throwable类有两个直接子类:Exception类、Error类。
Error表示错误,往往程序中并不处理。
Exception表示异常,是所有异常类的父类,是程序员所关心的。
那么接下来就是重点学习Exception:
异常分为运行期异常和编译期异常两种
-
运行期异常
:程序运行时抛除的异常,所有RuntimeException子类都是运行期异常;
(即所有直接或者间接继承RuntimeException的异常类);在编译期间不强制要求处理;
例如:数组下标越界,空指针异常; -
编译期异常
(Checked Exception):除去运行期之外的异常都是编译期异常,也称为检测异常;在编译期间强制要求处理;否则代码不能编译;
例如:IOException , SQLException;
异常处理
Java的异常处理是通过5个关键字来实现的:try、catch、finally、throw、throws
try&catch
写个简单的异常处理:
仅包含try代码块和catch捕获:
在try
代码块中写入可能会出现异常的代码;
在catch
中写入需要捕获的异常类型(仅捕获指定类型的),以及处理异常的代码;
例如算术异常:
public class Demo003 {
public static void main(String[] args) {
//在try代码块中写入可能会出现异常的代码
//在catch中写入需要捕获的异常类型(仅捕获指定类型的),以及处理异常的代码
try{
//先写个算术异常
int a=5;
int b=0;
System.out.println(a/b);
//由于前面出现异常;不会进入下一个代码
System.out.println("下一个代码");
}
//捕获算术异常
catch (ArithmeticException a){
System.out.println("除数不能为0");
}
//后面的程序
//处理完异常后,继续运行后面的程序
System.out.println("后面的程序");
}
}
输出:
除数不能为0
后面的程序
出现两个异常时;
public class Demo003 {
public static void main(String[] args) {
//在try代码块中写入可能会出现异常的代码
//在catch中写入需要捕获的异常类型(仅捕获指定类型的),以及处理异常的代码
try{
//写第二个异常:数组越界异常
int[] array={0,1,3,4};
array[5]=0;
//发现后面的代码块不运行了;
//先写个算术异常
int a=5;
int b=0;
System.out.println(a/b);
//由于前面出现异常;不会进入下一个代码
System.out.println("下一个代码");
}
//负责捕获数组越界异常;
catch(ArrayIndexOutOfBoundsException array){
System.out.println("数组下标越界了");
}
//负责捕获算术异常
catch (ArithmeticException a){
System.out.println("除数不能为0");
}
//后面的程序
//处理完异常后,继续运行后面的程序
System.out.println("后面的程序");
}
}
发现处理完数组下标越界异常后,不再执行算术异常代码以及下一个代码了;处理完数组下标越界异常后直接进入运行之后的程序;
数组下标越界了
后面的程序
如果一开始不确定代码会出现什么异常,可以直接写个捕获Exception类型的异常;
catch(Exception e){
System.out.println("代码有异常");
}
注意:一个try代码块中可以写多个可出现异常的代码;可以对应多个catch代码块,异常类型越大的放在子类的下面.
异常处理中的几个常用方法:
在catch语句处理时,通常需要两种处理;
处理1:给用户的提示;
处理2:程序开发人员需要看到的信息;打印输出异常信息;记录日志,后续会学到通过一些日志组件将异常信息写到文件中去;
- public String getMessage( )
返回此throwable的详细消息字符串。
public class Demo004 {
public static void main(String[] args) {
//在try代码块中写入可能会出现异常的代码
//在catch中写入需要捕获的异常类型(仅捕获指定类型的),以及处理异常的代码
try{
//写个算术异常
int a=5;
int b=0;
System.out.println(a/b);
}
//如果一开始不确定代码会出现什么异常,可以直接写个捕获Exception类型的异常;
catch(Exception e){
//给用户的提示
System.out.println("提示:代码有异常");
//程序开发人员需要看到的信息
//public String getMessage()
// 返回此throwable的详细消息字符串。
System.out.println(e.getMessage());
}
//后面的程序
//处理完异常后,继续运行后面的程序
System.out.println("后面的程序");
}
}
输出:
提示:代码有异常
/ by zero
后面的程序
- public void printStackTrace()
打印输出异常信息到控制台;
public class Demo004 {
public static void main(String[] args) {
//在try代码块中写入可能会出现异常的代码
//在catch中写入需要捕获的异常类型(仅捕获指定类型的),以及处理异常的代码
try{
//写个算术异常
int a=5;
int b=0;
System.out.println(a/b);
}
//如果一开始不确定代码会出现什么异常,可以直接写个捕获Exception类型的异常;
catch(Exception e){
//给用户的提示
System.out.println("提示:代码有异常");
//程序开发人员需要看到的信息
//public void printStackTrace()
//打印输出异常信息
e.printStackTrace();
}
//后面的程序
//处理完异常后,继续运行后面的程序
System.out.println("后面的程序");
}
}
输出:
提示:代码有异常
后面的程序
java.lang.ArithmeticException: / by zero
at com.ff.javaException01.Demo004.main(Demo004.java:15)
- public void printStackTrace(java.io.PrintWriter s)
将异常信息的日志文件打印到文件中去;
(在之后的IO流中会讲解到)
public class Demo004 {
public static void main(String[] args) throws FileNotFoundException {
//在try代码块中写入可能会出现异常的代码
//在catch中写入需要捕获的异常类型(仅捕获指定类型的),以及处理异常的代码
try{
//写个算术异常
int a=5;
int b=0;
System.out.println(a/b);
}
//如果一开始不确定代码会出现什么异常,可以直接写个捕获Exception类型的异常;
catch(Exception e){
//给用户的提示
System.out.println("提示:代码有异常");
//public void printStackTrace(java.io.PrintWriter s)
//将异常信息的日志文件打印到文件中去;
PrintWriter p=new PrintWriter("F:\\\\exception.txt");
e.printStackTrace(p);
p.flush();
p.close();//关闭 流
}
//后面的程序
//处理完异常后,继续运行后面的程序
System.out.println("后面的程序");
}
}
我们会发现控制台并没有变化,实际上它将异常信息存储到了文件中;
这些方法来自Throwable类;而不是Exception类;
finally块
无论程序是否有异常;finally块中的内容总是会执行的,只能有一个finally语句;
- (1)可以不写catch语句;只写try和finally;程序异常时,执行finally后抛出异常信息,后面的程序不再执行;
public class Demo005 {
public static void main(String[] args) {
//可以不写catch语句
//只写try和finally;
// 程序异常时,执行finally后,后面的程序不再执行
try{
//写第二个异常:数组越界异常
int[] array={0,1,3,4};
array[5]=0;
}
finally {
System.out.println("finally块中一定执行");
}
//后面的程序;不会执行
System.out.println("后面的程序");
}
}
输出:
finally块中一定执行
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at com.ff.javaException01.Demo005.main(Demo005.java:13)
- (2)在try语句和catch语句中写return,finally块中的内容也会执行,且优先执行输出;
例如:
首先给该测试方法,输入a=5,b=0;即出现算术异常的状况;输出时发现:优先执行finally块内容,再返回catch中的-1;
public class Demo006 {
public static void main(String[] args) {
Demo006 d=new Demo006();
System.out.println(d.test(5,0));
}
//写个方法
public int test(int a,int b){
try{
return a/b;
}
catch (ArithmeticException num){
//程序异常时,返回-1;
return -1;
}
finally{
System.out.println("finally语句执行");
}
}
}
输出时发现:优先执行finally块内容,再返回catch中的-1;
finally语句执行
-1
给该测试方法,输入a=5,b=1;即正常的状况;输出时发现:优先执行finally块内容,再返回try中的计算得到5;
finally语句执行
5
- (3)在try语句和catch语句中写return,finally块中也写return;不论程序是否异常,直接优先执行finally块中的内容,并且返回值为finally块中的return内容;不执行输出try或者catch中的return;
在上个程序中的finally块中加入返回值return;
finally{
System.out.println("finally语句执行");
return 100;
}
输出:
finally语句执行
100
throws 声明异常
throws声明方法中可能会出现的某种异常;
例如: public void test throws 异常1,异常2,异常3{......}
(1)throws声明异常大多数是编译期(检查期)的异常;如果是声明的是运行期异常,在方法调用处可处理,也可不处理; 如果声明的是编译期异常,在方法调用处,要么声明给调用它的上一级;要么try catch处理;
(2)对于编译期的异常可以throws声明,也可以直接try, catch直接处理;
(3)在调用声明了异常的方法时,可以选择try,catch处理异常,或者选择throws声明给调用它的上级;
(4)在实际应用中,不要在main方法中进行throws声明,没有实际效果;
(5) 一个方法中可以声明多个异常;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
//throws关键字
//throws声明方法中可能会出现的某种异常,作为方法的声明,调用时需要注意
public class Demo007throw {
public static void main(String[] args) {
//实际中;在main方法中就要处理异常了;而不是再次throws声明;
//这里就需要处理异常了;
Demo007throw d=new Demo007throw();
try {
d.test1();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
//方法1,调用方法2;它进行了声明,传给了调用它的方法;
public void test1() throws FileNotFoundException, UnsupportedEncodingException {
test2();
}
//方法2中声明异常,
public void test2() throws FileNotFoundException, UnsupportedEncodingException {
//两个异常代码:
PrintWriter p=new PrintWriter("W:\\\\exception.txt");
"我".getBytes("utf-8");
}
}
(6)在抽象方法中也可以使用throws声明,即便它没有方法体;在子类继承抽象类时,重写声明了抽象方法;那么这时,子类重写的方法中声明的异常类型需要小于等于父类的异常类型
例如:
父类
public abstract class Demo008 {
//抽象方法,这里声明Exception异常
public abstract void test3() throws Exception;
}
子类:
//子类
public class Demo008extend extends Demo008{
//重写test3方法
//且ArrayIndexOutOfBoundsException小于父类中的Exception
@Override
public void test3() throws ArrayIndexOutOfBoundsException {
int[]a= {0,1,2,3};
a[2]=2;
}
}
throw 抛出异常
•throw关键字用于显式抛出异常,抛出的是一个异常类的实例化对象.
•在异常处理中,try语句要捕获的是一个异常对象,那么此异常对象也可以自己抛出。
如: throw new RunTimeException( );
public class Demo001 {
public static void main(String[] args) {
test4(0);
}
public static void test4(int a) {
if (a==0) {
throw new RuntimeException("a不能为0");
//异常被抛出,后面的代码不再执行
}
if(a==1){
a+=2;
System.out.println(a);
}else
System.out.println(a);
}
}
这里传入a=0;抛出异常;
Exception in thread "main" java.lang.RuntimeException: a不能为0
at com.ff.javaException01.throw01.Demo001.test4(Demo001.java:12)
at com.ff.javaException01.throw01.Demo001.main(Demo001.java:8)
对于这样不做处理的运行期异常;输出的是由虚拟机在运行时出现的异常,抛出此类的对象;
public class Demo02 {
public static void main(String[] args) {
System.out.println(10/0);
}
}
//由虚拟机在运行时出现的异常,抛出此类的对象;
/*
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.ff.day10.javaexception.start04throw.Demo02.main(Demo02.java:8)
*/
throws与throw的区别
•throw用于方法体中,用来抛出一个实际的异常对象,使用throw后,要么使用try ,catch捕获异常,要么使用throws声明异常
•throws用于方法声明,用来声明该方法可能发生的异常类型,可以是多个异常类型,用来强制调用该方法时处理这些异常
•抽象方法也可以使用throws
自定义异常
自定义异常就是自己定义的异常类,也就是API中的标准异常类的直接或间接的子类;
实际应用中根据需要,进行自定义;使得异常提示更精确;
-
自定义异常类中往往不写其他方法,只重载需要使用的构造方法;
-
继承Exception,在方法中使用throw抛出后,必须在方法中try-catch或throws抛出;
例如自定义一个成绩输入异常类;
//成绩输入异常类
public class GradeException extends Exception{
//构造方法
public GradeException() {
}
public GradeException(String message) {
super(message);
}
}
使用它:
public class Demo002 {
public static void main(String[] args) {
Demo002 d=new Demo002();
//使用try,catch处理异常
try {
d.grade(200);
} catch (GradeException e) {
e.printStackTrace();
}
}
//一个判断成绩的方法;声明了异常
public String grade(int num) throws GradeException {
if(num>150){
//抛出成绩输入异常
throw new GradeException("成绩输入异常!");
}
if(num==100){
return "好!";
}else
return "不行!";
}
}
输出:
com.ff.javaException01.throw01.GradeException: 成绩输入异常!
at com.以上是关于JavaSE基础七----<异常>常见的异常,异常处理机制,自定义异常的主要内容,如果未能解决你的问题,请参考以下文章