异常就是程序出现了不正常的状况。html
发现错误的理想时机是在编译期。然而,编译器并不能发现全部的错误,余下的问题就须要在程序运行时解决。这就须要错误能经过某种方式,把适当的信息传递给特定的接收者处理。Java中的异常处理的目的在于经过使用少许的代码来简化大型、可靠的程序的生成,经过此方式让你的应用中没有未处理的错误,并且它还带来了一个明显的好处:下降错误处理代码的复杂度。java
异常,根据字面理解,有意外之意。把它置于代码层面来理解,即阻止了当前方法或做用域继续执行。数据库
在Java中,异常被当作对象来处理,其基类是Throwable。数组
Java中的全部不正常类都继承于Throwable类。Throwable主要包括两个大类,一个是Error类,另外一个是Exception类;网络
其中Error类中包括虚拟机错误和线程死锁,一旦Error出现了,程序就完全的挂了,被称为程序终结者;这种问题通常都是很严重的,不是咱们处理的。jvm
Exception类,也就是一般所说的“异常”。主要指编码、环境、用户操做输入出现问题,Exception主要包括两大类,编译期异常和运行期异常(RuntimeException)ide
RuntimeException异常主要包括如下四种异常(其实还有不少其余异常,这里不一一列出):空指针异常、数组下标越界异常、类型转换异常、算术异常。RuntimeException异常会由java虚拟机自动抛出并自动捕获(就算咱们没写异常捕获语句运行时也会抛出错误!!),此类异常的出现绝大数状况是代码自己有问题应该从逻辑上去解决并改进代码。学习
不是RuntimeException的异常都是编译期异常,引发该异常的缘由多种多样,好比说文件不存在(IOException)、或者是链接错误(SQLException)等等。跟它的“兄弟”RuntimeException运行异常不一样,该异常咱们必须手动在代码里添加捕获语句来处理该异常,由于你不处理,编译就不能经过。这也是咱们学习java异常语句中主要处理的异常对象。测试
下面经过一个例子来理解上述异常分类:编码
今每天气很好,班长出去旅游。骑着自行车,去山里面呼吸新鲜空气。
Error:走到半路上,发生山路塌陷,或者出现了泥石流,这个问题很严重,不是班长可以立马解决的。严重的问题
Exception:出门前,班长要看看车轮子以及车链子等是否还在。出发前就应该检查的问题。
RuntimeException:在骑车的过程当中,有好路不走,恰恰要走石子路,结果爆胎了。旅游的过程当中出现的问题。
Java中的异常被分为两大类:编译时异常和运行时异常。全部的RuntimeException类及其子类的实例被称为运行时异常,其余的异常就是编译时异常
编译时异常:Java程序必须显示处理,不然程序就会发生错误,没法经过编译。
运行时异常:无需显示处理,也能够和编译时异常同样处理
此对象的类的 name(全路径名) ": "(冒号和一个空格) 调用此对象 getLocalizedMessage()方法的结果 (默认返回的是getMessage()的内容)
public class ExceptionDemo { public static void main(String[] args) { String s = "2014-11-20"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date d = sdf.parse(s); // 建立了一个ParseException对象,而后抛出去,和catch里面进行匹配 System.out.println(d); } catch (ParseException e) { // ParseException e = new ParseException(); // ParseException // e.printStackTrace(); // getMessage() // System.out.println(e.getMessage()); // Unparseable date: "2014-11-20" // toString() // System.out.println(e.toString()); // java.text.ParseException: Unparseable date: "2014-11-20" e.printStackTrace(); //跳转到某个指定的页面(index.html) } System.out.println("over"); } }
如何程序出现了问题,咱们没有作任何处理,最终jvm会作出默认的处理。处理方式是:
把异常的名称,缘由及出现的问题等信息输出在控制台。
同时会结束程序。
1 public class ExceptionDemo { 2 public static void main(String[] args) { 3 // 第一阶段 4 int a = 10; 5 int b = 0; 6 System.out.println(a / b); 7 8 // 第二阶段 9 System.out.println("over"); 10 } 11 }
上述程序中,咱们并无作任何处理,运行到第6行时,程序报错,并结束程序,致使"over"并无输出。
格式:
try { 可能出现问题的代码; }catch(异常名 变量) { 针对问题的处理; }
格式说明:
try块:负责捕获异常,一旦try中发现异常,程序的控制权将被移交给catch块中的异常处理程序。try语句块不能够独立存在,必须与 catch 或者 finally 块同存
catch块:如何处理?好比发出警告:提示、检查配置、网络链接,记录错误等。执行完catch块以后程序跳出catch块,继续执行后面的代码。
public class ExceptionDemo { public static void main(String[] args) { // 第一阶段 int a = 10; // int b = 2; int b = 0; try { System.out.println(a / b); } catch (ArithmeticException ae) { System.out.println("除数不能为0"); } // 第二阶段 System.out.println("over"); } }
注意:
A:try里面的代码越少越好。由于try里面的代码要走异常处理机制,jvm就会开辟新的资源来管理,代码越多,Java就要用更多的资源来处理它。
B:catch里面必须有内容,哪怕是给出一个简单的提示
格式:
try{ ... }catch(异常类名 变量名) { ... } catch(异常类名 变量名) { ... } ...
注意事项:
public class ExceptionDemo { public static void main(String[] args) { // method1(); method2(); } public static void method2() { int a = 10; int b = 0; int[] arr = { 1, 2, 3 }; // 爷爷在最后 try { System.out.println(a / b); System.out.println(arr[3]); System.out.println("这里出现了一个异常,你不太清楚是谁,该怎么办呢?"); } catch (ArithmeticException e) { System.out.println("除数不能为0"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("你访问了不应的访问的索引"); } catch (Exception e) { System.out.println("出问题了"); } // 爷爷在前面是不能够的 /*try { System.out.println(a / b); System.out.println(arr[3]); System.out.println("这里出现了一个异常,你不太清楚是谁,该怎么办呢?"); } catch (Exception e) { System.out.println("出问题了"); } catch (ArithmeticException e) { System.out.println("除数不能为0"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("你访问了不应的访问的索引"); }*/ } public static void method1() { int a = 10; int b = 0; int[] arr = {1, 2, 3}; try { System.out.println(a / b); System.out.println(arr[3]); } catch (ArithmeticException e) { System.out.println("除数不能为0"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("你访问了不应的访问的索引"); } System.out.println("over"); } }
注意:
一旦try里面出了问题,就会在这里把问题给抛出去,而后和catch里面的问题进行匹配,一旦有匹配的,就执行catch里面的处理,而后结束了try...catch,继续执行后面的语句。
【JDK7新特性】
JDK7出现了一个新的异常处理方案:
try{ }catch(异常名1 | 异常名2 | ... 变量 ) { ... }
注意:这个方法虽然简洁,可是也不够好。
A:处理方式是一致的。(实际开发中,好多时候可能就是针对同类型的问题,给出同一个处理)
B:多个异常间必须是平级关系。
public class ExceptionDemo { public static void main(String[] args) { method(); } public static void method() { int a = 10; int b = 0; int[] arr = {1, 2, 3}; /*try { System.out.println(a / b); System.out.println(arr[3]); } catch (ArithmeticException e) { System.out.println("除数不能为0"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("你访问了不应的访问的索引"); } catch (Exception e) { System.out.println("出问题了"); }*/ // JDK7的处理方案 try { System.out.println(a / b); System.out.println(arr[3]); } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) { System.out.println("出问题了"); } System.out.println("over"); } }
格式:try...catch...finally...
特色:被finally控制的语句体必定会执行。特殊状况:若是在执行到finally以前jvm退出了,就不能执行了。
做用:用于释放资源,在IO流操做和数据库操做中会见到
public class FinallyDemo { public static void main(String[] args) { String s = "2018--5-16"; SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = null; try { date = format.parse(s); } catch (ParseException e) { e.printStackTrace(); //System.exit(0);//jvm退出,finally的代码不会执行 }finally { System.out.println("这里的代码是能够执行的"); } System.out.println(date); } }
【final,finally和finalize的区别】
final:最终的意思,能够修饰类,成员变量,成员方法
修饰类,类不能被继承
修饰变量,变量是常量
修饰方法,方法不能被重写
finally:是异常处理的一部分,用于释放资源。
通常来讲,代码确定会执行,特殊状况:在执行到finally以前jvm退出了
finalize:是Object类的一个方法,用于垃圾回收
【补充问题】
若是catch里面有return语句,请问finally里面的代码还会执行吗?若是会,请问是在return前,仍是return后?
答:会。在return前。(准确的说,应该是在中间)
public class FinallyDemo2 { public static void main(String[] args) { System.out.println(getInt()); } public static int getInt() { int a = 10; try { System.out.println(a / 0); a = 20; } catch (ArithmeticException e) { a = 30; return a; /* * return a在程序执行到这一步的时候,这里不是return a而是return 30;这个返回路径就造成了。 * 可是呢,它发现后面还有finally,因此继续执行finally的内容,a=40 * 再次回到之前的返回路径,继续走return 30; */ } finally { a = 40; // return a;//若是这样结果就是40了。 } return a; } }
有些时候,咱们是能够对异常进行处理的,可是又有些时候,咱们根本就没有权限去处理某个异常。或者说,我处理不了,我就不处理了。为了解决出错问题,Java针对这种状况,就提供了另外一种处理方案:throws(抛出)。
格式:throws 异常类名
注意:这个格式必须跟在方法的括号后面。
public class ExceptionDemo { public static void main(String[] args) { System.out.println("今每天气很好"); try { method(); } catch (ParseException e) { e.printStackTrace(); } System.out.println("可是就是不应有雾霾"); method2(); } // 运行期异常的抛出 public static void method2() throws ArithmeticException { int a = 10; int b = 0; System.out.println(a / b); } // 编译期异常的抛出 // 在方法声明上抛出,是为了告诉调用者,你注意了,我有问题。 public static void method() throws ParseException { String s = "2018-11-20"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d = sdf.parse(s); System.out.println(d); } }
小结:
编译期异常抛出,未来调用者必须处理。
运行期异常抛出,未来调用能够不用处理。
在功能方法内部出现某种状况,程序不能继续运行,须要进行跳转时,就用throw把异常对象抛出。
public class ExceptionDemo { public static void main(String[] args) { // method(); try { method2(); } catch (Exception e) { e.printStackTrace(); } } /** * 若是throw的是运行期异常,方法上就不须要throws了 */ public static void method() { int a = 10; int b = 0; if (b == 0) { throw new ArithmeticException(); } else { System.out.println(a / b); } } /** * 若是throw的是编译时期异常,由于你既然写了throw,说明你不想在这里try...catch了,因此要在方法上throws出该异常 * @throws Exception */ public static void method2() throws Exception { int a = 10; int b = 0; if (b == 0) { throw new Exception(); } else { System.out.println(a / b); } } }
【throws和throw的区别】
throws:
throw:
java不可能对全部的状况都考虑到,好比考试成绩必须在0-100之间,若是成绩超过100或成绩小于0的话,都属于异常,很明细Java中没有对应的异常,这时候就须要咱们本身来作一个异常。
而咱们本身随意的写一个类,是不能做为异常类来看的,要想你的类是一个异常类,就必须继承自Exception或者RuntimeException
public class MyException extends Exception { public MyException() { } public MyException(String message) { super(message); } }
定义一个类:
public class Teacher { public void check(int score) throws MyException { if (score > 100 || score < 0) { throw new MyException("分数必须在0-100之间"); } else { System.out.println("分数没有问题"); } } }
自定义异常测试类
public class StudentDemo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入学生成绩:"); int score = sc.nextInt(); Teacher t = new Teacher(); try { t.check(score); } catch (MyException e) { e.printStackTrace(); } } }
public class ExceptionDemo { } class Fu { public void show() throws Exception { } public void method() { } } class Zi extends Fu { @Override public void show() throws ArithmeticException { } @Override public void method() { // String s = "2014-11-20"; // SimpleDateFormat sdf = new SimpleDateFormat(); // Date d = sdf.parse(s); // System.out.println(d); } }