Java中的异常及try、catch、finally

异常

概念: Java语言将程序运行过程中所发生的不正常严重错误称为异常,对异常的处理称为异常处理。 它会中断正在运行的程序,正因为如此异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点。

我们可以进行如下两点的理解:

①出现和正常预期结果不同的情况,就叫异常。
如下情况,就会出现异常

public class Test{
	public static void main(String [] args){ 
		System.out.println(1/0);//分母为0,控制台报错
	}
}
/*运行结果(控制台输出):
  Exception in thread "main" java.lang.ArithmeticException: / by zero
    	at Test.main(Test.java:)*/

②语句出现异常时,程序将中断同级代码的执行。
如下情况,就会出现异常中断现象

public class Test{
	public static void main(String [] args){ 
		System.out.println(1/1);//此语句不存在异常风险,且在异常语句前,可正常执行
		System.out.println(1/0);//分母为0,控制台报错
		System.out.println(2/1);//异常情况后的同级语句,将不被执行
	}
}
/*运行结果(控制台输出):
  1
  Exception in thread "main" java.lang.ArithmeticException: / by zero
    	at Test.main(Test.java:9)*/

异常分类

在这里插入图片描述
我们可以看到,Java中,把异常分为很多类,不只是抽象的类,在jdk中这些类是真实存在的,且存在父类子类的继承关系,对应上图中的上下级。

如:Exception类为Throwable的子类,而RuntimeException又为Exception的子类。

那么,这些分类代表着什么呢?

1、Throwable中的常用方法:
public String getMessage():获取异常信息;
public void printStackTrace():输出异常堆栈中的异常信息

2、Error : 指合理的应用程序在执行过程中发生的严重问题。当程序发生这种严重错误时,通常的做法是通知用户并中止程序的执行。(本篇不详细说明)

3、Exception

①构造方法:
public Exception():无参构造方法;
public Exception(String message):可以指定详细异常信息的有参构造方法

②运行时异常:可以成功编译,但运行时暴露异常。RuntimeException异常类及其下面的子类均为运行时异常。

//例:
public class Test{
	public static void main(String [] args){ 
		System.out.println(1/0);//虽然存在异常,但是编译时不会报错,运行时出错
	}
}

所以:运行时异常可以不进行显式的处理(我们下面会讲如何处理异常),javac依然可以编译程序。

③检查时异常(CheckedException):Exception下:除了运行时异常,剩下的都是检查时异常。检查时异常编译时既报错。(当然语法上要正确才算)

public class Test{
	public static void main(String [] args){ 
		Class.forName("");//存在异常,且编译时就直接报错
	}
}

出现检查时异常时,我们需要对其进行显式处理。

异常处理

当程序存在异常时,意味着无法得出我们想要的结果,我们就需要对其进行处理。
有两种处理异常的方法:
①通过try、catch和finally关键字捕获异常;(本篇详述)
②通过throw或throws关键字抛出异常;(本篇简单提一下使用方法及例句)

1、通过try、catch和finally关键字捕获异常
①try、catch组合:
//直接来一个例子便于理解
public class Test{
	public static void main(String [] args){ 
		System.out.println(1/1);     //此语句不存在异常风险,且在异常语句前,可正常执行
		try{                         //对{}中的语句进行尝试
			System.out.println(1/0); //运行时异常语句(ArithmeticException)
			Class.forName("");       //异常后同级语句不被执行
		} catch{(Exception e) {      //尝试后如果异常,捕获异常(ArithmeticException为Exception子类,所以e为上转型对象)
			e.printStackTrace();     //输出异常信息(e继承Throwable中的printStackTrace方法)
		}
		System.out.println(2/1);     //异常情况后的非同级语句,可以执行
	}
}
/*运行结果
  1
  java.lang.ArithmeticException: / by zero
  at Test.main(Test.java:11)
  2*/
  • try就是尝试的意思,catch就是抓住、捕获。通过这种组合,试出异常,然后实例一个异常对象存储异常。

  • 通过继承关系,子异常类可以调用父类方法。如上例catch{}中,异常对象调用了.printStackTrace方法。

  • 通过try、catch组合,防止了异常使程序运行中断的情况。

  • 异常的特性仍然存在:try{}中,只能试出将会出现的第一个异常,try{}中第一个异常后的代码将不被执行。如上例中Class.forName("")语句,没有被执行。

  • 一个try可以有多个catch{},try{}不能单独使用,必须组合catch{}或finally{}。

②finally{}
//例
public class Test{
	public static void main(String [] args){ 
		try{
			System.out.println(1/0); 
		} finally{
			System.out.println("try、finally语句");//try可以搭配finally语句执行
		}
		
		try{
			System.out.println(1/0); 
		} catch(Exception e){
			System.out.println("try、catch语句”);
		} finally{
			System.out.println("try、catch、finally语句");//finally语句也可以在try{}catch{}后
		}
	}
}
/*运行结果:
   try、finally语句
   try、catch语句
   try、catch、finally语句*/
  • 无论try中是否有异常发生,finlly中的代码总会执行,一般用于释放资源。
③log4j
  • 当我们通过try、catch和finally关键字捕获异常后,我们通常是要输出记录异常情况的,通过控制台缓存输出是最直接的方法。但是,当异常情况累计大于缓存时,最早被记录的情况会被挤出缓存。所以,当碰到比较大的工程时,只靠控制台显然是不稳妥的。

  • Log4j是Apache的一个开源项目,通过使用Log4j,可以控制日志信息格式及其输送目的地(控制台、文件、数据库等),方便后期查找系统运行期间出现的问题,进而便于维护系统。这就解决了上面刚刚提到的问题。

  • 配置Log4j如下步骤

  • 第一步:导入log4j-1.2.15.jar依赖包
  • 第二步:在src根目录下创建名为log4j.properties的文件,文件内容如下:
# DEBUG设置输出日志级别,由于为DEBUG,所以ERROR、WARN和INFO 级别日志信息也会显示出来
log4j.rootLogger=DEBUG,Console,RollingFile

#将日志信息输出到控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern= [%-5p]-[%d{yyyy-MM-dd HH:mm:ss}] -%l -%m%n
#将日志信息输出到操作系统D盘根目录下的log.log文件中
log4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.RollingFile.File=D://log.log
log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p %-40.40c %X{traceId}-%m%n
  • 第三步:src目录创建Test类(例),代码如下:
import org.apache.log4j.Logger;
 
public class Test {
 
	private static final Logger logger = Logger.getLogger(Test.class);
 
	public static void main(String[] args) {
		try {
			Class.forName("ErrorClassName");
		} catch (ClassNotFoundException e) {
			logger.debug(e.getMessage(),e);//详细日报信息
			logger.info(e.getMessage(),e);//详细日报信息
			logger.warn(e.getMessage());//简单日报信息
			logger.error(e.getMessage());//简单日报信息
		}
          }
}
  • 经过上述三步,最终Java工程结构如下:
    在这里插入图片描述
  • 运行Test类方法,打开D盘根目录中log.log文件可以看到相应的日志信息,此时的日志信息都会显示出来,Log4j常用日志级别从高到低依次为:ERROR、WARN、INFO和DEBUG,由于上例所设置的Log4j日志级别为DEBUG,所以ERROR、WARN和INFO 级别的日志信息也会显示出来。
  • 上例配置文件是将所有的日志信息都收集到了一个文件中,那么随着时间的推移,该文件会越来越大,内容也会越来越多,这不利于后期对日志文件进行分析,为了解决该问题可以这样配置log4j.properties文件:
# DEBUG设置输出日志级别,由于为DEBUG,所以ERROR、WARN和INFO 级别日志信息也会显示出来
log4j.rootLogger=DEBUG,RollingFile
#每天产生一个日志文件(RollingFile)  
log4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender
#当天的日志文件全路径
log4j.appender.RollingFile.File=d:/logs/sirius.log
#服务器启动日志是追加,false:服务器启动后会生成日志文件把老的覆盖掉
log4j.appender.RollingFile.Append=true
#日志文件格式  
log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout  
log4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p %-40.40c %X{traceId}-%m%n
log4j.appender.RollingFile.Threshold=DEBUG
#设置每天生成一个文件名后添加的名称,备份名称:sirius.log.年月日时分.log
log4j.appender.RollingFile.DatePattern='.'yyyy-MM-dd-HH-mm'.log'
  • DatePattern选项的有效值为:
    '.'yyyy-MM,对应monthly(每月)
    '.'yyyy-ww,对应weekly(每周)
    '.'yyyy-MM-dd,对应daily(每天)
    '.'yyyy-MM-dd-a,对应half-daily(每半天)
    '.'yyyy-MM-dd-HH,对应hourly(每小时)
    '.‘yyyy-MM-dd-HH-mm,对应minutely(每分钟)
    DatePattern中不用处理的文字要放到单引号(’)中,如上面的(.)。
2、通过throw或throws关键字抛出异常(详述参见Java异常中的throw和throws)
①throw(抛出异常对象):

格式:throw 异常对象

throw new NullPointerException();//抛出一个空指针异常对象
①throws(抛出异常对象):

格式:方法名([参数])throws 异常类名1,异常类名2,…{方法体}

public static void main(String[] args) throws Exception {
	String name;
	Class.forName("");//检查时异常
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值