java基础知识——异常
6.5.1异常
异常就是不正常的情况。在现实生活中也会出现不能随人愿的一些不正常的情况。比如每天上班过程中不一定都是交通拥堵的。碰到了交通拥堵的情况之后我们可以选择其他的办法解决。程序往往有可能会出现运行不正常的行为和状态,我们就称为异常
6.5.2异常处理
- 异常处理是面向对象语言区别于面向过程语言的重要标志,异常的出现,可以使我们编写的程序变得强大并安全,简而言之,异常是处理错误的机制,程序的不正常的行为和状态
6.5.3程序模拟异常
代码演示:
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
System.out.println("请输入第一个被除数:");
int a=input.nextInt();
System.out.println("请输入第二个除数数");
int b=input.nextInt();
int c=a/b;
System.out.println("c为多少:"+c);
System.out.println("程序运行中");
}
}
- 这个程序在执行过程中不可避免的会出现一些问题,不正常的情况
//执行结果:
请输入第一个被除数:
12
请输入第二个除数数
a
//当用户输入的非数字时,程序就会报异常
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Unknown Source)
at java.util.Scanner.next(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at Test5.main(Test5.java:8)
- 程序碰到了不正常情况之后,由于程序员没有预处理的解决办法,导致JVM自己解决。
- JVM解决异常的办法是:
- 停止程序
- 将异常信息包装到一个类中告知异常原因打印异常在当前代码中的行数
6.5.4解决办法
利用if做判断来解决
代码演示:
import java.util.Scanner;
public class Test2 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
System.out.println("请输入第一个被除数:");
//用到Scanner类中的方法,判断是否是int类型的值输入
if(input.hasNextInt()) {
int a=input.nextInt();
System.out.println("请输入第二个除数");
if(input.hasNextInt()){
int b=input.nextInt();
if(b!=0) {
int c=a/b;
System.out.println("c的为多少:"+c);
}
System.out.println("请不要输入零");
}else {
System.out.println("你输入的有错误,请重新输入!");
}
}else {
System.out.println("你输入的有错误,请重新输入!");
}
}
}
- 通过在编写程序时编写大量的if判断来规范用户的输入内容。保证程序不会出现异常。
- 出现大量的判定条件导致程序会显得格外臃肿;
- 程序员永远无法预知用户会输入什么,导致我们编写的判断总会有疏漏的点。
6.5.5异常解决机制
- java为了能够让程序可以更加健壮以及更加安全,通过异常解决机制将一个可能后期出现问题的程序进行一系列的校验或者是补足安全隐患。
异常机制分为:
try-catch
try-catch-finally
throws
throw
throw-throws
6.5.6try-catch-finally
i.try-catch
- try-catch处理异常,适合处理程序员可以控制和用户输入有误的情况,以起到程序开发顺利进行和避免没有必要的情况发生
(1)语法格式:
try{
//可能出现的异常代码
}catch(异常类型){
//解决办法
}
(2)代码演示:
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
try {
System.out.println("请输入第一个被除数:");
int a=input.nextInt();
System.out.println("请输入第二个除数数");
int b=input.nextInt();
int c=a/b;
System.out.println("c为多少:"+c);
}
//我们知道程序可能会出现的异常
catch (InputMismatchException e) {
System.out.println("程序存在异常");
}
//关闭Scanner的输出资源
input.close();
System.out.println("程序运行中");
}
}
(3)执行顺序
- 执行try中的代码块
- 如果出现了异常信息去匹配catch中声明的异常,如果没有匹配上则当前异常信息交由JVM处理。如果匹配上了则执行catch中的代码块
- 继续执行后续代码
(4)注意事项:
- catch中的异常一定要和可能出现的异常的匹配上,否则交由JVM处理。
- 一定不要再catch中编写逻辑代码来"自作聪明"的解决当前异常信息。
- try-catch是java解决异常的一种手段,但是我们都是希望程序没有任何异常的。
- 建议不要使用一个父类的异常来在catch中声明,会将子类异常覆盖掉,导致后期的维护边的比较棘手。
ii.try-多重catch
(1)语法格式:
try{
//可能出现的异常代码
}catch(异常类型1){
//解决办法1
}catch(异常类型2){
//解决办法2
}。。。。。。。。。{
//解决办法n
}
(2)
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
try {
System.out.println("请输入第一个被除数:");
int a=input.nextInt();
System.out.println("请输入第二个除数数");
int b=input.nextInt();
int c=a/b;
System.out.println("c为多少:"+c);
}
//我们知道程序可能会出现的异常
catch (InputMismatchException e) {
System.out.println("程序存在异常");
}catch(NullPointException e){
System.out.println("程序存在异常");
//我们不知道程序出现可能出现的异常,就直接Exception e
}catch(Exception e) {
System.out.println("程序出现异常");
}
//关闭Scanner的输出资源
input.close();
System.out.println("程序运行中");
}
}
(3)执行顺序
- 执行try中的代码块
- 如果出现了异常信息去匹配第一个catch中声明的异常,没匹配上,就匹配第二个catch中的声明的异常,以此类推,如果都没有匹配上则当前异常信息交由JVM处理。如果匹配上了则执行catch中的代码块
- 继续执行后续代码
(4)注意事项:
- 和try-catch雷同。
- 一般情况下们会在最后catch结尾处增加一个catch(Exception e)为了去捕获可能在程序中出现的其它异常信息。
- 通过Exception捕获异常时不能放在之前catch(小异常情况)的前面写,否则后续catch(小异常情况)会报错,原因是由于Exception是所有类的父类,所有异常都会被Exception捕获。
iii.try-catch-finally
(1)语法格式
try{
//可能出现的异常代码
}catch(异常类型1){
//解决办法1
}catch(异常类型2){
//解决办法2
}。。。。。。。。。{
//解决办法n
}finally{
//最后执行的内容
}
(2)代码演示:
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
try {
System.out.println("请输入第一个被除数:");
int a=input.nextInt();
System.out.println("请输入第二个除数数");
int b=input.nextInt();
int c=a/b;
System.out.println("c为多少:"+c);
}
catch (InputMismatchException e) {
System.out.println("程序存在异常");
}catch(Exception e) {
System.out.println("程序出现异常");
}finally {
input.close();
System.out.println("程序运行中");
}
}
}
(3)执行顺序
- 执行try中的代码块,如果出现了异常信息,执行匹配的catch,最后执行finally执行try块中的内容,如果没有异常,最后执行finally。
- finally是在整个try-catch语句中最后被执行的程序。
(4)注意事项
- 和try-多重catch雷同。
- finally一定会被执行,return也没用。return是在finally代码执行之后执行的。
- System.exit(0);停止虚拟机,0是正常停止,非0数为非正常停止
vi.jdk1.7之后的新特性(针对于try-catch改进)
(1)try-catch语法格式:
try(之后需要关闭的资源声明){
//可能出现的异常代码段
}catch(异常1|异常2|异常。。。){
//异常执行代码
}
(2)代码演示:
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
try (Scanner input=new Scanner(System.in)){
System.out.println("请输入第一个被除数:");
int a=input.nextInt();
System.out.println("请输入第二个除数数");
int b=input.nextInt();
int c=a/b;
System.out.println("c为多少:"+c);
}
catch (InputMismatchException e) {
System.out.println("程序存在异常");
}catch(Exception e) {
System.out.println("程序出现异常");
}finally {
System.out.println("程序运行中");
}
}
}
- try小括号中的代码必须要实现了Closeable或者是AutoCloseable接口的实现类对象,才能通过try-resource关闭。
- 在catch中声明的多个异常要同类型以及同级。(不能有父子关系以及检查和运行异常混合的情况)
- 在try中可以声明多个待关闭资源对象的声明,通过:分隔开
6.5.7throw-throws
i.throws
- throws用来处理异常,它的处理方法是将异常抛给上一级处理,如都不能处理,最终抛给jvm处理,称为抛异常,
- 这种方法适合比较严重的异常和程序员无法预料或无法完全避免异常发生的情况,以及无法处理的异常
- 用来在方法声明的末尾添加throws语句,将程序中有可能出现的异常抛给调用者
代码演示:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Test3 {
public static void main(String[] args)throws NullPointerException, FileNotFoundException{
text();
}
public static void text()throws FileNotFoundException , NullPointerException {
FileInputStream fis = new FileInputStream("a.txt");
String str=null;
System.out.println(str.toString());
}
}
- throws是写在方法声明的末尾处
- throws后可以跟多个异常信息异常类型之间通过,分割开
- throws抛出异常之后,调用者需要捕获或者是继续向上抛出该异常
- throws抛出编译时异常,程序调用时不会显式报错,但是如果抛出的是检查时异常,程序编译就会报错。
ii.throw
代码演示:
public class Test4a[
public static void main(){
int[] arrs=new int[]{56,33,88,23,89};
sort(arrs);
}
public static void sort(int[] arrs){
if(arrs==null||arrs.length==0){
throw new IllegalArgument Exception();
}
System.out.println("排序");
Arrays.sort(arrs);
for(int x:arrs){
System.out.println(x);
}
}
- throw声明在方法体中,后跟创建出的一个异常对象
- throw可以被应用在异常中断中,防止程序继续往下执行
- throw一般和throws一起使用通过throw,创建一个异常对象,通过throws抛出异常
- throw如果创建的是一个运行时异常,可以不使用throws或者是try-catch,但是如果是一个检查时异常则一定要使用。
6.5.8异常继承关系图
6.5.9自定义异常
- 在JDK中虽然包含了大量的异常信息,但是在实际开发过程中还是会出现一些特殊的异常,这些异常JDK并没有办法保证也被创建出来。
(1)自定义异常的创建方式
- 声明一个异常类继承Exception / RuntimeExceltion
- 创建两个构造器一个无参一个有参(String类型),在有参构造器的内部调用super(有参)
代码演示:
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age) {
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0||age>150) {
try {
throw new AgeException("年龄超过规定");
}catch(AgeException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
}
this.age = age;
}
}
//自定义异常类,必须继承Exception\RuntimeException
public class AgeException extends RuntimeException{
public AgeException() {
super();
}
public AgeException(String exceptionMessage) {
super(exceptionMessage);
}
}
//测试类
public class Test4 {
public static void main(String[] args) {
Person a=new Person();
a.setAge(200);
}
}
(2)常见异常方法
- 异常对象.getMessag():获取异常的原因描述
- 异常对象.printStackTrace():打印当前异常的堆栈信息(异常出现的行数、异常的内容以及异常的原因描述