异常概述
用户能够解决的叫Exception,通过异常处理给出提示,让用户知道异常原因,具体操作是:通过try去检测可能出现异常的代码,程序出现异常时会产生一个异常对象,再通过catch的参数去匹配异常类型,进而执行{}内处理该异常的代码;不能解决的叫Error,比如堆栈溢出,不是用户的错,此时需要程序员修改代码
package com.xyl.contacts;
public class ErrorTest {
public static void main(String[] args) {
//main(args);//StackOverflowError栈溢出
Integer[] i=new Integer[1024*1024*1024];//OutOfMemoryError堆溢出
}
}
只讨论Exception
运行时异常可以不处理,编译时异常必须处理
常见异常
异常处理
抓抛模型
try-catch-finally
package com.xyl.contacts;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.junit.Test;
/**
*
* @Descryption 抓抛模型实例
* @author xyl Email:l1264009784@163.com
* @version
* @date 2021年3月7日下午12:49:55
*
*/
public class ExceptionTest {
private FileInputStream fileInputStream;
@Test
public void test1() {
int i = 0;
try {
i = Integer.parseInt("abc");
System.out.println("测试点1");
} catch (NumberFormatException e) {
System.out.println("出现数值转换异常");
System.out.println("正在处理");
System.out.println(e.getMessage());
e.printStackTrace();
} catch (NullPointerException e) {
System.out.println("出现空指针异常,正在处理");
System.out.println(e.getMessage());
e.printStackTrace();
} catch (Exception e) {
System.out.println("其他异常处理");
System.out.println(e.getMessage());
e.printStackTrace();
}
System.out.println("测试点2");
}
@Test
public void test2() {
try {
File file = new File("hello.txt");
fileInputStream = new FileInputStream(file);
int read = fileInputStream.read();
while(read!=-1) {
System.out.print((char)read);
read = fileInputStream.read();
}
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}finally {
try {
if(fileInputStream!=null)
fileInputStream.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
try是检测,catch方法参数是配对,catch方法体是处理异常,通常提示异常原因,finally是关闭资源;如果不写异常处理语句就系统就只会抛出一个异常对象,所以说异常处理主要是为了提示异常原因以及关闭资源
编译时异常就是编译就能检查到的,运行时异常只有运行才会发现,比如空指针异常;文件不存在异常为编译时异常,通过异常处理并没有解决文件不存在的根本问题,只是会提示下你,但是运行时还是会出现空指针,此时你的代码写的时没错的,毕竟用户的输入你也控制不了,程序运行时就会出现空指针异常的提示,也就是说编译时异常的处理是为了运行时异常时知道错误原因
Error不能异常处理,因为处理不了;运行时异常不需要处理,因为运行时异常太多了,比如每个引用变量都可能是空指针null,到处异常处理会显得代码臃肿;编译时异常一定要处理,否则编译就过不了,更别谈运行,编译时异常不是代码错了,可能是输入输出的问题,只能等到运行时才知道
new FileInputStream(file);文件没创建成功时也会出异常,这种就没必要处理,进而导致的空指针异常都是运行时异常,这种异常太多就没必要处理,运行时异常需要直接处理,不需要去trycatch了
throws
方法内不处理异常,方法抛出异常,使得方法通过编译,但是使用该方法的调用者还是得处理异常或者继续抛出异常
package com.xyl.contacts;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Override {
public static void main(String[] args) {
method2(new SubClass());
}
public static void method2(SupperClass sc) {
try {
sc.method();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
/*
* 子类抛出异常类型要小于父类
* 原因是子类调用父类方法执行的是被子类复写过得方法,该方法会抛出异常
* 而父类只能接收比父类抛出异常,也就是method方法类处理异常范围小得异常
*
* 另外,父类不抛异常,子类就不能抛,只能自己处理异常,因为没人接受你抛出得异常,也就没人处理异常
*/
class SupperClass{
public void method() throws IOException{
}
}
class SubClass extends SupperClass{
public void method() throws FileNotFoundException{
}
}
手动抛出异常
package com.xyl.contacts;
public class StudentTest {
public static void main(String[] args) {
Student s=new Student();
try {
s.setAge(-12);
} catch (Exception e) {
// TODO 自动生成的 catch 块
//e.printStackTrace();
System.out.println(e.getMessage());
}
System.out.println(s);
}
}
class Student{
int age;
public int getAge() {
return age;
}
public void setAge(int age) throws Exception{
if(age>0)
this.age = age;
else
//throw new RuntimeException("输入有误");
throw new Exception("输入有误");//手动抛出异常对象的目的是使得出现异常提示
//不处理程序就结束,也可以通过异常处理使得程序继续执行
}
@Override
public String toString() {
return "Student [age=" + age + "]";
}
}
自定义异常类
package com.xyl.contacts;
class MyException extends Exception {
static final long serialVersionUID = 13465653435L;//识别同一个类的码
public MyException() {
}
public MyException(String message) {
super(message);
}
}
package com.xyl.contacts;
public class StudentTest {
public static void main(String[] args) {
Student s=new Student();
try {
s.setAge(-12);
} catch (MyException e) {
// TODO 自动生成的 catch 块
//e.printStackTrace();
System.out.println(e.getMessage());
}
System.out.println(s);
}
}
class Student{
int age;
public int getAge() {
return age;
}
public void setAge(int age) throws MyException{
if(age>0)
this.age = age;
else
//throw new RuntimeException("输入有误");
//throw new Exception("输入有误");//手动抛出异常对象的目的是使得出现异常提示
//不处理程序就结束,也可以通过异常处理使得程序继续执行
throw new MyException("年龄没有负数");
}
@Override
public String toString() {
return "Student [age=" + age + "]";
}
}
异常处理练习
进入方法A、用A方法的finally、制造异常
进入方法B、调用方法B的finally
package com.xyl.contacts;
public class EcDef extends Exception{
static final long serialVersionUID = 1346565343511L;
public EcDef() {
}
public EcDef(String message) {
super(message);
}
}
package com.xyl.contacts;
public class EcmDef {
public static void main(String[] args) {
// TODO 自动生成的方法存根
try {
int parseInt = Integer.parseInt(args[0]);
int parseInt2 = Integer.parseInt(args[1]);
int result = ecm(parseInt,parseInt2);
System.out.println(result);
} catch (EcDef e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}catch(NumberFormatException e) {
//e.getMessage();
e.printStackTrace();
System.out.println("数值转换异常");
}catch(ArrayIndexOutOfBoundsException e) {
//e.printStackTrace();
System.out.println("数组下标越界");
}catch(ArithmeticException e) {
System.out.println("除数不能为0");
}
}
public static int ecm(int i,int j) throws EcDef{
if(i<0||j<0) {
throw new EcDef("不能输入负数");//如果此地不抛出异常,用sout()代替就会继续执行程序,因为输入有误,继续执行没有意义,所以要抛出异常终止程序
}
return i/j;
}
}