JAVA基础——异常详解
JAVA异常与异常处理详解
⼀、异常简介
什么是异常?
异常就是有异于常态,和正常情况不⼀样,有错误出错。在java中,阻⽌当前⽅法或作⽤域的情况,称之为异常。
java中异常的体系是怎么样的呢?
1.Java中的所有不正常类都继承于Throwable类。Throwable主要包括两个⼤类,⼀个是Error类,另⼀个是Exception类;
2.其中Error类中包括虚拟机错误和线程死锁,⼀旦Error出现了,程序就彻底的挂了,被称为程序终结者;
3.Exception类,也就是通常所说的“异常”。主要指编码、环境、⽤户操作输⼊出现问题,Exception主要包括两⼤类,⾮检查异常(RuntimeException)和检查异常(其他的⼀些异常)
4.RuntimeException异常主要包括以下四种异常(其实还有很多其他异常,这⾥不⼀⼀列出):空指针异常、数组下标越界异常、类型转换异常、算术异常。RuntimeException异常会由java虚拟机⾃动抛出并⾃动捕获(就算我们没写异常捕获语句运⾏时也会抛出错误!!),此类异常的出现绝⼤数情况是代码本⾝有问题应该从逻辑上去解决并改进代码。
5.检查异常,引起该异常的原因多种多样,⽐如说⽂件不存在、或者是连接错误等等。跟它的“兄弟”RuntimeException运⾏异常不同,该异常我们必须⼿动在代码⾥添加捕获语句来处理该异常,这也是我们学习java异常语句中主要处理的异常对象。
⼆、try-catch-finally语句
(1)try块:负责捕获异常,⼀旦try中发现异常,程序的控制权将被移交给catch块中的异常处理程序。
【try语句块不可以独⽴存在,必须与 catch 或者 finally 块同存】
(2)catch块:如何处理?⽐如发出警告:提⽰、检查配置、⽹络连接,记录错误等。执⾏完catch块之后程序跳出catch块,继续执⾏后⾯的代码。
【编写catch块的注意事项:多个catch块处理的异常类,要按照先catch⼦类后catch⽗类的处理⽅式,因为会【就近处理】异常(由上⾃下)。】
(3)finally:最终执⾏的代码,⽤于关闭和释放资源。
=======================================================================
语法格式如下:
try{
//⼀些会抛出的异常
}catch(Exception e){
//第⼀个catch
//处理该异常的代码块
}catch(Exception e){
//第⼆个catch,可以有多个catch
//处理该异常的代码块
}finally{
//最终要执⾏的代码
}
当异常出现时,程序将终⽌执⾏,交由异常处理程序(抛出提醒或记录⽇志等),异常代码块外代码正常执⾏。 try会抛出很多种类型的异常,由多个catch块捕获多钟错误。
多重异常处理代码块顺序问题:先⼦类再⽗类(顺序不对编译器会提醒错误),finally语句块处理最终将要执⾏的代码。
=======================================================================
接下来,我们⽤实例来巩固try-catch语句吧~
先看例⼦:
1package st;
2
3public class TryCatchTest {
4/**
5 * divider:除数
6 * result:结果
7 * try-catch捕获while循环
8 * 每次循环,divider减⼀,result=result+100/divider
9 * 如果:捕获异常,打印输出“异常抛出了”,返回-1
10 * 否则:返回result
11 * @return
12*/
13public int test1(){
14int divider=10;
15int result=100;
16try{
17while(divider>-1){
18 divider--;
19 result=result+100/divider;
20 }
21return result;
22 }catch(Exception e){
23 e.printStackTrace();
24 System.out.println("异常抛出了!!");
25return -1;
26 }
27 }
28public static void main(String[] args) {
29// TODO Auto-generated method stub
30 TryCatchTest t1=new TryCatchTest();
31 System.out.println("test1⽅法执⾏完毕!result的值为:"+t1.test1());
32 }
33
34 }
运⾏结果:
结果分析:结果中的红⾊字抛出的异常信息是由e.printStackTrace()来输出的,它说明了这⾥我们抛出的异常类型是算数异常,后⾯还跟着原因:by zero(由0造成的算数异常),下⾯两⾏at表明了造成此异常的代码具体位置。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
在上⾯例⼦中再加上⼀个test2()⽅法来测试finally语句的执⾏状况:
1/**
2 * divider:除数
3 * result:结果
4 * try-catch捕获while循环
5 * 每次循环,divider减⼀,result=result+100/divider
6 * 如果:捕获异常,打印输出“异常抛出了”,返回result=999
7 * 否则:返回result
8 * finally:打印输出“这是finally,哈哈哈!!”同时打印输出result
9 * @return
10*/
11public int test2(){
12int divider=10;
13int result=100;
14try{
15while(divider>-1){
16 divider--;
17 result=result+100/divider;
18 }
19return result;
20 }catch(Exception e){
21 e.printStackTrace();
22 System.out.println("异常抛出了!!");
23return result=999;
24 }finally{
25 System.out.println("这是finally,哈哈哈!!");
26 System.out.println("result的值为:"+result);
27 }
28
29 }
30
31
32
33public static void main(String[] args) {
34// TODO Auto-generated method stub
35 TryCatchTest t1=new TryCatchTest();
36//System.out.println("test1⽅法执⾏完毕!result的值为:"+t1.test1());
37 t1.test2();
38 System.out.println("test2⽅法执⾏完毕!");
39 }
运⾏结果:
结果分析:我们可以从结果看出,finally语句块是在try块和catch块语句执⾏之后最后执⾏的。finally是在return后⾯的表达式运算后执⾏的(此时并没有返回运算后的值,⽽是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执⾏前确定的;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
这⾥有个有趣的问题,如果把上述中的test2⽅法中的finally语句块中加上return,编译器就会提⽰警告:finally block does not complete normally
1public int test2(){
2int divider=10;
3int result=100;
4try{
5while(divider>-1){
error parse new6 divider--;
7 result=result+100/divider;
8 }
9return result;
10 }catch(Exception e){
11 e.printStackTrace();
12 System.out.println("异常抛出了!!");
13return result=999;
14 }finally{
15 System.out.println("这是finally,哈哈哈!!");
16 System.out.println("result的值为:"+result);
17return result;//编译器警告
18 }
19
20 }
分析问题: finally块中的return语句可能会覆盖try块、catch块中的return语句;如果finally块中包含了return语句,即使前⾯的catch块重新抛出了异常,则调⽤该⽅法的语句也不会获得catch块重新抛出的异常,⽽是会得到finally块的返回值,并且不会捕获异常。
解决问题:⾯对上述情况,其实更合理的做法是,既不在try block内部中使⽤return语句,也不在finally内部使⽤ return语句,⽽应该在 finally 语句之后使⽤return来表⽰函数的结束和返回。如:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
总结:
1、不管有⽊有出现异常或者try和catch中有返回值return,finally块中代码都会执⾏;
2、finally中最好不要包含return,否则程序会提前退出,返回会覆盖try或catch中保存的返回值。
3. e.printStackTrace()可以输出异常信息。
4. return值为-1为抛出异常的习惯写法。
5. 如果⽅法中try,catch,finally中没有返回语句,则会调⽤这三个语句块之外的return结果。
6. finally 在try中的return之后在返回主调函数之前执⾏。
三、throw和throws关键字
java中的异常抛出通常使⽤throw和throws关键字来实现。
throw ----将产⽣的异常抛出,是抛出异常的⼀个动作。
⼀般会⽤于程序出现某种逻辑时程序员主动抛出某种特定类型的异常。如:
语法:throw (异常对象),如:
1public static void main(String[] args) {
2 String s = "abc";
3if(s.equals("abc")) {
4throw new NumberFormatException();
5 } else {
6 System.out.println(s);
7 }
8//function();
9 }
运⾏结果:
Exception in thread "main" java.lang.NumberFormatException
at test.ExceptionTest.main(ExceptionTest.java:67)
throws----声明将要抛出何种类型的异常(声明)。
语法格式:
1public void⽅法名(参数列表)
2throws异常列表{
3//调⽤会抛出异常的⽅法或者:
4throw new Exception();
5 }
当某个⽅法可能会抛出某种异常时⽤于throws 声明可能抛出的异常,然后交给上层调⽤它的⽅法程序处理。如:
1public static void function() throws NumberFormatException{
2 String s = "abc";
3 System.out.println(Double.parseDouble(s));
4 }
5
6public static void main(String[] args) {
7try {
8 function();
9 } catch (NumberFormatException e) {
10 println("⾮数据类型不能转换。");
11//e.printStackTrace();
12 }
13 }
throw与throws的⽐较
1、throws出现在⽅法函数头;⽽throw出现在函数体。
2、throws表⽰出现异常的⼀种可能性,并不⼀定会发⽣这些异常;throw则是抛出了异常,执⾏throw则⼀定抛出了某种异常对象。
3、两者都是消极处理异常的⽅式(这⾥的消极并不是说这种⽅式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调⽤处理。
来看个例⼦:
throws e1,e2,e3只是告诉程序这个⽅法可能会抛出这些异常,⽅法的调⽤者可能要处理这些异常,⽽这些异常e1,e2,e3可能是该函数体产⽣的。
throw则是明确了这个地⽅要抛出这个异常。如:
1void doA(int a) throws (Exception1,Exception2,Exception3){
2try{
3 ......
4
5 }catch(Exception1 e){
6throw e;
7 }catch(Exception2 e){
8 System.out.println("出错了!");
9 }
10if(a!=b)
11throw new Exception3("⾃定义异常");
12 }
分析:
1.代码块中可能会产⽣3个异常,(Exception1,Exception2,Exception3)。
2.如果产⽣Exception1异常,则捕获之后再抛出,由该⽅法的调⽤者去处理。
3.如果产⽣Exception2异常,则该⽅法⾃⼰处理了(即System.out.println("出错了!");)。所以该⽅法就不会再向外抛出Exception2异常了,void doA() throws Exception1,Exception3 ⾥⾯的Exception2也就不⽤写了。因为已经⽤try-catch语句捕获并处理了。
4.Exception3异常是该⽅法的某段逻辑出错,程序员⾃⼰做了处理,在该段逻辑错误的情况下抛出异常Exception3,则该⽅法的调⽤者也要处理此异常。这⾥⽤到了⾃定义异常,该异常下⾯会由解释。>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
使⽤throw和throws关键字需要注意以下⼏点:
1.throws的异常列表可以是抛出⼀条异常,也可以是抛出多条异常,每个类型的异常中间⽤逗号隔开
2.⽅法体中调⽤会抛出异常的⽅法或者是先抛出⼀个异常:⽤throw new Exception() throw写在⽅法体⾥,表⽰“抛出异常”这个动作。
3.如果某个⽅法调⽤了抛出异常的⽅法,那么必须添加try catch语句去尝试捕获这种异常,或者添加声明,将异常抛出给更上⼀层的调⽤者进⾏处理>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
⾃定义异常
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论