zoukankan      html  css  js  c++  java
  • Java_异常以及处理


    写了一天的bug,来try...catch...finally了解一下。异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。在使用IDE编程的时候,会出现一些红色的波浪线(编译都过不了)【受查异常】,Alt+Enter键还提示add exception to method... 和.. with try/catch。按照提示加了之后运行,mmp 控制台又出现Exception in thread ... at java ...【非受查异常】。这Exception跟我过不去了,真是的让不让人愉快的写bug了。不说了先看看看Java异常类层次结构图


    JAVA异常

    • Throwable:是Java语言中所有错误(Error)和异常(Exception)的父类,只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
    • Error(错误):一般是指虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误。
    • Exception:是程序本身可以处理的异常。

    Java异常分为两大类:

    可查异常(编译器要求必须处置的异常):除RuntimeException类及其子类的异常以及Error外。要么显示声明抛出异常,要么显示捕获并处理它。
    不可查异常(编译器不要求强制处置的异常):所有的 RuntimeException类及其子类的异常和 Error(错误)。

    异常的处理机制

    • 使用 try...catch 或 try...catch...finally 捕获异常
     try {
     	FileInputStream fis = new FileInputStream("E:\a.txt");
     	System.out.println(fis.available());
     }catch (IOException e){
    	e.printStackTrace();
     }
    
     FileInputStream fis = null;
     try {
         fis= new FileInputStream("E:\a.txt");
         System.out.println(fis.available());
     }catch (IOException e){
         e.printStackTrace();
         //System.exit(1);  退出虚拟机,finally将不会执行
     }finally {
         // java垃圾回收机制不会回收任何物理资源,只能回收堆内存中的对象
    	if(fis != null){ // 关闭磁盘文件,回收资源
             try {
                 fis.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     }
    

    尽量避免在finally块里使用return 或 throw 等导致语句方法终止的语句,否则可能出现一些奇怪的情况

    情况1:文件存在,会先执行try块,再执行finally块,执行最后面return语句,返回 int类型的值 1
    文件不存在,不会执行try块输出语句,执行catch块,再执行finally块,执行最后面return语句,返回int类型的值 1
    
    情况2:文件存在,会先执行try块非return语句,执行return语句,再执行 finally块非return语句,执行return语句,返回finally中int类型的值 1
    文件不存在,不会执行try块输出语句及之后的语句,执行catch块非return语句,执行return语句,再执行finally块非return语句,执行return语句,返回finally中int 类型的值1
    
    情况3:文件不存在,不会执行try块输出语句,执行catch块非return语句,执行return语句,再执行finally块非return语句,执行return语句,返回finally中int 类型的值 1
    
    情况4:文件不存在,不会执行try 块输出语句,执行catch块非return语句,执行return语句,再执行finally块,不执行最后的return语句,返回catch中int类型的值 0
    
    情况5:文件存在,会先执行try块,再执行finally块,不执行最后面的return语句,返回try中int类型的值 0
    文件不存在,不会执行try块输出语句及之后的语句,执行catch块,再执行finally块,执行最后面的return语句,返回 int类型的值 1
    
    public class Test0022{
        public static void main(String [] args){
            System.out.println("返回的值为:"+new ReadDiskE().read());
        }
    }
    
    class ReadDiskE{
        public int read(){
            try {
                FileInputStream fis = new FileInputStream("E:\a.ba");
                System.out.println("try 块");
                //return 0; // 情况2
                return 0; // 情况5
            }catch (IOException e){
                System.out.println("catch 块");
                //return 0; // 情况3
                //return 0; // 情况4
            }finally {
                System.out.println("finally 块");
                //return 1; // 情况2 一般放到括号外
                //return 1; // 情况3
            }
            //return 1; // 情况1
            //return 1; // 情况4
            return 1; // 情况5
        }
    }
    

    总结:
    try 捕获异常交给catch处理,catch若无法处理则交给调用者处理,若无法处理则交给虚拟机处理抛出异常。
    try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
    catch 块:用于处理try捕获到的异常。
    finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。以下4种特殊情况下,finally块不会被执行:
    1)在finally语句块中发生了异常。
    2)在前面的代码中用了System.exit()退出程序。
    3)程序所在的线程死亡。
    4)关闭CPU。

    • 使用 throws 声明抛出异常
      当方法不知道如何处理这种异常时,该异常应该由上一级调用者处理;如果main方法也不知道如何处理,也可以使用throws声明throws 声明抛出异常,该异常将交给JVM处理。JVM对异常的处理是:打印异常的跟踪栈信息,并中止程序运行。
    public static void main(String [] args) throws Exception {
            //调用test方法声明抛出IOException异常
            //所以调用该方法代码要么在 try...catch中,要么在带 throws声明的方法中
            test();
    }
    public static void test() throws IOException {
            FileInputStream fis = new FileInputStream("E:\a.txt");
    }
    
    • 使用 throw 抛出异常
      当程序出现错误时,系统会自动抛出异常;Java也允许程序自行抛出异常,自行抛出异常使用 throw语句完成。
    public class Test0022{
    	public static void main(String [] args){
    		try {
    		    test0();
    		    test();
    		}catch (FileNotFoundException e){ // 捕获异常,先捕获小异常,再捕获大异常。
    			e.printStackTrace();
    			// 注释 throw e 后,程序继续运行(异常被吃掉了)
    			//throw e; // 继续抛出,由main方法处理,程序终止(main方法需要throws 声明抛出异常)。
    		}catch (IOException e1){
    			e1.printStackTrace();
    		}
    		System.out.println("------test or test0 end-----");
    
    		// 调用声明 Runtime 异常的方法既可以显示捕获该异常,也可不理会
    		test1(-1);  // 交给main方法抛出异常,程序终止
    		System.out.println("------test1 end-----"); // 不打印该语句
    	}
    	public static void test() throws IOException {
    	    System.out.println("test");
    	    throw new IOException("I'm an IOException");
    	}
    	public static void test0() throws FileNotFoundException{
    	    System.out.println("test0");
    	    throw new FileNotFoundException("I'm a FileNotFoundException");
    	}
    	public static void test1(int i){
    	    if(i < 0){
    	        System.out.println("test1");
    	        throw new RuntimeException("I'm an RuntimeException");
    	    }
    	}
    }
    

    自定义异常

    通常情况,程序很少会自行抛出系统异常,因为异常的类名通常也包含了该异常的有用信息。所以在选择抛出异常时,应该选择合适的异常,从而可以明确的描述该异常的情况。
    用户自定义的异常都应该继承 Exception的基类,如果希望自定义Runtime 异常,则应该继承RuntimeException基类。

    public class Test0022{
    	public static void main(String [] args){
    		try{
    		    throw new  AutionException("我是自定义异常");
    		}catch (AutionException e){
    			e.initCause(new Throwable("初始化原因"));
    			System.out.println(e.getMessage()); // 打印 "我是自定义异常" , 返回此throwable的详细消息字符串。
    			System.out.println(e.getLocalizedMessage()); // 打印 "我是自定义异常", 创建此可抛出的本地化描述。
    			System.out.println(e.getCause().toString());//打印 "java.lang.Throwable: 初始化原因",将此throwable的原因初始化为指定值
    			StackTraceElement[] trace = e.getStackTrace(); // 提供编程访问由 printStackTrace() 输出的堆栈跟踪信息
    			for (int i=0; i<trace.length;i++){
    				StackTraceElement ste = trace[i];
    				System.out.println("i:"+i+"--"+ste.toString()); // e.printStackTrace();
    				System.out.println("i:"+i+"--"+ste.getClassName()); // 返回堆栈信息类名的完整信息 com.zzw.test005.Test0022
    				System.out.println("i:"+i+"--"+ste.getMethodName()); // 返回方法名  main
    				System.out.println("i:"+i+"--"+ste.getLineNumber()); // 返回报错的行数 4
    				System.out.println("i:"+i+"--"+ste.getFileName()); // 返回类所在的文件名 Test0022.java
    			}
    		}
    	}
    }
    
    // 自定义异常类
    class AutionException extends Exception{
    
        public AutionException(){}
    
        public AutionException(String msg){
            super(msg);
        }
    }
    

    注:
    推荐阅读博客:https://blog.csdn.net/hguisu/article/details/6155636
    参考书籍《Java疯狂讲义》

  • 相关阅读:
    sync_with_stdio(false)和cin.tie(NULL)
    会场安排问题(贪心 两种方法)
    面向对象分析和设计笔记——第6章界面组件
    用Java实现文件复制
    面向对象分析和设计笔记——第5章输入输出
    面向对象分析和设计笔记——第4章设计模式
    常规类、抽象类和接口的对比分析
    使用for-each循环的三种情况
    StringTokenizer类
    String类的常用方法
  • 原文地址:https://www.cnblogs.com/zeo-to-one/p/9420213.html
Copyright © 2011-2022 走看看