异常
异常的概念
在使用计算机语言开发项目时,即使程序员将代码写的十分严谨,在系统运行的时候也可能会出现错误,以为很多问题不是靠代码可以解决的.例如:客户输入的格式,文件是否存在,网络问题等等.
**异常概念:**在Java语言中,将程序执行中发生的不正常情况称为“异常”.
广义上异常:程序出现的所有不正常的
狭义上异常:是指程序在运行过程中出现的不正常现象,可以通过异常处理机制解决的
广义的异常可以分为两类:
Error:(又称错误) java虚拟机无法解决的问题.一般不编写代码处理.
Exception:(程序异常,狭义的异常)因编程错误或者是偶然的外在因素导致的一般性问题,可以编写针对性代码进行解决处理的
public class ExceptionDemo1 {
//错误代码演示
public static void main(String[] args) {
ExceptionDemo1 demo1 = new ExceptionDemo1();
demo1.sum(666);
}
public int sum (int a ){
return sum(a-1);
}
//结果显示:Exception in thread "main" java.lang.StackOverflowError 表示栈溢出错误
}
//数组越界异常
public static void main(String[] args) {
int[] a=new int[5];
a[5]=16;
//结果显示为:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at com.ffyc.exceptions.ExceptionDemo1.main(ExceptionDemo1.java:17)
// 异常 在"main"线程中,java.lang包下的ArrayIndexOutOfBoundsException类异常 位置在com.ffyc.exceptions.ExceptionDemo1中的main函数中的17行
//表示数组越界,在编译期间是没有错误的,在运行时发生了异常
//在运行时程序遇到未处理的异常时虚拟机就会停止运行.
}
//算数异常
public static void main(String[] args) {
int a=10;
int b=0;
System.out.println(a/b);
}
//结果:Exception in thread "main" java.lang.ArithmeticException: / by zero
// at com.ffyc.exceptions.ExceptionDemo1.main(ExceptionDemo1.java:28)
//类型转换异常
public static void main(String[] args) {
Object obj = "ajgh";
Integer in = (Integer)obj;
}
//结果:Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
// at com.ffyc.exceptions.ExceptionDemo1.main(ExceptionDemo1.java:32)
//空指针异常
public static void main(String[] args) {
String str = null;
System.out.println(str.length());
}
//结果:Exception in thread "main" java.lang.NullPointerException
// at com.ffyc.exceptions.ExceptionDemo1.main(ExceptionDemo1.java:36)
对于这些异常,一般有两种解决方法:一是遇到异常就终止程序的运行。另一种方法是由程序员在编写程序时,就考虑到异常的检测、异常消息的提示,以及异常的处理。
异常的体系
异常分为运行期异常和编译期异常两种.
运行期异常,就是在运行期间抛出的异常,RuntimeException的所有子类都是运行期间异常.如以上提到的数组越界,算数异常,空指针异常等等.
编译期间异常,也叫检查异常,在编译时就必须要对其进行处理的.
public static void main(String[] args) {
String str = "ajgag";
byte[] s = str.getBytes("utf-8");
}
//以上代码是没有问题的,但是getBytes是编译不通过的,需要使用try-catch 或者 向上抛出异常
public static void main(String[] args) {
String str = "ajgag";
try {
byte[] s = str.getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
//只要是在写代码的时候就需要处理的问题都称之为编译期异常
异常处理
异常处理通过5个关键字来实现,try,catch,finally,throws,throw
基本语法
try{
可能会发生异常的代码
}catch(异常类型 引用名){
异常处理代码
}finally{
必须执行代码
}
try:用于检测不安全的代码,即就是try可以发现异常.当try代码块中的任何一条语句发生了异常,其代码块后 面的代码都不执行,程序将直接跳转到异常处理代码块中,也就是catch代码块.
catch:把抓到的类型匹配的异常捕获,保证程序能继续运行下去catch语句必须跟在try语句后面,称为捕获异常,即异常处理函数,一个try后面可以跟多个catch,分别捕获不同类型的异常,跟多个catch时需要注意的是异常类型需要从子类往父类的顺序写,否则将会出现错误.
public static void main(String[] args) {
int a=10;
int b=0;
try {
int c=a/b; //发现异常
}catch (ArithmeticException e){
/*
ArithmeticException 异常的类型,如果此处的异常类型与
try中发生的异常不同时将不会进入到此catch中,也就不会被
此catch处理,如果没有匹配的异常类型,那么所发生的异常将不会被处理程序将会终止
*/
System.out.println("算数异常");//处理异常,以保证后面的代码可以继续执行
}
System.out.println("执行后面的代码");
}
//一个try可以跟多个catch,但是catch必须有子类到父类
public static void main(String[] args) {
int a=10;
int b=2;
try {
int c=a/b;
String str = null;
System.out.println(str.length());
}catch (ArithmeticException e){
System.out.println("算数异常");
}catch (NullPointerException n) {
System.out.println("空指针异常");
}catch (Exception ex){
System.out.println("系统忙,稍后再试");
}
System.out.println("后面的代码");
}
finally: 此代码块中的代码块总是会执行,并且只能有一个finally语句.
//try-catch组合
public static void main(String[] args) {
int a=10;
int b=2;
try {
int c=a/b;
String str = null;
System.out.println(str.length());
}catch (ArithmeticException e){
System.out.println("算数异常");
}catch (NullPointerException n) {
System.out.println("空指针异常");
}catch (Exception ex){
System.out.println("系统忙,稍后再试");
}finally {
System.out.println("finally");
}
System.out.println("后面的代码");
}
/*
空指针异常 //捕获的异常
finally //执行finally语句
后面的代码
*/
/*此处异常已经被finally之前的catch捕获处理,程序可以向后继续执行*/
//try-finally组合
public static void main(String[] args) {
try {
String str = null;
System.out.println(str.length());
}finally {
System.out.println("finally");
}
System.out.println("后面的代码");
}
/*结果:
Exception in thread "main" java.lang.NullPointerException
at com.ffyc.exceptions.ExceptionDemo1.main(ExceptionDemo1.java:31)
finally
*/
/*由于异常并未catch捕获处理,所以程序将会抛出异常并停止,但是finally是总能执行的代码块,所以会输出finally*/
public class ExceptionDemo1 {
public static void main(String[] args) {
System.out.println(ExceptionDemo1.test());
}
public static int test(){
int a=10;
int b=0;
try {
return a/b;
}catch (ArithmeticException ari){
System.out.println("算数异常");
return 0;
}finally {
System.out.println("最终执行代码");
}
}
/*结果:
算数异常 //此处之后应执行return 0; 但finally是总能执行的,先执行finally在return
最终执行代码
0
*/
throws:定义一个方法的时候可以使用throws关键字声明,表示此方法不处理异常,而交给方法调用者,让调用者进行处理.
任何方法都可以使用throws关键字,一个throws可以跑出多种异常.
public void test throws 异常1,异常2,异常3{
}
注意:1.使用throws抛出异常时,此异常一般直接或间接继承Exception,即就是编译期异常.
2.子类重写父类的方法时,子类方法不能声明抛出比父类类型更大的异常(针对编译期异常).
3.使用了throws的方法,在被调用的时候必须处理声明的异常,要么使用try-catch,要么继续使用throws.
import java.io.UnsupportedEncodingException;
public class Demo4{
public static void main(String[] args){
try {
Demo4.test2();//调用test2,仍然需要处理异常,main是最顶层的放法,一般不能够继续向上抛出异常,使用try-catch处理.
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/*
throws + 编译期异常 在调用该方法时,会显性的提示,在编译时就要进行处理异常
throws + 运行期异常 在编译期间不会显性的提示需要处理异常(需要看个人经验)
*/
public static void test1() throws UnsupportedEncodingException {
String s = null;
s.getBytes("utf-8");//此处需要使用throws抛出异常
}
public static void test2() throws UnsupportedEncodingException {
Demo4.test1();//调用论了test1,需要对test1中的异常进行处理,此处继续选择throws抛出异常
}
}
//注:如果在底层就使用try-catch处理,上层在调用的时候是不知道底层出现了异常的,此时上层就不用再处理
//一般的在底层的方法通常会用throws进行抛出,因为在底层就处理上层是不知道的,上层仍在调用,导致返回的结果不正确
throw:用于显式的抛出异常,抛出的时候是抛出一个异常类的实例化对象.在方法中显式的抛出一个异常类的对象,表示此处实际发生了异常.
new + 有参构造方法(“异常原因”)
import java.io.UnsupportedEncodingException;
public class Demo3 {
public static void main(String[] args) {
try {
test(110);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();//在控制台打印异常信息 开发测试时使用,以便于更准确找到错误
System.out.println(e.getMessage());//getMessage();属于Throwable中的方法,用于打印throw抛出的异常原因
}
}
public static String test(int socer) throws UnsupportedEncodingException {
if(socer<0||socer>100)
throw new UnsupportedEncodingException("成绩错误");//表示出现异常,程序是不会继续向下执行的.
if (socer>=90){
return "a";
}
else {
return "b";
}
}
}
//注:throws是声明异常
// throw是抛出异常
自定义异常
为什么需要自定义异常类?
java中提供的是针对语法上的异常类,在多数项目实际情况下异常不单单是语法上的.例如成绩输入的异常,
因此我们可以自己定义一个异常类,在实际开发过程中,可以根据自己需求,自己开发一个异常类,用于表示某一类问题.
自定义一个异常类其实只需要写一个类继承某个异常类,在编写有参构造和无参构造,在分别调用父类构造方法就行了
//自定义一个分数异常类
public class ScoreException extends Exception {
public ScoreException() {
super();
}
public ScoreException(String message) {
super(message);
}
}