异常

异常

​ 在生活中异常情况随时都有可能发生,以上下班为例在正常情况下,小王每日开车去上班,耗时大约30分钟。但是,由于车多,人多,路窄异常情况横有可能发生。有时会遇上比较严重的堵车,偶尔还会很倒霉地与其他汽车情迷接触。这种情况下,小王往往很晚到达单位,这种异常虽然偶尔才会发生但是若真发生也是件极其麻烦的事情。

​ 这就是生活中的异常。下面我们看看程序运行过程中会不会发生异常:

	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入被除数");
		int num1 = input.nextInt();
		System.out.println("请输入除数");
		int num2 = input.nextInt();
		System.out.println(String.format("%d/d=%d", num1,num2,num1/num2));
		System.out.println("感谢使用本程序");
	}

我们只要输出了非数字,或者除数为0系统就会异常,一旦出现异常,程序将会立刻结束,不经计算和输出商的语句不被执行,而且输出”感谢使用本程序!“的语句也不执行,应该如何解决这些异常呢?我们可以通过if - else语句来对各种异常情况进行判断处理

但不过通过if-else语句来进行异常处理的机制主要有以下特点:

  • 代码臃肿,加入大量的异常情况判断和处理代码
  • 程序员把相当多的经理放在了处理异常代码上,放在了”堵漏洞“上,减少了编写业务代码的时间,必然影响开发效率
  • 很难穷举所有的异常情况,程序任然不健壮
  • 异常处理代码和业务代码交织在一起,影响代码的可读性,加大日后程序的维护难度

如果堵漏洞的工作由系统来处理,用户关注于业务代码的编写,对于异常只需调用相应的异常处理程序就好了。

异常处理

异常处理机制就像我们对平时可能遇到的意外情况,预先想好了一些处理代码的办法,也就是说在程序执行代码的时候,万一发生了异常,程序会按照预定的处理办法对异常进行处理,异常处理完毕之后程序继续进行。

​ Java的异常处理是通过五个关键字来实现的:try,catch,finally,throw,throws

try-catch块

public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入被除数");
		try {
			int num1 = input.nextInt();
			System.out.println("请输入除数");
			int num2 = input.nextInt();
			System.out.println(String.format("%d/d=%d", num1,num2,num1/num2));
			System.out.println("感谢使用本程序");
		} catch (Exception e) {
			System.out.println("程序出现错误");
			e.printStackTrace();
		}
		
	}
  • try-catch程序块比较简单,首先执行的是try语句快的语句,这时可能会有以下三种情况:
  • 如果try中所有语句正常执行完毕,没有发生异常那么catch块中的所有语句都不执行
  • 如果try语句块在执行过程中遇到异常,并且这个异常与catch中声明的异常类型相匹配,那么try里面的其余剩下的代码都将不执行了,而相应的catch快将会被执行。匹配是指catch所处理的异常类型与所生成的异常类型完全一致或是他的父类。
  • 如果try语句块在执行过程中遇到异常,而抛出的异常在catch里面没有被被声明那么程序立刻退出

常见的异常类型

异常说明
exception异常层次结构的根类
ArithmeticException算数错误情形,如以零做除数
ArrayIndexOutOfBoundsException数组下标越界
NullPointerException尝试访问null对象的成员
ClassNotFoundException不饿能加载所需的类
InputMismatchException遇得到的数据类型与实际输入的类型不匹配
IIIegalArgumentException方法接收到非法参数
ClassCastException对象强制类型转换出错
NumberFormatException数字格式转换异常

try-catch-finally块

	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入被除数");
		try {
			int num1 = input.nextInt();
			System.out.println("请输入除数");
			int num2 = input.nextInt();
			System.out.println(String.format("%d/d=%d", num1,num2,num1/num2));
			
		} catch (Exception e) {
			System.out.println("程序出现错误");
			e.printStackTrace();
			
		}finally {
			System.out.println("感谢使用本程序");
		}
		
	}

try-catch-finally程序块的执行流程大致分为两种情况

  • 如果try块中所有语句正常执行完毕,那么finally块将会被执行

  • 如果try语句在执行过程中碰到一场,无论catch能不能捕获异常,都将执行finally块中的代码

    try-catch-finally结构中try块是必须的,catch和finally块为可选,但两者至少必须出现其中之一

需要特别注意的是,即使在try块和catch块中存在return语句,finally块中语句也会被执行,发生异常时的执行顺序,执行try块或catch块中存在return语句,finally块中的语句也会被执行。finally块中语句不被执行的唯一情况:在异常处理代码中执行System.exit(1)。将退出Java虚拟机。

多重catch块

在上面计算并输出商的示例中,其中至少存在两种异常情况,输入非整数内容和除数为0.之前我同意按照Exception类型捕获,其实完全可以分别捕获,即使用多重catch块。

public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入被除数");
		try {
			int num1 = input.nextInt();
			System.out.println("请输入除数");
			int num2 = input.nextInt();
			System.out.println(String.format("%d/d=%d", num1,num2,num1/num2));
		} catch (InputMismatchException e) {
			System.err.println("被除数和除数必须是整数");
		}catch (ArithmeticException e) {
			System.err.println("除数不能为0");
		}catch (Exception e) {
			System.err.println("程序出现错误");
		}finally {
			System.out.println("感谢使用本程序");
		}
		
	}

程序运行后,如果输出的不是整数,系统将会抛出InputMismatchException异常对象因此进入第一个catch块并执行其中的代码,而其他的catch块将不执行。

如果除数输入0系统会抛出ArithmeticException异常对象。因此进入第二个catch块,并执行其中的代码,其他catch将不执行。

注意:在使用多重catch块时,catch块的排序必须时从子类到父类,最后一个一般都是Exception类

声明异常——throws

如果在一个方法体中抛出了异常,我们就希望调用者能够及时的捕获异常,那么如何通知调用者呢?Java语言中关键字throws声明某个方法可能抛出的各种异常,throws可以声明多个异常之间用逗号隔开。

我们把计算并输出商的任务封装在divide()方法中,并在方法的参数列表后通过throws声明了一场,然后在main方法中调用该方法,此时main()方法就知道divide()方法抛出了异常,可以采用一下两种方式进行处理异常

通过try-catch捕获并处理异常。

通过throws继续声明异常。如果调用者不打算处理该异常,则可以继续通过throws声明异常,让上一级调用者处理异常。main方法声明的异常将由Java虚拟机来处理

public static void main(String[] args) {
		
		
		try {
			divide();
		} catch (Exception e) {
			System.out.println("出现错误");
			e.printStackTrace();
		}
	}
	public static void divide() throws Exception{
		Scanner input = new Scanner(System.in);
		int num1 = input.nextInt();
		System.out.println("请输入除数");
		int num2 = input.nextInt();
		System.out.println(String.format("%d/d=%d", num1,num2,num1/num2));
	}

抛出异常——throw

在Java语言中,可以使用throw关键字来自行抛出异常在person类中抛出一个异常,抛出的异常的原因,由于在当前环境中无法解决参数问题,因此在方法内通过throw抛出异常,把问题交给调用者去处理,在调用该方法的Test类中捕获并处理异常。

public class Person {
	private String name ="";
	private int age =0;
	private String sex ="男";
	public void setSex(String sex) throws Exception{
		if ("男".equals(sex)||"女".equals(sex)) {
			this.sex = sex;
		}else {
			throw new Exception("性别必须是男或者女");
		}
	}
	public void print(){
		System.out.println(name+sex+age);
	}
}
public class Test {
	public static void main(String[] args) {
		Person jkl = new Person();
		try {
			jkl.setSex("male");
			jkl.print();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

异常的分类

Throwable类:所有的异常类型都是Throwable的子类,他派生两个子类,即Error和Exception

Error类:表示仅靠程序本身无法恢复的严重错误,如内存溢出动态链接失败,虚拟机错误。应用程序不应该抛出这种类型的对象。加入出现这种错误,除了尽力时程序安全退出外,在其他方面时无能为力的,所以在进行程序设计时,应该更关注Exception

Exception类:由Java应用程序抛出和处理的非严重错误,如所需文件找不到,网络连接不通或中断,常见的异常类型里面详细讲到Exception是他们的父类

运行时异常:包括RuntimeException及其所有子类,不要求程序必须对他们做出处理。在程序中并没有使用try-catch或throws进行处理,任然可以进行编译和运行,如果运行时发生异常,会输出异常的堆栈信息并终止程序运行

Checked异常:除了运行时异常外的其他有Exception继承来的异常类程序必须捕获或者声明抛出这种异常,否则会出现编译从无,无法通过编译,处理方式包括两种try-catch 通过Throws声明抛出异常,交给上一级调用方法处理

开源日志记录工具log4j

在MyEclipse中使用log4j的步骤比较简单,主要分为一下四个步骤

  1. 在项目中加入log4j所使用的JAR文件
  2. 创建Log4j.properties文件
  3. 编写Log4j.properties文件,配置日志信息。
  4. 在程序中使用log4j记录日志信息

日志及分类

日志根据记录内容的不同,主要分成一下三类

SQL日志:记录系统执行的SQL语句

异常日志:记录系统运行中发生的异常事件

业务日志:记录系统运行过程,如用户登录,操作记录

Log4j配置文件

输出级别
Log4j.rootLogger = debug,stdout,Logfile

其中debug指的是日志记录器Logger的输出级别,主要输出级别及含义如下:

fatal:指出严重的错误事件将会导致应用程序的退出。

error:指出虽然发生错误事件。但仍然不影响系统的继续运行

warm:表明会出现潜在错误的情形。

info:在粗粒度级别上指明消息,强调应用程序的运行过程

debug:指出细粒度信息事件,对调试应用程序是非常有帮助的

各个输出级别优先级:

fatal>error>warm>info>debug

日志输出目的地Appender

log4j允许记录日志到多个输出目的地,一个输出目的地被称为Appender.Log4j中最常用的Appender有以下两种

ConsoleAppender:输出日志事件到控制台,通过Target属性来配置输出到System.out或System.err

FileAppender:输出日志事件到一个文件通过File属性配置文件的路径及名称

日志布局类型Layout

有三种

HTMLLayout:格式化日志输出HTML表格

SimpleLayout:以一种非常简单的方式格式化日志输出,他输出级别Level,最后日志消息

PattermLayout:根据指定的转换模式格式化日志输出,从而支持丰富多样的输出格式。

转换模式ConversionPattern

%p:输出的等级

%m:消息,输出的内容

%n:换行

%F:输出文件名

%M:用来输出方法名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值