异常

异常

在生活中,异常(exception)情况随时都有可能发生。以上下班为例,在正常情况下,小明每日开车去上班,耗时大约30分钟。但是,由于车多、人多、路窄,异常情况很有可能发生。有时会遇上比较严重得堵车,这种情况下,小明往往很晚才能到公司,这种异常虽然偶尔才会发生,但是真的发生也是件极其麻烦的事情。

在程序中,异常就是在程序的运行过程中所发生的不正常的事件,如所需文件找不到、数组下标越界等等,异常会中断正在运行的程序。

异常处理

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

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

try-catch块

import java.util.Scanner;
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.err.println("输入的被除数不是整数,除数不能为零");
			e.printStackTrace();
		}
	}
  1. 如果try块中所有语句正常执行完毕,不会发生异常,那么catch块中的所有语句都将会被忽略。
  2. 如果try语句块在执行过程中遇到异常,并且这个异常与catch中声明的异常类型相匹配,那么try块中其余剩下的代码都将被忽略。
  3. 如果try语句块在执行过程中遇到异常,而抛出的异常在catch块里面没有被声明,那么程序立刻退出。

在catch块中可以加入用户自定义处理信息,也可以调用异常对象的方法输出异常信息,常用的方法主要有两种:

  • void printStackTrace():输出异常的堆栈信息。堆栈信息包括程序运行到当前类的执行流程,它将输出从方法调用处到异常抛出处的方法调用序列。
  • String Message():返回异常信息描述字符串。该字符串描述异常产生的原因,是printStackTrace()方法输出信息的一部分。

常见的异常类型

异常说明
Exception异常层次结构的根类
ArithmeticException算术错误情形,如以0做除数
ArrayIndexOutOfBoundsException数组下标越界
NullPointException尝试访问null对象成员
ClassNotFoundException不能加载所需的类
InputMismatchException数据类型不匹配
IllegalArgumentException方法接收到非法参数
ClassCastException对象强制类型转换出错
NumberFormatException数字格式转换异常,如把“abc”转换为数字

try-catch-finally块

import java.util.Scanner;
public static void main(String[] args) {
	Scanner input = new Scanner(System.in);
	try {
		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));
			
	} catch (Exception e) {
		System.err.println("输入的被除数不是整数,除数不能为零");
		e.printStackTrace();
	}finally {		//无论是否发生异常,finally块中的代码总能被执行
		System.out.println("感谢使用本程序!");
	}
}
  1. 如果try块中所有语句正常执行完毕,那么finally块就会被执行。
  2. 如果try语句在执行过程中碰到异常,无论这种异常是否被catch块捕获到,都将执行finally块中的代码。

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

注意:

即使在try块和catch块中存在return语句,finally块中语句也会被执行。发生异常时的执行顺序:执行try块或catch块中return之前的语句,执行finally块中的语句,执行try块或catch中的return语句退出。

多重catch块

一段代码可能会引发多种类型的异常,这时,可以在一个try语句块后面跟多个catch块,分别处理不同的异常。但排序顺序必须是从子类到父类,最后一个一般都是Exception类。因为所有异常子类都继承自Exception类,所以如果将父类异常放到前面,那么所有的异常都将被捕获,后面catch块中的子类异常将得不到被执行的机会。

当运行时,系统从上到下分别对每个catch语句块处理的异常类型进行检测,并执行第一个与异常类型匹配的catch语句。执行其中的一条catch语句之后,其后的catch语句都将被忽略。

import java.util.Scanner;
public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		try {
			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));
		}catch (InputMismatchException e) {
			System.err.println("被除数和除数必须是整数");
			System.exit(1);
		}catch (ArithmeticException e) {	//检测是否算术错误
			System.err.println("除数不能为零");
			System.exit(1);
		}catch (Exception e) {
			System.err.println("其他未知错误");
			System.exit(1);
		}finally {
			System.out.println("感谢使用本程序!");
		}
	}

声明异常–throws

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

抛出异常的两种方式:

  • 通过try-catch捕获并处理异常。
  • 通过throws继续声明异常。如果调用者不打算处理该异常,则可以继续通过throws声明异常,让上一级调用者处理异常。main()方法声明的异常将由Java虚拟机来处理。
import java.util.Scanner;
public static void main(String[] args) {
		try {
			divide();
		} catch (Exception e) {
			System.err.println("输入的被除数不是整数,除数不能为零");
			e.printStackTrace();
		}
	}
	
	public static void divide() throws Exception{
		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));
	}

抛出异常

抛出异常–throw

除了系统自动抛出异常外,在编程过程中,有些问题是系统无法自动发现并解决的,如性别输入的不是“男”或“女”,此时需要程序员而不是系统来自行抛出异常,把问题提交给调用者解决。

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(this.name + "(" + this.sex + "," + this.age + "岁)");
	}
}

public class Test {
	public static void main(String[] args) {
		Person xx = new Person();
		try {
			xx.setSex("Male");
			xx.print();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

throws和throw的区别

  • 作用不同:throw用于在程序中抛出异常;throws用于声明在该方法内抛出了异常。
  • 使用的位置不同:throw位于方法体内部,可以作为单独语句使用;throws必须跟在方法参数列表的后面,不能单独使用。
  • 内容不同:throw抛出一个异常对象,而且只能是一个;throws后面跟异常类,而且可以跟多个异常类。

异常的分类

在这里插入图片描述

  • Throwable类:所有异常类型都是Throwable类的子类,它派生两个子类,即Error和Exception。
  • Error类:表示仅靠程序本身无法恢复的严重错误,如内存溢出动态链接失败、虚拟机错误。
  • Exception类:由Java应用程序抛出和处理的非严重错误,如所需文件找不到、数组下标越界等等。
  • 运行时异常:包括RuntimeException及其所有子类,不要求必须对它们做出处理。
  • Checked异常(非运行时异常):除了运行时异常外的其他由Exception继承来的异常类。程序必须捕获或声明抛出这种异常,否则会出现编译错误,无法通过编译。

开源日志记录工具log4j

使用步骤:

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

日志及分类

软件的运行过程离不开日志,日志主要用来记录系统运行过程中的一些重要的操作信息,便于监视系统运行情况,帮助用户提前发现和避开可能出现的问题,或者出现问题后根据日志找到发生的原因。

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

  1. SQL日志:记录系统执行的SQL语句。
  2. 异常日志:记录系统运行中发生的异常事件。
  3. 业务日志:记录系统运行过程,如用户登录、操作记录。

log4j是一个非常优秀的日志(log)记录工具。通过使用log4j,可以控制日志的输出级别,以及日志信息输送的目的地(如控制台、文件等),还可以控制每一条日志的输出格式。

要使用log4j,首先需要下载log4j的JAR文件。log4j是 Apache的一个开源项目,官方网站是http://logging.apache.org/log4j。

如何使用log4j记录日志

  1. 在项目中加入log4j所使用的JAR文件。在 MyEclipse中选中要使用log4j的项目,然后依次选择" Project"→" properties→" Java Build Path"→" Libraries→" Add External JARs…"选项,弹出选择JAR的窗口,找到自己计算机上存放的文件。
  2. 创建log4j.properties文件。选择要使用log4j的项目,右击src,依次选择“New”→“File”,输入文件名“log4j.properties”→“Finish”。
  3. 编写log4j.properties文件,配置日志信息。
### 设置Logger输出级别和输出目的地  ###
log4j.rootLogger=debug, stdout,logfile

### 把日志信息输出到控制台  ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout

### 把日志信息输出到文件:jbit.log ###
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=jbit.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}%l %F %p %m%n
import org.apache.log4j.Logger;
import prepare.Yx12;
public class Test{
    private static Logger logger = Logger.getLogger(Yx12.class.getName());
	public static void main(String[] args) {
		try {
			Scanner in = new Scanner(System.in);
			System.out.print("请输入被除数:");
			int num1 = in.nextInt();
			logger.debug("输入被除数:" + num1);
			System.out.print("请输入除数:");
			int num2 = in.nextInt();
			logger.debug("输入除数:" + num2);
			System.out.println(String.format("%d / %d = %d",num1,num2,num1/num2));
			logger.debug("输出运算结果:"+String.format("%d / %d = %d", num1,num2,num1/num2));
		} catch (InputMismatchException e) {
			logger.error("被除数和除数必须是整数",e);
		}catch(ArithmeticException e) {
			logger.error(e.getMessage());
		}catch(Exception e) {
			logger.error(e.getMessage());
		}finally {
			System.out.println("欢迎使用本程序!");
		}
	}
}

在程序中log4j使用:首先创建一个私有静态的Logger对象,然后就可以通过它的debug()或者error()等方法输出日志信息了。

Logger对象是用来替代System.err的日志记录器,供程序员输出日志信息,它提供了一系列方法来输出不同级别的日志信息。

  • public void debug(Object msg)
  • public void debug(Object msg, Throwable t)
  • public void info(Object msg)
  • public void info(Object msg, Throwable t)
  • public void warn(Object msg)
  • public void warn(Object msg, Throwable t)
  • public void error(Object msg)
  • public void error(Object msg, Throwable t)
  • public void fatal(Object msg)
  • public void fatal(Object msg, Throwable t)

log4j配置文件

1、输出级别

log4j.rootLogger=debug, stdout,logfile

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

  • fatal:指出严重的错误事件将会导致应用程序的退出。
  • error:指出虽然发生错误事件,但仍然不影响系统的继续运行。
  • warn:表明会出现潜在错误的情形。
  • info:在粗粒度级别上指明消息,强调应用程序的运行过程。
  • debug:指出细粒度信息事件,对调试应用程序非常有帮助。
  • 优先级:fatal > error > warn > info > debug

日志记录器(Logger)将只会输出那些级别高于或等于它的信息。例如级别为error,将只输出fatal、error级别的日志信息。

2、日志输出目的地Appender

log4j.rootLogger=debug, stdout,logfile

stdout,logfile指的是日志输出目的地的名字。

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

  • ConsoleAppender:输出日志事件到控制台。通过Target属性配置输出到System.out或System.err,默认的目标是System.out。
  • FileAppender:输出日志事件到一个文件。通过File属性配置文件的路径及名称。

3、日志布局类型Layout

Appender必须使用一个与之相关联的布局类型Layout,用来指定它的输出样式:

  • HTMLLayout:格式化日志输出为HTML表格。
  • SimpleLayout:以一种非常简单的方式格式化日志输出,它输出级别Level(最小),然后跟着一个破折号,最后是日志信息。
  • PatternLayout:根据特定的转换模式格式化日志输出,从而支持丰富多样的输出格式。需要配置layout.ConversionPattern属性,若没有配置该属性,则使用默认的转换模式。

4、转换模式ConversionPattern

  • %d:设置输出日志的日期和时间,默认格式为ISO8601。
  • %m:输出代码中指定的消息。
  • %n:输出一个回车换行符。
  • %l:输出日志事件的发生位置,包括类名、发生的线程,以及在代码中的行数。
  • %p:输出优先级。
  • %F:输出文件名
  • %M:输出方法名。

Layout:以一种非常简单的方式格式化日志输出,它输出级别Level(最小),然后跟着一个破折号,最后是日志信息。

  • PatternLayout:根据特定的转换模式格式化日志输出,从而支持丰富多样的输出格式。需要配置layout.ConversionPattern属性,若没有配置该属性,则使用默认的转换模式。

4、转换模式ConversionPattern

  • %d:设置输出日志的日期和时间,默认格式为ISO8601。
  • %m:输出代码中指定的消息。
  • %n:输出一个回车换行符。
  • %l:输出日志事件的发生位置,包括类名、发生的线程,以及在代码中的行数。
  • %p:输出优先级。
  • %F:输出文件名
  • %M:输出方法名。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值