2020_4_1异常

1. 异常的概念

在Java中异常被当做对象来处理,根类是java.lang.Throwable类。所有异常类分为两大类:Error和Exception

  • Error是无法处理的异常,比如OutOfMemoryError(内存),一般发生这种异

常,JVM会选择终止程序。因此我们编写程序时不需要关心这类异常

  • Exception,也就是我们经常见到的一些异常情况,这些异常是我们可以处理的

2. 常见的异常及捕获

下表中列出了几个常见的异常,其中所有的异常都是Exception的子类:

![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3OotZb4i-1587181067664)(E:\Blogs\java学习笔记\2020_4_1异常.assets\1586700742619.png)]](https://img-blog.csdnimg.cn/202004181138381.png?x-oss- process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Nlbjg3MzU5MTc2OQ==,size_16,color_FFFFFF,t_70)

我们使用try catch块来捕获异常,最基本的用法如下,我们捕获一个NullPointerException异常:

Ps:请留意异常的打印到栈的用法。

public class Ex1 {


	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		try {
			/*
			 *  1.抛出到main的外面
			 *  2.捕获
			*/
//			int a = 10/0;
			String string = null;
			System.out.println(string.length());
			System.out.println("不报错");
		} catch (Exception e) {
			// TODO: handle exception
			//异常的打印到栈
			e.printStackTrace();
			System.out.println("报错了");
		}
		
		System.out.println("程序结束!!");
	}

}

//输出:
//java.lang.NullPointerException
//报错了
//程序结束!!
//	at Ex1.main(Ex1.java:15)

我们还可以捕获一个日期类型的异常:

这里我们顺便复习了如何用Date类去统计某一段程序的运行时间。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Ex2 {

	
	public static void main(String[] args)  {
		
		//统计运行时间
		Date d1=new Date();
		System.out.println(d1);
		long t1 = d1.getTime();
		for(int i = 0;i < 100000000 ;i++) {
			int a = i;
			for(int j = 0;j < 100000000 ;j++) {
				int b = 1;
			}
		}
		Date d2 = new Date();
		long t2 = d2.getTime();
		System.out.println(t2-t1);
        
        //异常
		SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
		try {
			Date d3 = s.parse("2020-12-aaaaaaa");
			System.out.println(s.format(d3));
			System.out.println("okokoko");
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}


/*
Sun Apr 12 22:19:29 CST 2020
78
java.text.ParseException: Unparseable date: "2020-12-aaaaaaa"
at java.base/java.text.DateFormat.parse(Unknown Source)
at Ex2.main(Ex2.java:26)
 * */
 */

上面这段程序的异常类型是ParseException类型,我们可以从parse函数的源码中知道为什么。

    public Date parse(String source) throws ParseException
    {
        ParsePosition pos = new ParsePosition(0);
        Date result = parse(source, pos);
        if (pos.index == 0)
            throw new ParseException("Unparseable date: \"" + source + "\"" ,
                pos.errorIndex);
        return result;
    }

下面我们捕获一个ClassCastException异常;

public class Man {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
            //向上转换
			Man m1 = new Teacher();
			Student s1 = (Student)m1;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		System.out.println("运行结束");
	}
}

/*
java.lang.ClassCastException: Teacher cannot be cast to Student
运行结束
	at Man.main(Man.java:12)
*/
public class Student extends  Man{

}
public class Teacher extends Man{

}

下面是一个ArrayIndexOutOfBoundsException异常,同样的还有字符串对应的IndexOutOfBoundsException(不演示了);

public class Ex3 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		try {
			int[] num = new int[3];
			num[4] = 2; 
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

}

//
//java.lang.ArrayIndexOutOfBoundsException: 4
//at Ex3.main(Ex3.java:9)

下面捕获一个输入异常InputMismatchException,如果我们输入了一个字符串,基本的情况如下;

import java.util.Scanner;

public class Ex4 {
	
	public int getInputNum() {
		Scanner s = new Scanner(System.in);
		return s.nextInt();
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Ex4 ex4 = new Ex4();
		
		System.out.println(ex4.getInputNum());

	}

}
/**
Exception in thread "main" java.util.InputMismatchException
	at java.base/java.util.Scanner.throwFor(Unknown Source)
	at java.base/java.util.Scanner.next(Unknown Source)
	at java.base/java.util.Scanner.nextInt(Unknown Source)
	at java.base/java.util.Scanner.nextInt(Unknown Source)
	at Ex4.getInputNum(Ex4.java:7)
	at Ex4.main(Ex4.java:14)
*/

我们想要让这段代码具有更高的容错率,如果我们输入了字符串或其他,应该让我们重复输入,直到我们输入了正确的int类型:

import java.util.Scanner;

public class Ex4 {
	
	public int getInputNum() {
		while (true) {
			try {
				System.out.println("请输入数字:");
				Scanner s = new Scanner(System.in);
				return s.nextInt();
			} catch (Exception e) {
				// TODO: handle exception
				System.out.println("您的输入不是数字");
			}
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Ex4 ex4 = new Ex4();
		System.out.println(ex4.getInputNum());
	}

}

/**
请输入数字:
sen
您的输入不是数字
请输入数字:
12
12

*/

3. 异常的抛出

异常可以大致分为两类:编译时异常(显式异常)和运行时异常(隐式异常)

首先我们来看一个显式异常的例子:

这里的parseException是一个显式异常,必须在编译期处理,类似的还有SQLException和IOException

我们对于这种异常,必须在编写程序的时候添加抛出(throws ParseException),不然编译器就会爆红;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Ex5 {

	public Date getDate(String sDate) throws ParseException {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
		return simpleDateFormat.parse(sDate);
	}
	
	//parseException 显式异常,必须在编译期处理
	//类似的还有SQLException和IOException
	public static void main(String[] args) {
		
		Ex5 ex5 = new Ex5();
		try {
			System.out.println(ex5.getDate("2020-1-3"));
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}


下面再来看一个隐式异常:

这里如果分母是0的话会出现异常,这种异常在编译期间是不处理的,编译期间不报错,如果不处理,一旦发生异常,就会造成程序的终止。

public class Ex6 {

	public int math(int a,int b) {
		return a/b;
	}
    
	/**
	 * 隐式异常(运行时异常)的处理
	 * 这种异常在编译期间是不处理的,编译期间不报错;
	 * 如果不处理,一旦发生异常,就会造成程序的终止
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Ex6 ex6 = new Ex6();
		ex6.math(10, 0);
		System.out.println("all is ok");
	}
}

/**
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Ex6.math(Ex6.java:6)
	at Ex6.main(Ex6.java:17)
	*/

在处理异常的时候我们有两个关键字 throws和throw

throws的用法就是在函数的方法名后面可以抛出异常,throw可以用来转换异常。

我们可以看出throw是动词,所以是一个转换的动作。

注意,异常的抛出和截获要保持一致。

这里利用throw把ParseException转换成IOException。(并没有什么用,仅仅为了演示用法)

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.imageio.IIOException;

public class Ex5 {
	
	public Date getDate(String sDate) throws IOException  {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
		
		try {
			return simpleDateFormat.parse(sDate);
		} catch (ParseException e) {
			//利用throw把ParseException转换成IOException
            //同时,throws对应的异常也要改。
			throw new IOException();
		}
	}
	
	//parseException 显式异常,必须在编译期处理
	//类似的还有SQLException和IOException
	public static void main(String[] args) {
		
		Ex5 ex5 = new Ex5();
		try {
			System.out.println(ex5.getDate("AAA-1-3"));
            //异常的抛出和截获要保持一致。
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
/**
java.io.IOException
at Ex5.getDate(Ex5.java:18)
at Ex5.main(Ex5.java:28)
*/


4. 自定义异常

我门可以通过继承Exception来自定义异常,自定义异常实际上是实际上用的最多的地方。

我门假设以下情况:

在这里插入图片描述

这里我们主要模拟这里的用户异常和系统异常。

首先先创建系统异常和用户异常两个异常类,继承与Exception。

package demo2;

//自定义异常--用户级异常
public class appException extends Exception{

	//	异常码和异常信息
	private int ErrorCode;
	private String ErrMessags;
	
	/**
	 * 有参数的构造器
	 * @param errorCode
	 * @param errMessags
	 */
	public appException(int errorCode, String errMessags) {
		super();
		ErrorCode = errorCode;
		ErrMessags = errMessags;
	}
	
	public int getErrorCode() {
		return ErrorCode;
	}
	public void setErrorCode(int errorCode) {
		ErrorCode = errorCode;
	}
	public String getErrMessags() {
		return ErrMessags;
	}
	public void setErrMessags(String errMessags) {
		ErrMessags = errMessags;
	}
}


package demo2;


//自定义异常--系统级异常
public class systemException extends Exception{
	//	异常码和异常信息
	private int ErrorCode;
	private String ErrMessags;
	
	/**
	 * 有参数的构造器
	 * @param errorCode
	 * @param errMessags
	 */
	public systemException(int errorCode, String errMessags) {
		super();
		ErrorCode = errorCode;
		ErrMessags = errMessags;
	}

	public int getErrorCode() {
		return ErrorCode;
	}
	public void setErrorCode(int errorCode) {
		ErrorCode = errorCode;
	}
	public String getErrMessags() {
		return ErrMessags;
	}
	public void setErrMessags(String errMessags) {
		ErrMessags = errMessags;
	}
}


随后我们模拟上图中的两种异常:

建立主函数来调用我们创建好的两个异常:

package demo2;

public class Ex8 {

	public int math(int a,int b) throws appException, systemException {
		try {
//			数组越界异常,利用系统异常抛出
			int[] nums = new int[3];
			nums[3] = 8;
//			数学运算异常,利用用户异常抛出
			return a/b;
		} catch (ArithmeticException e) {
			//转换成自定义异常为用户级异常;
			throw new appException(1001, "b不能为0!");
		}catch (IndexOutOfBoundsException e) {
			// TODO: handle exception
			throw new systemException(999, "系统异常!");
		}
		
	}
	public static void main(String[] args) {
		Ex8 ex8 = new Ex8();
		
		try {
			ex8.math(20, 0);
		} catch (appException e) {
			System.out.println(e.getErrMessags());
		}catch (systemException e) {
			System.out.println(e.getErrMessags());
		}
		System.out.println("finished!");
	}
}

//系统异常!
//finished!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值