java exception 语法_Java异常机制

C语言编程中通过返回值来判断程序是否运行正常。而Java设计了一套异常机制来处理程序运行过程不正常的情况,这点非常重要,只有了解这一点,才能判断什么时候该抛异常,抛出什么异常,异常什么时候该被处理。

1、Java异常的相关语法

try-catch-finally,throw,throws

2、Java异常的分类

Java通过Exception类创建一套异常体系,定义了一系列有语义的运行时发生的可被捕获或者处理的各种错误。例如IOException,IllegalArgumentException。这点要比通过返回值来判断错误要强很多。

这点非常重要,异常就是运行的错误,它没什么,就是起到了告诉调用者程序出现的错误,如果抛出一个异常类,没有定义清楚错误的信息,那么无疑是失败的,不合理的。既然是错误信息,可被捕获,那么如果捕获要么自己容忍处理,记录下错误信息,要么继续加强异常错误的信息量,继续扔出让上层调用者更加明白出现的错误是个什么东西。

Java异常分为Checked异常和UnChecked异常,前者继承自Exception类,后者继承RuntimeException类。两种异常都是可以throw,可以catch的。区别在于Java语言本身是如何对待两种异常,以及两种异常所代表的语义和应用场景。

(1)Checked异常,就是需要被处理的异常。大家经常见到的IOException、SQLException这些,需要try-catch或者进一步throws给上层,如果不做就会出现语法错误。这是Java在编译器强制调用者处理其中方法抛出的checked异常。这类异常一般是可预期的,可预期的意思就是,上层调用者拿到你的异常后,知道它如何产生的,也预料到它会产生,所以才有抛出去的必要,才可以采取措施去处理它:容忍异常继续调用运行其他代码或者重试修复异常或者扔给上层。如果你扔给上层一个异常,上层也不知道它是干什么的,那么就没必要定义为Checked异常。对于这种异常,我们本身无法处理,也就是无法修复,但是上层知道这个异常,有办法处理,那么就应该扔给上层。那么需要捕获,还是直接抛出?捕获,再抛出:代表这个异常说明的还不够清楚,我们需要进一步加强说明,再扔给上层,上层调用者才更清楚知道如何处理

(2)UnChecked异常,就是不强制要求处理的异常。例如经常见到的参数、状态非法的异常IllegalArgumentException,这种异常表示的语义是出现了大家预期之外的异常。本来约定的参数,按照正确的传入就行了,但是传入非法的,在上层调用者意料之外,那么它就不会事先写好try-catch去处理。因此Java不在编译期从语法上要求捕获该类异常。如果出现了该类异常后,那么就直接trhow运行时异常就行了。虽然语法上不强制要求处理该类异常,但是到底该不该catch呢?这种异常上层调用者压根就没预料到,所以也不会去处理。但是一旦抛出异常,throw后,不管是Checked异常还是UnChecked异常,程序都会终止运行。那么万一后面的代码在干很重要的事情怎么办,因此一些非常重要的代码,不管有没有异常,都会try-catch,然后catch中记录异常就行了,保证后面代码的运行。

(3)catch捕获异常该做些什么呢,如果什么都不做,那么就不需要catch,直接在函数后面throws扔给上层,书写try-finally就行。可以干些什么呢?三件事:将异常的发生原因进一步描述,也就是封装的更加细致,加上一些描述信息,再扔给上层,这时也可以log记录下错误信息,防止无人记录错误原因;上层获取该异常没有太大价值,当前程序可以容忍这种错误,那么记录下来错误原因,继续执行其他代码;记录错误原因,采取一些措施进行重试或者修复工作

(4)自定义异常:这种场景很少见。不管是Checked异常还是UnChecked异常,Java都提供了几乎覆盖各种错误的异常类。我们只需要加上一些特殊文字说明就行了,自定义异常类除了可能导致错误语义表达不清晰,还会造成额外代码。

再次强调异常传达的是一种程序运行的错误信息,既然是错误信息就应该根据错误的类型进行符合场景的处理,没有什么统一的处理方式,了解其本质,才能灵活应用。下面针对具体代码进行讲解

/发现很多地方省去了log记录异常信息,因为即使记录也只是传达给日后分析的人员,而没有起到告知上层调用者的目的。

publicclassTask2 {

privatestaticfinalLogger log = LoggerFactory.getLogger(Task2.class);

publicstaticvoidreplaceCode(String propFilePath, String templateFilePath, String desFilePath)throwsIOException {

Validate.notBlank(propFilePath);//这个方法会判断参数是否为空,来抛出运行时异常。因为接口需要传入的参数各种路径是不能为空的,但是传入为空,那么就是意料之外,调用者不会一方面知

//道会出现参数异常,进行捕获处理,一方面又传入非法的参数。错误的产生是上层调用者无意之间导致的,如果知道这个异常是可以提前避免的。而IOException

//这种异常,即使之前做了狠多准备,还是可以产生这种错误

Validate.notBlank(templateFilePath);

Validate.notBlank(desFilePath);

finalBufferedWriter destWriter;

try{

destWriter = IOUtil.converseBufferdWriter(IOUtil.getFileWriter(desFilePath));

} catch(UnsupportedEncodingException e1) {

thrownewUnsupportedEncodingException("输出文件"+ e1.getMessage());//对下层函数抛出的异常进一步包装,再扔出,让上层调用者知道这是输出文件编码不对,而不是普通的

//IOException

} catch(FileNotFoundException e1) {

thrownewFileNotFoundException("输出文件"+ e1.getMessage());

}

URL templateURL = Resources.getResource(templateFilePath);

finalStrSubstitutor strSub = getPropStrSub(propFilePath);

try{

Resources.readLines(templateURL, Charsets.UTF_8, newLineProcessor() {

intlineNumber =0;

@Override

publicbooleanprocessLine(String line)throwsIOException {

if(lineNumber >0) {

destWriter.newLine();

}

lineNumber++;

returnreplaceCodePerLine(line, strSub, destWriter);

}

@Override

publicString getResult() {

returnnull;

}

});

} catch(IOException e) {

thrownewIOException("模板文件读取错误", e);//继续抛出异常,因为读取错误的IOException是调用者可预知的,读文件会出现错误。这里加强了语义扔出

} finally{

Closeables.closeQuietly(destWriter);//这里也该抛出异常,但是guava实现的是容忍这种错误,只记录了日志。应该告诉上层关闭文件出错

}

}

privatestaticbooleanreplaceCodePerLine(String line, StrSubstitutor strSub, BufferedWriter destWriter)throwsIOException

{

if(strSub ==null|| destWriter ==null) {

returnfalse;

}

if(StringUtils.contains(line,'$')) {

line = strSub.replace(line);

}

try{

destWriter.append(line);

} catch(IOException e) {

thrownewIOException("输出文件写入出错");//继续抛出异常,因为读取错误的IOException是调用者可预知的,读文件会出现错误。这里加强了语义扔出

}

returntrue;

}

publicstaticStrSubstitutor getPropStrSub(String propFilePath)throwsIOException {

finalHashMap propMap = Maps.newHashMap();

URL propURL = Resources.getResource(propFilePath);

try{

Resources.readLines(propURL, Charsets.UTF_8, newLineProcessor() {

@Override

publicbooleanprocessLine(String line)throwsIOException {

String[] metas = StringUtils.split(line, "=");

if(metas.length !=2)

returnfalse;

propMap.put(metas[0], metas[1]);

returntrue;

}

@Override

publicString getResult() {

returnnull;

}

});

} catch(IOException e) {

thrownewIOException("读取配置文件出错");//继续抛出异常,因为读取错误的IOException是调用者可预知的,读文件会出现错误。这里加强了语义扔出

}

returnnewStrSubstitutor(propMap);

}

publicstaticvoidmain(String[] args) {

longstartTime = System.currentTimeMillis();

try{

Task2.replaceCode("sdxl.properties","temp.txt","output.txt");

}catch(IOException e){

log.error(e.getMessage,e);//main的上层调用者就是系统进程,上层对IOException不清楚,也无法处理,因此直接记录异常即可。

}

System.out.println(System.currentTimeMillis() - startTime);

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值