> Java > java지도 시간 > 본문

JAVA의 예외에 대한 자세한 소개

零下一度
풀어 주다: 2017-07-17 09:46:25
원래의
1427명이 탐색했습니다.

1. 예외 소개

예외:

예외: 비정상입니다. 프로그램 실행 중 발생하는 비정상적인 상황. 사실 프로그램상의 문제입니다. 이 문제는 객체 지향 아이디어에 따라 설명되고 객체로 캡슐화됩니다. 문제 발생에는 문제의 원인, 문제 이름, 문제 설명 등 여러 속성 정보가 있기 때문입니다. 다중 속성 정보가 나타날 때 가장 편리한 방법은 정보를 캡슐화하는 것입니다. 객체 지향 사고에 따라 문제를 Java의 객체 캡슐화하는 경우는 예외입니다. 이를 통해 운영 및 문제 처리가 더 쉬워집니다.

아웃 오브 바운드 코너 마커, 널 포인터 등 다양한 종류의 문제가 있습니다. 이러한 문제를 분류하면 됩니다. 또한 이러한 질문에는 각 질문에 이름이 있고 문제 설명 정보와 문제 위치가 포함되어 있어 지속적으로 추출할 수 있는 공통된 내용이 있습니다. 비정상적인 시스템이 형성되었습니다.

Java의 예외 시스템이란 무엇인가요?

1. Java의 모든 비정상적인 클래스는 Throwable 클래스에서 상속됩니다. Throwable에는 주로 두 가지 주요 범주가 포함됩니다. 하나는 Error 클래스이고 다른 하나는 Exception 클래스입니다. 2. Error 클래스에는

가상 머신 오류

thread 교착 상태

가 포함됩니다. 완전히 끊겼고

, Program Terminator;  3.일반적으로 "예외"로 알려진 예외 클래스라고 했습니다. 주로 코딩, 환경, 사용자 조작 입력에 관한 문제를 말합니다. 예외에는 주로 확인되지 않은 예외(RuntimeException)와 확인된 예외(일부 예외)가 있습니다

   

4. RuntimeException 예외에는 주로 다음 네 가지 유형이 있습니다. (실제로 여기에 나열되지 않은 다른 예외가 많이 있습니다): Null 포인터 예외, 배열 첨자 범위를 벗어난 예외, 유형 변환 예외, 산술 예외. RuntimeException 예외는 자동으로 발생하고 Java 가상 머신

에 의해 자동으로 캡처됩니다(예외 캡처 문을 작성하지 않더라도 런타임 중에 오류가 발생합니다!!)

. 코드 자체를 해결해야 하며 코드를 논리적으로 해결하고 개선해야 합니다.

 

5. 예외가 발생하는지 확인하세요. 파일이 존재하지 않거나 연결 오류가 있는 등 다양한 이유가 있습니다. "형제" RuntimeException과 달리 이 예외를 처리하려면 캡처 문을 코드에 수동으로 추가해야 합니다. 이는 Java 예외 문을 학습할 때 처리하는 주요 예외 개체이기도 합니다.  

2. try-catch-finally 문

(1) try 블록: 예외 포착을 담당합니다.

일단 try에서 예외가 발견되면 프로그램 제어가 예외 처리자에게 넘겨집니다. 캐치 블록에 있습니다.

 

[try 문 블록은 독립적으로 존재할 수 없으며 catch 또는 finally 블록과 같은 위치에 있어야 함]

(2) Catch 블록: 어떻게 처리하나요? 예를 들어 경고 발행:

프롬프트, 구성 확인, 네트워크 연결, 오류 기록 등. catch 블록을 실행한 후 프로그램은 catch 블록에서 벗어나 다음 코드를 계속 실행합니다.

  【

catch 블록 작성 시 주의 사항: 여러 catch 블록으로 처리되는 예외 클래스는 먼저 하위 클래스를 포착한 다음 상위 클래스를 포착하는 방식으로 처리해야 합니다. 예외는 [근처에서](위에서 아래로) 처리되기 때문입니다. ]

(3)finally:

최종적으로 실행된 코드, 리소스를 닫고 해제하는 데 사용됩니다.

============================================== == =======================

구문 형식은 다음과 같습니다.

try{//一些会抛出的异常}catch(Exception e){//第一个catch//处理该异常的代码块}catch(Exception e){//第二个catch,可以有多个catch//处理该异常的代码块}finally{//最终要执行的代码}
로그인 후 복사

当异常出现时,程序将终止执行,交由异常处理程序(抛出提醒或记录日志等),异常代码块外代码正常执行。 try会抛出很多种类型的异常,由多个catch块捕获多钟错误

多重异常处理代码块顺序问题先子类再父类(顺序不对编译器会提醒错误),finally语句块处理最终将要执行的代码。

=======================================================================

接下来,我们用实例来巩固try-catch语句吧~

先看例子:

 1 package com.hysum.test; 2  3 public class TryCatchTest { 4     /** 5      * divider:除数 6      * result:结果 7      * try-catch捕获while循环 8      * 每次循环,divider减一,result=result+100/divider 9      * 如果:捕获异常,打印输出“异常抛出了”,返回-110      * 否则:返回result11      * @return12      */13     public int test1(){14         int divider=10;15         int result=100;16         try{17             while(divider>-1){18                 divider--;19                 result=result+100/divider;20             }21             return result;22         }catch(Exception e){23             e.printStackTrace();24             System.out.println("异常抛出了!!");25             return -1;26         }27     }28     public static void main(String[] args) {29         // TODO Auto-generated method stub30         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      * @return10      */11     public int test2(){12         int divider=10;13         int result=100;14         try{15             while(divider>-1){16                 divider--;17                 result=result+100/divider;18             }19             return result;20         }catch(Exception e){21             e.printStackTrace();22             System.out.println("异常抛出了!!");23             return result=999;24         }finally{25             System.out.println("这是finally,哈哈哈!!");26             System.out.println("result的值为:"+result);27         }28         29     }30     31     32     33     public static void main(String[] args) {34         // TODO Auto-generated method stub35         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 

  public int test2(){ 
          int divider=10; 
          int result=100; 
          try{ 
              while(divider>-1){ 
                  divider--; 
                  result=result+100/divider; 
              } 
              return result;10         }catch(Exception e){
              e.printStackTrace();
              System.out.println("异常抛出了!!");
              return result=999;14         }finally{
              System.out.println("这是finally,哈哈哈!!");
              System.out.println("result的值为:"+result);
              return result;//编译器警告18         }
          
      }
로그인 후 복사

分析问题: 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 (异常对象),如:

1 public static void main(String[] args) { 
2     String s = "abc"; 
3     if(s.equals("abc")) { 
4       throw 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----声明将要抛出何种类型的异常(声明)。

语法格式:

1 public void 方法名(参数列表)2    throws 异常列表{3 //调用会抛出异常的方法或者:4 throw new Exception();5 }
로그인 후 복사

当某个方法可能会抛出某种异常时用于throws 声明可能抛出的异常,然后交给上层调用它的方法程序处理。如:

 1 public static void function() throws NumberFormatException{ 
 2     String s = "abc"; 
 3     System.out.println(Double.parseDouble(s)); 
 4   } 
 5      6   public static void main(String[] args) { 
 7     try { 
 8       function(); 
 9     } catch (NumberFormatException e) { 
10       System.err.println("非数据类型不能转换。"); 
11       //e.printStackTrace(); 12     } 
13 }
로그인 후 복사

throw与throws的比较
1、throws出现在方法函数头;而throw出现在函数体。
2、throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。
3、两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

来看个例子:

throws e1,e2,e3只是告诉程序这个方法可能会抛出这些异常,方法的调用者可能要处理这些异常,而这些异常e1,e2,e3可能是该函数体产生的。
throw则是明确了这个地方要抛出这个异常。如:

 1 void doA(int a) throws (Exception1,Exception2,Exception3){ 2       try{ 3          ...... 4   5       }catch(Exception1 e){ 6        throw e; 7       }catch(Exception2 e){ 8        System.out.println("出错了!"); 9       }10       if(a!=b)11        throw new Exception3("自定义异常");12 }
로그인 후 복사

분석:
1. 코드 블록에는 세 가지 예외가 발생할 수 있습니다(Exception1, Exception2, Exception3).
2. Exception1 예외가 발생하면 catch된 후 발생하며 메서드 호출자가 처리합니다.
3. Exception2 예외가 발생하면 메서드가 이를 자체적으로 처리합니다(예: System.out.println("An error 발생!");). 따라서 이 메소드는 더 이상 Exception2 예외인 void를 발생시키지 않습니다. doA()에서 Exception2를 작성하면 Exception1,Exception3을 발생시킬 필요가 없습니다. try-catch 문을 사용하여 캡처하고 처리했기 때문입니다.
4.Exception3 예외는 이 메서드의 특정 논리 오류입니다. 프로그래머가 직접 처리했습니다. 이 논리 오류의 경우 예외 3이 발생하면 메서드 호출자도 이 예외를 처리해야 합니다. 여기서는 사용자 정의 예외가 사용되며 이에 대해서는 아래에서 설명합니다.

>>>>>>>>>>>>>>>>>>>>>>> ;>>>>>>>>>>>>>>>

throw 및 throws 키워드를 사용할 때 다음 사항에 주의하세요.

1. 예외 발생 목록은 하나 또는 여러 예외를 발생시킬 수 있습니다. 각 예외 유형은 쉼표로 구분됩니다.

2. 먼저 예외 발생: throw new Exception 사용() throw는 "예외 발생" 동작을 나타내기 위해 메서드 본문에 작성됩니다.

3. 메소드가 예외를 발생시키는 메소드를 호출하는 경우 이 예외를 포착하기 위해 try catch 문을 추가하거나 처리를 위해 상위 수준 호출자에게 예외를 발생시키는 문을 추가해야 합니다.

> >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>> 맞춤 예외


맞춤 예외를 사용해야 하는 이유는 무엇인가요?
이점

은 무엇인가요?

1. 프로젝트는 모듈이나 함수 단위로 개발됩니다. 기본적으로 사용자 정의 예외 클래스를 사용하면 외부 예외 표시 방식이 통합됩니다.

2. 가끔 특정 확인이나 문제가 발생하면

현재 요청을 직접 종료해야 합니다. 이때 프로젝트에서 SpringMVC를 사용하는 경우 비교적 새로운 방법으로 종료할 수 있습니다. 버전에는 컨트롤러 향상 기능이 있으므로 @ControllerAdvice 주석을 통해 컨트롤러 향상 클래스를 작성하여 사용자 정의 예외를 가로채고 해당 정보

로 프런트엔드에 응답할 수 있습니다.

3. 프로젝트에서 "neutral".equals(sex)와 같은 특정 특수 비즈니스 로직이 발생하는 경우 사용자 정의 예외가 발생할 수 있습니다. 성별이 중립인 경우 예외를 발생시켜야 하며 Java에는 없습니다. 그러한 예외. 시스템의 일부 오류는 Java 구문을 따르지만 우리 프로젝트의 비즈니스 로직을 따르지 않습니다.

4. 사용자 정의 예외를 사용하여 관련 예외를 상속하여 처리된 예외 정보를 발생시킵니다.

기본 예외를 숨길 수 있어 더 안전하고 예외 정보가 더 직관적입니다. 사용자 정의 예외는 우리가 던지고 싶은 정보를 던질 수 있습니다. 던진 정보를 사용하여 예외 이름을 기반으로 예외가 어디에 있는지 알 수 있고 예외 프롬프트 정보를 기반으로 프로그램을 수정할 수 있습니다. . 예를 들어 NullPointException의 경우 "xxx is null" 정보를 발생시켜 스택 정보를 출력하지 않고 예외 위치를 찾을 수 있습니다.

맞춤 예외를 사용해야 하는 이유와 이점에 대해 이야기한 후 맞춤 예외의 문제

를 살펴보겠습니다.

말할 필요도 없이 JVM(Java Virtual)을 기대할 수 없습니다. Machine) 하나의 사용자 정의 예외를 자동으로 발생시키거나 JVM이 사용자 정의 예외를 자동으로 처리할 것이라고 기대할 수도 없습니다. 예외 감지, 예외 발생 및 예외 처리 작업은 코드의 예외 처리 메커니즘을 사용하여 프로그래머가 직접 완료해야 합니다. 이에 따라 일부 개발 비용과 작업량이 증가하므로 프로젝트에 필요하지 않은 경우 반드시 사용자 정의 예외를 사용할 필요는 없습니다.

마지막으로

사용자 정의 예외를 사용하는 방법을 살펴보겠습니다.

Java에서는 예외를 사용자 정의할 수 있습니다. 자신만의 예외 클래스를 작성할 때 염두에 두어야 할 몇 가지 사항이 있습니다. 모든 예외는 Throwable의 하위 클래스여야 합니다.

  • 如果希望写一个检查性异常类,则需要继承 Exception 类。

  • 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。

  • 可以像下面这样定义自己的异常类:

    class MyException extends Exception{ }

     

    我们来看一个实例:

     1 package com.hysum.test; 2  3 public class MyException extends Exception { 4      /** 5      * 错误编码 6      */ 7     private String errorCode; 8  9    10     public MyException(){}11     12     /**13      * 构造一个基本异常.14      *15      * @param message16      *        信息描述17      */18     public MyException(String message)19     {20         super(message);21     }22 23    24 25     public String getErrorCode() {26         return errorCode;27     }28 29     public void setErrorCode(String errorCode) {30         this.errorCode = errorCode;31     }32 33     34 }
    로그인 후 복사

    使用自定义异常抛出异常信息:

     1 package com.hysum.test; 2  3 public class Main { 4  5     public static void main(String[] args) { 6         // TODO Auto-generated method stub 7         String[] sexs = {"男性","女性","中性"}; 8                   for(int i = 0; i < sexs.length; i++){ 9                       if("中性".equals(sexs[i])){10                           try {11                             throw new MyException("不存在中性的人!");12                         } catch (MyException e) {13                             // TODO Auto-generated catch block14                             e.printStackTrace();15                         }16                      }else{17                          System.out.println(sexs[i]);18                      }19                 } 
    20     }21 22 }
    로그인 후 복사

    运行结果:

    就是这么简单,可以根据实际业务需求去抛出相应的自定义异常。


    四、java中的异常链

    异常需要封装,但是仅仅封装还是不够的,还需要传递异常

    异常链是一种面向对象编程技术,指将捕获的异常包装进一个新的异常中并重新抛出的异常处理方式。原异常被保存为新异常的一个属性(比如cause)。这样做的意义是一个方法应该抛出定义在相同的抽象层次上的异常,但不会丢弃更低层次的信息

    我可以这样理解异常链:

    把捕获的异常包装成新的异常,在新异常里添加原始的异常,并将新异常抛出,它们就像是链式反应一样,一个导致(cause)另一个。这样在最后的顶层抛出的异常信息就包括了最底层的异常信息。

    》场景

    比如我们的JEE项目一般都又三层:持久层、逻辑层、展现层,持久层负责与数据库交互,逻辑层负责业务逻辑的实现,展现层负责UI数据的处理。

    有这样一个模块:用户第一次访问的时候,需要持久层从user.xml中读取数据,如果该文件不存在则提示用户创建之,那问题就来了:如果我们直接把持久层的异常FileNotFoundException抛弃掉,逻辑层根本无从得知发生任何事情,也就不能为展现层提供一个友好的处理结果,最终倒霉的就是展现层:没有办法提供异常信息,只能告诉用户“出错了,我也不知道出了什么错了”—毫无友好性而言。

    正确的做法是先封装,然后传递,过程如下:

     1.把FileNotFoundException封装为MyException。

    2.抛出到逻辑层,逻辑层根据异常代码(或者自定义的异常类型)确定后续处理逻辑,然后抛出到展现层。

    3.展现层自行确定展现什么,如果管理员则可以展现低层级的异常,如果是普通用户则展示封装后的异常。

    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    》示例

     1 package com.hysum.test; 2  3 public class Main { 4     public void test1() throws RuntimeException{ 5         String[] sexs = {"男性","女性","中性"}; 6         for(int i = 0; i < sexs.length; i++){ 7             if("中性".equals(sexs[i])){ 8                 try { 9                     throw new MyException("不存在中性的人!");10                 } catch (MyException e) {11                     // TODO Auto-generated catch block12                     e.printStackTrace();13                     RuntimeException rte=new RuntimeException(e);//包装成RuntimeException异常14                     //rte.initCause(e);15                     throw rte;//抛出包装后的新的异常16                 }17            }else{18                System.out.println(sexs[i]);19            }20       } 
    21     }22     public static void main(String[] args) {23         // TODO Auto-generated method stub24         Main m =new Main();25         26         try{27         m.test1();28         }catch (Exception e){29             e.printStackTrace();30             e.getCause();//获得原始异常31         }32         33     }34 35 }
    로그인 후 복사

    실행 결과:

    결과 분석: 콘솔이 먼저 e.getCause()에 의해 출력된 원래 예외를 출력한 다음 여기에서 볼 수 있는 e.printStackTrace()를 출력하는 것을 볼 수 있습니다. 원인: 원래 예외는 e.getCause()의 출력과 일치합니다. 이것은 비정상적인 사슬을 형성합니다. initCause()의 기능은 원래 예외를 래핑하는 것입니다. 맨 아래 레이어에서 어떤 예외가 발생했는지 알고 싶다면 getCause()를 호출하여 원래 예외를 가져올 수 있습니다.

    >>>>>>>>>>>>>>>>>>>>>>> ;>>>>>>>>>>>>>>>

    》예외를 캡슐화하는 것이 좋습니다. 시스템을 개발할 때 예외를 "삼키거나" 예외를 "노골적으로" 던져서는 안 됩니다. 이를 캡슐화한 다음 예외 체인을 통해 전달하면 됩니다. 사용자 친화적입니다.

    5. 결론

    Java 예외 처리 지식은 복잡하고 이해하기 다소 어렵습니다.

    좋은 코딩 습관: 1. 런타임 예외 처리, 논리를 사용하여 try-catch 처리를 합리적으로 방지하고 지원합니다

    2. 여러 catch 블록 뒤에 catch(Exception)를 추가하여 놓칠 수 있는 예외를 처리할 수 있습니다

    3, 불확실한 코드의 경우 다음을 수행할 수도 있습니다. 잠재적인 예외를 처리하려면 try-catch를 추가하세요.

    4. 인쇄하려면 printStackTrace()를 호출하세요.

    5. 예외를 처리하는 방법은 상황에 따라 다릅니다.

    6. 점유된 리소스를 해제하려면 finally 문 블록을 추가해 보세요.

    위 내용은 JAVA의 예외에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    원천:php.cn
    이전 기사:Java 캡슐화, 상속 및 다형성의 세 가지 주요 기능 다음 기사:Spring+SpringMVC+MyBatis 심층 학습 및 구성(17) - SpringMVC 인터셉터
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    저자별 최신 기사
    최신 이슈
    관련 주제
    더>
    인기 추천
    인기 튜토리얼
    더>
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿