예외 및 오류:
예외: Java의 프로그램 오류는 주로 구문 오류와 의미 오류입니다. 프로그램을 컴파일하고 실행할 때 발생하는 오류를 집합적으로 예외라고 하며 이를 VM(가상 머신)에 알리는 방법입니다. 여기서 VM은 귀하(개발자)가 실수를 했으며 이제 이를 수정할 수 있는 기회가 있음을 알려줍니다. 예외 클래스는 Java에서 예외를 나타내는 데 사용되며, 다른 예외 클래스는 다른 예외를 나타냅니다. 그러나 Java의 모든 예외에는 Exception이라는 기본 클래스가 있습니다.
오류: 합리적인 적용으로 차단할 수 없는 심각한 문제를 말합니다. 대부분은 변칙입니다. 오류는 VM의 오류입니다(모든 시스템 수준 서비스일 수 있음). 따라서 오류는 처리하기 어렵고 일반 개발자(물론 귀하는 아님)는 메모리 오버플로와 같은 오류를 처리할 수 없습니다. 예외와 마찬가지로 오류 클래스는 Java에서 오류를 나타내는 데 사용되며 다른 오류 클래스는 다른 오류를 나타냅니다. 그러나 Java의 모든 오류에는 Error라는 기본 클래스가 있습니다.
요약하자면, 예외와 오류의 가장 근본적인 차이점은 예외는 개발자가 처리할 수 있는 반면, 오류는 시스템에 고유하며 일반적으로 처리할 수 없으며 프로그래머가 이를 처리할 필요가 없다는 점입니다.
1. 예외는 프로그램 실행 중에 발생하여 정상적인 명령의 실행을 방해하는 이벤트입니다.
2. 오류, 허용 가능한 코드 동작을 벗어나는 동작 또는 인스턴스
예외 구조 분류:
1. 런타임 예외(unchecked 예외)
2. 컴파일 시간 예외(checked 예외)
실행 예외는 RuntimeException입니다. 나머지는 모두 컴파일 예외입니다.
Java 예외 및 오류 오류는 공통 상위 클래스를 가집니다. 던질 수 있습니다.
오류 예외
runtimeException의 여러 하위 클래스
1. java.lang.ArrayIndexOutOfBoundsException
배열 인덱스 범위를 벗어난 예외입니다. 배열의 인덱스가 음수이거나 배열 크기보다 크거나 같을 때 발생합니다.
2. java.lang.ArithmeticException
산술 조건 예외입니다. 예: 0으로 정수 나누기 등
3. java.lang.NullPointerException
널 포인터 예외. 이 예외는 애플리케이션이 객체가 필요한 곳에 null을 사용하려고 시도할 때 발생합니다. 예: null 객체의 인스턴스 메서드 호출, null 객체의
속성에 액세스, null 객체의 길이 계산, null을 던지는 throw 문 사용 등
4. ClassNotFoundException
클래스 예외를 찾을 수 없습니다. 애플리케이션이 문자열 형식의 클래스 이름을 기반으로 클래스를 구성하려고 시도하지만 CLASSPAH를 순회한 후 해당 이름의 클래스 파일을 찾을 수 없는 경우
이 예외가 발생합니다.
예외 처리:
try{}catch{}
try{}catch{}finally{} finally 코드 블록은 예외 발생 여부에 관계없이 실행됩니다.
try{}finally {}도 가능합니다. 조합하여 사용할 수 있지만 catch{}finally{}는 사용할 수 없습니다
참고: 상속 관계에서 하위 클래스는 상위 클래스의 메서드를 재정의하며 발생하는 예외의 범위는 더 넓을 수 없습니다. 상위 클래스보다
예외 사용
예외 사용에 관한 이 부분은 주로 코드를 작성하는 과정에서 만나게 되는 데모 코드입니다(물론 작은 부분에 불과함). 다른 사람들에게 영감을 주기 위해!
예제 1. 이 예는 주로 두 메소드를 비교하여 예외 발생 후 코드의 실행 흐름을 보여줍니다.
public static void testException1() { int[] ints = new int[] { 1, 2, 3, 4 }; System.out.println("异常出现前"); try { System.out.println(ints[4]); System.out.println("我还有幸执行到吗");// 发生异常以后,后面的代码不能被执行 } catch (IndexOutOfBoundsException e) { System.out.println("数组越界错误"); } System.out.println("异常出现后"); } /*output: 异常出现前 数组越界错误 常出现后 */ 代码如下 复制代码 public static void testException2() { int[] ints = new int[] { 1, 2, 3, 4 }; System.out.println("异常出现前"); System.out.println(ints[4]); System.out.println("我还有幸执行到吗");// 发生异常以后,他后面的代码不能被执行 }
먼저 예제의 단점을 지적하세요. IndexOutofBoundsException은 확인되지 않은 예외이므로 캡처를 표시하기 위해...catch...를 시도할 필요가 없지만 제 목적은 동일한 예외에 대해 다른 처리 방법을 사용하여 어떤 차이가 발생하는지 확인합니다(여기서는 잠시 동안만 사용할 수 있습니다). 예외가 발생하면 첫 번째 메서드는 try 블록에서 벗어나지만 그 뒤의 코드는 계속 실행됩니다. 그러나 두 번째 종류는 다르며 더 어려운 방법에서 직접적으로 벗어납니다. 첫 번째 방법에서 try...catch...는 "트랜잭션" 보장이라는 것을 알 수 있습니다. 그 목적은 프로그램이 비정상적인 상황에서 실행을 완료하도록 보장하고 프로그램에 대한 자세한 정보를 알리는 것입니다. 오류(세부 사항은 프로그래머의 설계에 따라 달라질 수 있음).
예제 2. 예외 다시 발생
예외의 의도는 좋지만 실제로는 오류를 기록하는 데 사용하는 경우가 많습니다. . 정보. 계속해서 예외를 처리하는 데 지쳤다면 예외를 다시 발생시키는 것이 좋은 안도감을 줄 수 있습니다. 이 예외를 변경하지 않고 상위 레벨, 즉 이 메소드를 호출하는 사람에게 던지고 그것에 대해 생각하게 하십시오. 이러한 관점에서 볼 때, Java 예외(물론 확인된 예외를 의미함)는 출발점이 좋지만 우리에게 많은 문제를 야기했습니다.
예제 3. 예외 체인 사용 및 예외 손실
public class Rethrow { public static void readFile(String file) throws FileNotFoundException { try { BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); } catch (FileNotFoundException e) { e.printStackTrace(); System.err.println("不知道如何处理该异常或者根本不想处理它,但是不做处理又不合适,这是重新抛出异常交给上一级处理"); //重新抛出异常 throw e; } } public static void printFile(String file) { try { readFile(file); } catch (FileNotFoundException e) { e.printStackTrace(); } } public static void main(String[] args) { printFile("D:/file"); } }
예외 손실 상황:
ExceptionA,ExceptionB,ExceptionC public class ExceptionA extends Exception { public ExceptionA(String str) { super(); } } public class ExceptionB extends ExceptionA { public ExceptionB(String str) { super(str); } } public class ExceptionC extends ExceptionA { public ExceptionC(String str) { super(str); } }
왜 ExceptionC만 인쇄되고 ExceptionB는 인쇄되지 않습니까? 직접 분석해보자!
위 상황은 예외가 누락된 것과 동일하며 이는 문제 해결 과정에서 매우 불리합니다. 그렇다면 위와 같은 상황에 직면했을 때 우리는 어떻게 해야 할까요? 여기에서 예외 연결이 시작됩니다. 원래 예외를 잃지 않고 다른 예외를 발생시킬 수 있도록 예외 정보를 저장하는 것입니다.
public class NeverCaught { static void f() throws ExceptionB{ throw new ExceptionB("exception b"); } static void g() throws ExceptionC { try { f(); } catch (ExceptionB e) { ExceptionC c = new ExceptionC("exception a"); //异常连 c.initCause(e); throw c; } } public static void main(String[] args) { try { g(); } catch (ExceptionC e) { e.printStackTrace(); } } } /* exception.ExceptionC at exception.NeverCaught.g(NeverCaught.java:12) at exception.NeverCaught.main(NeverCaught.java:21) Caused by: exception.ExceptionB at exception.NeverCaught.f(NeverCaught.java:5) at exception.NeverCaught.g(NeverCaught.java:10) ... 1 more */
这个异常链的特性是所有异常均具备的,因为这个initCause()方法是从Throwable继承的。
例4. 清理工作
清理工作对于我们来说是必不可少的,因为如果一些消耗资源的操作,比如IO,JDBC。如果我们用完以后没有及时正确的关闭,那后果会很严重,这意味着内存泄露。异常的出现要求我们必须设计一种机制不论什么情况下,资源都能及时正确的清理。这就是finally。
public void readFile(String file) { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader( new FileInputStream(file))); // do some other work } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } }
例子非常的简单,是一个读取文件的例子。这样的例子在JDBC操作中也非常的常见。(所以,我觉得对于资源的及时正确清理是一个程序员的基本素质之一。)
Try...finally结构也是保证资源正确关闭的一个手段。如果你不清楚代码执行过程中会发生什么异常情况会导致资源不能得到清理,那么你就用try对这段"可疑"代码进行包装,然后在finally中进行资源的清理。举一个例子:
public void readFile() { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader( new FileInputStream("file"))); // do some other work //close reader reader.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
我们注意一下这个方法和上一个方法的区别,下一个人可能习惯更好一点,及早的关闭reader。但是往往事与愿违,因为在reader.close()以前异常随时可能发生,这样的代码结构不能预防任何异常的出现。因为程序会在异常出现的地方跳出,后面的代码不能执行(这在上面应经用实例证明过)。这时我们就可以用try...finally来改造:
public void readFile() { BufferedReader reader = null; try { try { reader = new BufferedReader(new InputStreamReader( new FileInputStream("file"))); // do some other work // close reader } finally { reader.close(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
及早的关闭资源是一种良好的行为,因为时间越长你忘记关闭的可能性越大。这样在配合上try...finally就保证万无一失了(不要嫌麻烦,java就是这么中规中矩)。
再说一种情况,假如我想在构造方法中打开一个文件或者创建一个JDBC连接,因为我们要在其他的方法中使用这个资源,所以不能在构造方法中及早的将这个资源关闭。那我们是不是就没辙了呢?答案是否定的。看一下下面的例子:
public class ResourceInConstructor { BufferedReader reader = null; public ResourceInConstructor() { try { reader = new BufferedReader(new InputStreamReader(new FileInputStream(""))); } catch (FileNotFoundException e) { e.printStackTrace(); } } public void readFile() { try { while(reader.readLine()!=null) { //do some work } } catch (IOException e) { e.printStackTrace(); } } public void dispose() { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } }
这一部分讲的多了一点,但是异常确实是看起来容易用起来难的东西呀,java中还是有好多的东西需要深挖的
更多java异常与错误处理基本知识相关文章请关注PHP中文网!