异常概述
假设在一个 Java 程序运行期间出现了一个错误。这个错误可能是由于文件包含了错误
信息,或者网络连接出现问题造成的,也有可能是因为使用无效的数组下标, 或者试图使用
一个没有被赋值的对象引用而造成的。用户期望在出现错误时, 程序能够采用一些理智的行
为。——《Java核心技术卷一》
简单来说,异常就是程序出现的错误,有时是程序编写时出现的错误,这是可以避免的,需要我们处理的异常,一种是是系统自身的问题,与我们编写的程序无关,是无法避免的的。Java使用异常的处理机制来处理这些问题。
Java的继承体系:
所有的异常都是由Throwable演化而来。
异常的分类:
error:Java运行时系统内部错误和资源耗尽错误,这个异常我们无法处理,因为不是编写程序的问题。
Exception:在Exception中,分为运行时异常RuntimeException和检查性异常,运行时异常是在程序运行时才会发现的异常,检查性异常在编译期就不能通过,需要立刻处理的异常。
show code :
运行时异常,编译时可以通过。
public class Demo01 {
public static void main(String[] args) {
int a=1;
int b=0;
try {
System.out.println(a/b);
} catch (Exception e) {
System.out.println("除数不能为0");
}
}
}
运行结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Demo01.main(Demo01.java:6)
演示一个检查性异常:如果不处理直接就编译不通过。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
* demo演示一个编译期异常,就算本身代码没有任何错误,也需要处理的异常。
*/
public class ExceptionDemo03 {
public static void main(String[] args) {
String s="2020-4-25";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
try {
Date d=sdf.parse(s);
System.out.println(d);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
异常的处理的方案。
第一种处理异常的方案是使用try…catch语句块。
我们把可能发生错误的代码放进catch里面。如果代码发生错误,就转移到catch语句块里面。
查看实例:
package ExceptionDemo;
/*
* 注意:在trycatch里面,一旦匹配上相应的catch,那么就跳到catch里面执行,然后整个try... catch语句就结束了。
* 父类是Excption,是万能匹配,但是尽量要具体的类,效率高一点。
* 在多个catch时,平级的异常谁先谁后无所谓,如果出现了子父类关系,那么父类要放在子类catch的下面。
*/
/*
* 异常处理方法:
* A:一个异常就一个trycatch
* B:多个异常:
* 1:写多个try catch
* 2:写一个try多个catch
* try{
* .....
* }
* catch(异常类名1 变量名1){}
* catch(异常类名2 变量名2){}
* .......
*/
public class ExceptionDemo01 {
public static void main(String[] args) {
//method2();
method3();
}
//演示多个异常处理
public static void method3()
{
try {
int a=1;
int b=0;
System.out.println(a/b);
int [] arr = {1,2,3};
System.out.println(arr[3]);
String s=null;
System.out.println(s.length());
} catch (ArithmeticException e) {
System.out.println("除数不能为0");
}catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常");
}
catch (NullPointerException e) {
System.out.println("空指针异常");
}
System.out.println("over");
}
//两个异常
public static void method2()
{
try {
int a=1;
int b=0;
System.out.println(a/b);
} catch (ArithmeticException e) {
System.out.println("除数 不能为0");
} /*
* catch (ArrayIndexOutOfBoundsException e) { System.out.println("数组越界异常"); }
*/
try {
int [] arr= {1,2,3};
System.out.println(arr[4]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数字越界异常");
}
System.out.println("over");
}
}
在try…catch语句块中,还有一个是try…catch…finally体系。finally用于释放资源,常用于数据库和Io的操作。
注意:finally语句一定会执行。但是 注意:在虚拟机退出后就不能执行了。(System.exit(0));
showcode:
/*
* 格式:try ...catch... finally..
*/
public class FinallyDemo01 {
public static void main(String[] args) {
try {
int a=1;
int b=0;
System.out.println(a/b);
} catch (Exception e) {
e.printStackTrace();
//虚拟机退出
//System.exit(0);
}
finally {
System.out.println("听说finally控制的语句块一定会执行");
}
System.out.println("over");
}
}
结果:
java.lang.ArithmeticException: / by zero
听说finally控制的语句块一定会执行
over
at finallyDemo.FinallyDemo01.main(FinallyDemo01.java:17)
面试题:如果catch里面有catch语句,那么finally还会不会执行。
- 如果会,那么是在return前还是return后。
- 会,前。
演示代码:
public class FinallyDemo02 {
public static void main(String[] args) {
System.out.println(getInta());
}
public static int getInta()
{
int a=1;
try{
System.out.println(a/0);
a=20;
}catch (ArithmeticException e) {
System.out.println("这里是catch");
a=30;
return a;
}
finally{
a=40;
System.out.println("这里是finally");
}
return a;
}
}
结果:
这里是catch
这里是finally
30
通果System语句来追踪代码执行的步骤。
异常的处理方案二:throws
谁调用,谁处理。如果不处理,就继续在方法上抛出,直到抛给main方法。但是尽量 不要抛给main方法,因为没有处理还是要出错的
- 格式:
- 在方法后throws 异常类型
- 注意:编译期异常抛出,调用者必须处理,并且在方法上throws 。运行时异常方法不强制需要在方法上抛出,调用者可以不用处理,也可以处理。
查看实例:注意那些需要try…catch,那些需要throws。
public class ExceptionDemo05 {
public static void main(String[] args) {
//对method1方法异常的处理,必须处理,因为是检查性异常。
try {
method1();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//方法二异常可以处理也可以不处理,不处理也可以通过,虽然会出错。
method2();
}
//编译期异常的抛出
public static void method1() throws ParseException
{
String s="fkhdasf";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date d=sdf.parse(s);
System.out.println(d);
}
//运行时异常的抛出.
public static void method2() throws ArithmeticException
{
int a=1;
int b=0;
System.out.println(a/b);
}
}
自定义异常
我们自定义异常很简单,只需要继承就可以了,如果需要写一个运行时异常,那么就继承RunTimeException。如果需要自定义一个检查性异常,就继承Exception.
查看实例:
//定义一个编译期异常
public class MyException01 extends Exception{
public MyException01()
{
}
public MyException01(String message)
{
super(message);
}
}
//定义一个运行期异常
class RunTimeExceptionDemo extends RuntimeException{
public RunTimeExceptionDemo()
{
}
public RunTimeExceptionDemo(String message) {
super(message);
}
}
测试类:
public class TestMyException {
public static void main(String[] args) {
//处理自定义的编译期异常,需要处理
try {
method1();
} catch (MyException01 e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//并不必须要处理
method2();
}
//使用编译期异常,需要在方法上抛出
public static void method1() throws MyException01
{
int a=1;
int b=0;
if(b==0)
{
throw new MyException01("除数补不能为0");
}else
{
System.out.println(a/b);
}
}
//使用运行时异常,并不需要在方法上出。
public static void method2()
{
int a=1;
int b=0;
if(b==0)
{
throw new RunTimeExceptionDemo();
}else{
System.out.println(a/b);
}
}
}
自定义异常的注意事项:
-子类重写父类方法时,子类方法必须抛出相同的异常或者父亲异常的子类。
-如果父类抛出了多个异常,子类重写父类时,子类只能抛出相同的异常或者他的子集,子类不能抛出父类没有的异常。
-如果被覆盖的方法没有异常抛出,那么子类方法决不能抛出异常,如果子类方法有异常抛出,那么子类只能try,不能throws.
以上就是简单的关于异常的总结,感谢阅读。
参考:《Java核心基础卷一》
https://www.cnblogs.com/Qian123/p/5715402.html