zoukankan      html  css  js  c++  java
  • java异常

    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停止。



    玉不琢,不成器,人不学,不知义
  • 相关阅读:
    Java笔记(二十一) 动态代理
    Java笔记(二十) 注解
    Java笔记(十九) 反射
    Java笔记(十八)同步和协作工具类
    Java笔记(十七) 异步任务执行服务
    Spring使用笔记(四) 面向切面的Spring
    Spring使用笔记(三) 高级装配
    Java笔记(十六)并发容器
    Java笔记(十五) 并发包
    Java笔记(十四) 并发基础知识
  • 原文地址:https://www.cnblogs.com/startery/p/14238853.html
Copyright © 2011-2022 走看看