java异常对象都派生于Throwable。Throwable分为两个分支:Error和Exception。Exception是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应的处理。Error是指正常情况下,不大可能出现的情况,一般与JVM有关,如系统奔溃,虚拟机错误,动态链接失败。既然是非正常情况,所以不便于也不需要捕获,常见的比如OutOfMemoryError之类。

 

 

 

java语言规范将派生于Error或RunTimeException的所有异常成为未检测(unchecked)异常。RunTimeException运行时异常通常在我们控制下,如ArrayIndexOutOfBoundException,修正程序。

所有其他异常为已检查(checked)异常

可检查异常在源码里必须显示的进行捕获处理或者进行thorws声明抛出让其他捕获器处理。当有异常(未检测/已检查)发生,没有进行捕获时候,当前执行线程会结束。先catch小异常(子异常)再catch大异常(父异常)。只能catch可能抛出异常的语句。

父类方法申明异常A。子类方法可以申明抛出A或者A的子类异常,或者不抛异常。但是不能抛出B异常。父类方法不抛异常,子类方法不能抛异常。

用thorws声明抛异常,thorw抛异常动作。

String readData(Scanner in) thorws EOFException
{
      ...
  while(...){
   if(in.hasNext()){
     if(n<len)
        thorw new EOFException();
        
     }
      ...
   }
   retrun s;
}

案例1 catch中异常或者有没有捕获的异常

inputStream in=new FileInputStream(...);
    try
    {
     //1
        code that might throw exception
    //2
    }
    catch(IOException e)
    {
    //3
    show error message
    //4
    }
    finally
    {
    //5
    in.close();
    }
    //6                

1。正常流程抛出异常,并捕获了。捕获的代码处没有抛出其他异常,则执行顺序1,3,4,5,6。

2。如果catch子句抛出一个异常,异常将会抛回给调用者,执行1,3,5代码6不行。

3。代码抛出异常,但是不是catch捕获的异常,则只执行1,5。

案例2 System.exit(0); 在finally前

public class ExitFinally
{
    public static void main(String[] args)    
        throws IOException
    {
        FileOutputStream fos = null;
        try
        {
            fos = new FileOutputStream("a.bin");
            System.out.println("程序打开物理资源");
            System.exit(0);
        }
        finally
        {
            //使用finally关闭资源
            if (fos != null)
            {
                try
                {
                    fos.close();
                }
                catch (Exception ex)
                {
                    ex.printStackTrace();
                }
            }
            System.out.println("程序关闭物理资源");
        }
    }
}
  System.exit(0);停止当前线程和所有其他线程。所有finally不会执行。
案例3 return
public class FinallyFlowTest
{
    public static void main(String[] args)
    {
        int a = test();
        System.out.println(a);
    }
    public static int test()
    {
        int count = 5;
        try
        {
            //因为在finally块里面包含了return云居
            //则下面的count++执行,先使用标记return 5;此时count为6
            return count++;//code1
        }
        finally
        {
            System.out.println("finally块被执行了");
        //     i++ 和 ++i 在理论上的区别是:
        // i++:是先把i拿出来使用,然后再+1;
 // ++i :是先把i+1,然后再拿出来使用;
            return count++;//标记返回6,此时count为7
        }
    }
}

 解析:返回6。code1处无论是count++或者++count。都会执行此时count为6,count++第一个renturn是5,++count的时候第一个return是6.

第二个return count++;先使用再++。即返回值是当前的count。所以为6若改为return ++count;则返回为7

public class FinallyFlowTest
{
    public static void main(String[] args)
    {
        int a = test();
        System.out.println(a);
    }
    public static int test()
    {
        int count = 5;
        try
        {
             //因为在finally块里面包含了return云居
            //则下面的count++先使用标记下返回5再++此时就为6
            return count++;
        }
        finally
        {
            System.out.println("finally块被执行了");
            System.out.println("count:"+count);//打印6
             count++;//执行7
             System.out.println("count:"+count);//打印7
        }
    }
}

结果:finally块被执行了
  count:6
  count:7
  5

案例4 retrun 抛出异常不终止

public class FinallyFlowTest2
{
    public static void main(String[] args)
    {
        int a = test();
        System.out.println(a);
    }
    public static int test()
    {
        int count = 5;
        try
        {
            //因为finally块中包含了return语句,
            //则下面的return语句不会立即返回
            throw new RuntimeException("测试异常");
        }
        finally
        {
            System.out.println("finally块被执行");
            return count;
        }
    }
}

没有终止线程返回5。在try块和catch块里面遇到throw语句时候,thorw不是立即结束还是找finally块,只有finlly块执行完了,再跳回抛异常。如果finally块使用return结束了方法。系统不会跳回到try块和catch块去抛异常。

案例5 带资源的try

资源:一般只物理资源比如:数据库连接,网络连接,硬盘文件,打开这些资源后必须显示关闭,不然会引起资源泄露。

在原来关闭资源的时候,用 try-catch-finally 时如果try中的代码跑出了一个非 IOException,在执行finally调用close方法时close方法本身也会有可能抛出 IOException 异常。这种情况下,原始的异常将丢失,转而抛出close方法的异常。

在jkd 1.7之前的处理方法较为繁琐,如下:

 public class Advice {  
          
        public static void main(String[] args) {  
            InputStream in = null;  
            Exception ex = null;  
            try{  
                try{  
                    //code…..;  
                } catch (Exception e) {  
                    ex = e;  
                    throw e;  
                }  
            } finally {  
                try {  
                    in.close();  
                } catch (Exception e) {  
                    if(ex == null)   
                        throw e;  
                }  
            }  
        }  
}

在jdk 1.7之后出现了带资源的try语句,它允许在try关键字后紧跟一对圆括号,圆括号可以声明、初始化一个或多个资源(此处的资源是指那些必须在程序结束时显式关闭的资源,比如数据库连接,网络连接等),try-with-resources 是一个定义了一个或多个资源的try 声明,try语句在该语句结束时自动关闭这些资源。try-with-resources确保每一个资源在处理完成后都会被关闭。这些资源必须实现AutoCloseable或者Closeable接口,实现这两个接口就必须实现close() 方法。

public class Xin {  
      
        public static void main(String[] args) throws Exception {  
      
            try(Scanner in = new Scanner(new FileInputStream(“d:\\haha.txt”));  
                    PrintWriter out = new PrintWriter(“d:\\hehe.txt”)) {  
                while(in.hasNext()) {  
                    out.println(in.next().toUpperCase());  
                }  
            }  
        }  
}

 思考题:一个main程序启动一个java虚拟机进程。一个tomcat对应一个java虚拟机进程。一个tomcat部署多个spring的war包,若一个war里面controller有异常没有捕获,tomcat不挂掉,spring对这个异常进行拦截处理。项目1跑起来了,项目2的某个@bean的时候抛出异常。则tomcat停止。



 

posted on 2021-01-06 01:38  朝闻道,夕可死  阅读(32)  评论(0编辑  收藏  举报