这篇我们聊聊java中的异常。首先我们要知道什么是异常?

Exception:

exception翻译过来就是“意外”的意思。事实上,异常的本质就是程序的错误,包括程序逻辑错误和系统错误。错误在编写程序中会时常出现,包括编译期间错误和运行期间的错误。编译期间的错误编译器会帮助我们一起修正,但是运行期间的错误编译器就无能为力了。如果程序在运行期间出了错误我们置之不理,程序就会终止或者直接导致系统崩溃,后果还是很严重的。那么,对运行期间出现的错误我们如何处理或补救呢?java很贴心的提供了异常处理机制来处理运行期间出现的错误,异常处理机制可以帮助我们更好的提升程序的健壮性。

下面我们来看下java中异常的分类:

在java中Throwable是所有异常的父类,Error类是error类型异常的父类,Exception是exception类型异常的父类,RuntimeException类是所有运行时异常的父类RuntimeException以外的且继承Exception的类是非运行时异常。

了解了什么是异常后,那么我们如何处理异常?

在java中如果需要处理异常,必须先对异常进行捕获,然后再对异常情况进行处理。如何对可能发生的异常代码进行异常捕获和处理呢?使用 try catch关键字即可。

一个栗子:

public static void main(String[] args) {
try {
File file = new File("d:/a.txt");
if(!file.exists()){
file.createNewFile();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

被try包含的代码说明这段代码可能会发生异常,一旦发生异常,异常便会被catch捕获到,然后需要在catch块中进行异常处理。

这是一种处理方式。在java中还提供了另外一种异常处理方式 即 抛出异常。顾名思义,也就是说一旦发生异常,我就把这个异常抛出去,让调用者去处理,自己不进行具体处理,此时需要用到throw和throws关键字。

一个栗子:

public class Test02 {
public static void main(String[] args) {
try {
createFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public static void createFile() throws IOException{
File file = new File("d:/b.txt");
if(!file.exists()){
file.createNewFile();
}
}
}

这段代码和上段代码的区别是,在实际的createFile方法中并没有捕获异常,而是使用throws关键字声明抛出异常,即告知这个方法的调用者此方法可能会抛出IOException异常,那么在main方法中调用createFile方法的时候,采用了try...catch块进行了异常捕获处理。

当然还可以使用throw关键字手动抛出异常对象,一个栗子:

public class Test03 {
public static void main(String[] args) {
try {
int[] data = new int[]{1,2,3};
getDataByIndex(-1,data);
} catch (Exception e) {
System.out.println(e.getMessage());
}
} public static int getDataByIndex(int index,int[] data){
if(index <0 || index >data.length){
throw new ArrayIndexOutOfBoundsException("数组下标越界异常");
}
return data[index];
}
}

通过这三段代码,我们知道java中异常处理的话,有三种方式:

1)对代码块使用try...catch进行异常捕获处理;

2)在该代码的方法体外使用throws进行抛出声明,告知此方法的调用者这段代码可能会出现这些异常,需谨慎处理。此时有两种情况:

  如果声明抛出的异常是运行时异常,调用者可以选择性的进行异常捕获处理;

  如果声明抛出的异常是非运行时异常,调用者必须显式的使用try...catch进行捕获或者继续向上层抛出异常;

3)在代码块用throw手动抛出一个异常,此时也有两种情况,与2)类似:

  如果抛出的异常对象是运行时异常,调用者可以选择性的进行异常捕获处理;

  如果抛出的异常对象是非运行时异常,调用者必须显式的使用try...catch进行捕获或者继续向上层抛出异常。

注意:如果最终将方法抛给main方法,则相当于交给JVM自动处理,此时JVM会简单的打印异常信息。

关于 try,catch,finally,throw,throws 这五个关键字

1、try,catch,finally

try关键字用来包围可能会出现异常的逻辑代码,它无法单独使用,必须搭配catch,finally使用。java编译器允许的组合形式有如下三种:

try...catch...;  try...finally...;  try...catch...finally...;

注意:

1)try块只能有一个,catch块可以有多个,finally块最多只能有一个;

2)三个块的执行顺序 try-->catch-->finally;

3)如果没有发生异常,catch块不会被执行;但finally块无论在什么情况下都是会被执行的(释放资源一般放在finally块中);

4)有多个catch块的情况下,是按照catch块的先后顺序进行匹配的,一旦异常被一个catch块匹配,则不会与后续的catch块匹配;

5)有finally块的情况下,千万不要在finally块中使用return,因为finally块中的return会覆盖已有的返回值。

一个栗子:

public class Test04 {
public static void main(String[] args) {
String str = new Test04().openFile();
System.out.println(str);
} public String openFile(){
try {
FileInputStream inputStream = new FileInputStream("d:/a.txt");
int ch = inputStream.read();
System.out.println("aaa");
return "step1";
} catch (FileNotFoundException e) {
System.out.println("file not found");
return "step2";
} catch (IOException e) {
System.out.println("io exception");
return "step3";
}finally{
System.out.println("finally block");
//return "finally";
}
}
}

控制台输出:

file not found
finally block
step2

可以看出,在try块中发生FileNotException之后,就跳到了第一个catch块,打印"file not found"信息,并将"step2"赋值给返回值,然后执行finally块,最后将返回值返回。

如果我们将finally块中return语句的注释释放开,会发生什么呢?

控制台输出:

file not found
finally block
finally

最后打印的是"finally",返回值被重新覆盖了。

所以如果方法有返回值,切记不要在finally里面写return语句。

2、throw和throws

1)throws出现在方法声明中,表示该方法可能会抛出异常,然后交给上层调用它的方法进行处理,允许throws后面跟着多个异常类型;

2)throw一般用于 在程序出现某种逻辑时,程序员主动抛出某种特定类型的异常。throw只会出现在方法体中,当方法在执行过程中遇到异常情况时,将异常信息封装为异常对象,然后throw出去。throw关键字的一个非常重要的作用就是异常类型的转换。

throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。两者都是消极处理异常的方式(并不是说不好),只是抛出或者可能抛出异常,当时不会由方法去处理异常,真正的处理异常由调用此方法的上层方法处理。

在类继承的时候,子类重写父类的方法,如何进行异常抛出声明?

遵循三点原则:

1)父类的方法没有声明异常,子类在重写该方法时不能声明异常;

2)如果父类的方法声明一个异常exception1,则子类在重写该方法时声明的异常不能是exception1的父类;

3)如果父类方法声明的异常类型只有运行时异常,则子类在重写该方法时也只能有运行时异常,不能有非运行时异常。

如图:

异常处理和设计的几个建议

1)谨慎的使用异常,不要使用异常去控制程序的流程;

  异常捕获的代价非常高昂,过多的使用异常会严重影响程序的性能。如果在程序中能够使用if语句或Boolean变量来进行逻辑判断,那么尽量减少异常的使用。

一个栗子:

public void useExceptionsForFlowControl() {   

  try {   

  while (true) {   

    increaseCount();   

    }   

  } catch (MaximumCountReachedException ex) {   

  }   

  //Continue execution   

}   

public void increaseCount() throws MaximumCountReachedException {   

  if (count >= 5000)   

    throw new MaximumCountReachedException();   

}

栗子中的useExceptionsForFlowControl()用一个无限循环来增加count直到抛出异常,这种做法并没有让代码不易读,但是却降低了程序的执行效率。

2)切忌使用空catch块

  在捕获异常之后什么都不做,相当于忽略了这个异常,空catch块意味着你的程序中隐藏了错误和异常,可能会导致程序出现不可控的结果。如果你非常确定捕获到的异常不会对程序造成影响,可以使用log日志记录,以便后续的更新和维护。

3)检查异常和非检查异常

  尽量避免使用检查异常,或者将检查异常转变为非检查异常交给上层处理。

4)注意catch块的顺序

5)不要将提供给用户看的信息放在异常信息里

  比较好的方式是将所有错误信息放在一个配置文件中统一管理。

6)避免多次在日志信息中记录同一个异常

  最好只在异常最开始发生的地方进行日志信息记录。

7)异常处理尽量放在高层进行

8)在finally中释放资源

参考博主Matrix海 子 https://www.cnblogs.com/dolphin0520/p/3769804.html

Java_异常处理的更多相关文章

  1. Java_异常处理误区

    转自:https://www.ibm.com/developerworks/cn/java/j-lo-exception-misdirection/index.html 本文着重介绍了 Java 异常 ...

  2. Java_异常处理(Exception)

    异常:Exception try{ //捕获异常 }catch{ //处理异常 } 异常处理机制: 1.在try块中,如果捕获了异常,那么剩余的代码都不会执行,会直接跳到catch中, 2.在try之 ...

  3. JAVA_输入输出流 异常处理

    输入输出流 文件创建

  4. Java_框架面试题

    Java_框架面试题 欢迎来我Git上分享您的优秀建议 1.Spring框架分为哪七大模块,各模块的主要功能作用是什么? 七大模块,如下: 1. Spring Core: Core封装包是框架的最基础 ...

  5. 关于.NET异常处理的思考

    年关将至,对于大部分程序员来说,马上就可以闲下来一段时间了,然而在这个闲暇的时间里,唯有争论哪门语言更好可以消磨时光,估计最近会有很多关于java与.net的博文出现,我表示要作为一个吃瓜群众,静静的 ...

  6. 基于spring注解AOP的异常处理

    一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...fin ...

  7. 异常处理汇总 ~ 修正果带着你的Net飞奔吧!

    经验库开源地址:https://github.com/dunitian/LoTDotNet 异常处理汇总-服 务 器 http://www.cnblogs.com/dunitian/p/4522983 ...

  8. JavaScript var关键字、变量的状态、异常处理、命名规范等介绍

    本篇主要介绍var关键字.变量的undefined和null状态.异常处理.命名规范. 目录 1. var 关键字:介绍var关键字的使用. 2. 变量的状态:介绍变量的未定义.已定义未赋值.已定义已 ...

  9. IL异常处理

    异常处理在程序中也算是比较重要的一部分了,IL异常处理在C#里面实现会用到一些新的方法 1.BeginExceptionBlock:异常块代码开始,相当于try,但是感觉又不太像 2.EndExcep ...

随机推荐

  1. ssh免密登陆:sshpass -p [passwd] ssh -p [port] root@192.168.X.X

    正文: ssh免密登陆:sshpass -p [passwd] ssh -p [port] root@192.168.X.X

  2. 强大的Resharp插件(转)

    使用VS有段时间了,一直深深的折服于其强大的功能.之前一直听说有Resharp这个工具,小猪一直也没有太在意.直到今天…… 下载安装: http://www.jetbrains.com/resharp ...

  3. python pymysql.err.InternalError: (1366, "Incorrect string value: '\\xE9\\x9F\\xA9\\xE6\\xA2\\x85...

    python3使用pymysql报错:   image.png 代码: #插入数据 try: sql = 'INSERT INTO classb (a_id,name,age) VALUES (6,& ...

  4. 在JavaScript中,如何判断数组是数组?

    如果你没有注意过这个问题,那么这个标题应该会让你感到困惑,判断数据类型这么基础的问题能有什么坑呢? 少年,你不能太天真了,我们朝夕面对的这门语言,可是JavaScript呀,任何你觉得已经习以为常的东 ...

  5. C# this关键字的四种用法

    Go to below URL to find more details and example. http://blog.csdn.net/longlong821/article/details/7 ...

  6. flutter 解析json

    关于flutter 解析json 自己看了几天,最近才大概知道是怎么个情况. 首先 要处理的 是后端返回的数据 ,如果是直接请求的话返回的是json 字符串 然后要把字符串转成对象,有几种方式参考 第 ...

  7. Chrome浏览器自动填充<input>标签的密码

    问题:登录页面登录时,Chrome浏览器保存了用户名和密码,在其他页面管理其他的账户和密码时,密码框先是显示正确的密码,然后一闪而过被覆盖. 原因:问了技术主管才得知,Chrome浏览器中的,保存用户 ...

  8. 怎样解决if __name__ == "__main__":下面的代码没有执行的问题

    很多初学者可能在用pycharm运行代码时会出现if __name__ == "__main__":下面的代码没有执行的问题,出现这类问题的原因是unittest运行姿势造成的,如 ...

  9. 字符串string的相关应用

    之所以抛弃char* 的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够.字符串长度等等, 而且作为一个泛型类出现,他集成的操作函数足以完成我们大多数情况下 ...

  10. java web项目最简单的结构

    为了解“徒手”建立一个web应用,此博客建立简单过程 1.在任意一个目录下,建立一个文件夹,取名字 webDemo .这个应用名字. 2.在 webDemo 内建立一个 WEB-INF 文件夹,此处大 ...