2018년 9월 8일 토요일

Java 예외처리

이전시간동안에 자바 클래스 다형성에 대해서 살펴보았다.

이제는 우리는 다양한 코드를 직접 구현할 능력이 되었다. 하지만 그전에 짚고넘어갈게하나있다. 바로 예외처리라고 하는건데, 코드를 작성할때 문법이 틀리거나 에러가 발생하는 경우 실행이 되지 않는다. 하지만, 실행이 되었을때 에러가 발생하는 경우. 즉 문법에 맞게 작성했지만, 프로그램을 실행하는 도중 발생했을 경우, 그것도 길게 짜여진 코드에서는 직접구현한 프로그래머도 어디서 발생했는지 찾기가 어려울것이다.

그럴때 사용하는것이 예외처리 방법이다.

이 예외처리방법은 에러난 곳을 직접 차자주는역할을 하는것이 아니다. 프로그램이 실행중에 에러가 발생할것같은 지점을 찾아서 그곳에 예외처리를 만들어주는것이다. 그래서 긴 코드에서 발생한 에러를 프로그래머는 인지 할 수 있게 된다. 또한 예외처리방식은 프로그램을 보안상의 위협으로도 매우 안전하게 해주는 역할을 한다.
예를들면, sql인젝션이라는 공격기법이 있는데, sql인젝션은 DB쿼리 검색에 오류를 발생시켜서 그 발생한 오류를 분석하여 쿼리정보들을 꺼내올 수 있다. 즉, 오류가 발생하면 DB를 종료하는 예외처리구문을 만들면 공격으로부터 조금 더 안전해질것이다.

예제를 통해서 살펴보자,

  1. package org.java.project1.compile;
  2. class Division{
  3.     public int left;
  4.     public int right;
  5.     public Division(int left, int right){
  6.         this.left = left;
  7.         this.right = right;
  8.     }
  9.     public void execute(){
  10.         try{  // 예외처리 시작.
  11.             System.out.println("Execute실행!");
  12.             int result = this.left / this.right;
  13.             System.out.println("나머니 연산결과 : " + result);  
  14.         } catch(Exception e){ // 모든 에러발생시 결과를 출력해준다.
  15.             System.out.println("에러발생 : "+ e.getMessage());
  16.         }      
  17.     }
  18. }
  19. public class compile{
  20.     public static void main(String[] args){
  21.         Division d = new Division(10);
  22.         d.execute();
  23.     }
  24. }

▶ 실행결과
Execute실행!
에러발생 : / by zero

자바 컴파일시에는 문제가 되지않았던 코드가 Run될 때는 에러가 발생하도록 만들었다.
자바는 숫자를 0으로 나눠버리게되면, 결과값이 0이되므로 에러를 발생시킨다.
여기서 주목해야할 것이 하나 있는데, 바로 코드의 에러발생하는 이후에 코드는
실행결과에 출력되지 않았다. 즉, 에러를 발생시키면 try에 해당하는 코드를 더이상 실행시키지 않고 catch구문으로 넘어간다. 그래서 에러를 막을수있으며 해당하는 에러가 어떠한 에러인지 프로그래머한테 알린다.

만약에 위 코드에서 try{}~catch{}구문이 없었다면,  다음과 에러가 발생할 것이다.

▶ 위 코드에 예외처리가 없었었을경우 실행결과
Execute실행!
Exception in thread "main" java.lang.ArithmeticException: / by zero
at org.java.project1.compile.Division.execute(compile.java:12)
at org.java.project1.compile.compile.main(compile.java:22)


먼저 첫번째줄을 실행시킨다음 에러가 발생시키고 종료됨. 

만약에 이상이 없을경우, catch문은 실행되지 않는다. 즉, 에러가 발생할 것 같은 코드를 try{}안에 넣어두며, 해당하는 오류가 발생했을경우 예외처리를 catch{}문 안에 넣어두면 된다. 그래서 프로그래머가 오류를 대처할 수 있게된다.

또한 다음과 같은 예제처럼 사용된다.

예제 - 발생하는 에러에따라 다르게 대처.
  1. package org.java.project1.compile;
  2. class Division{
  3.     public int left;
  4.     public int right;
  5.     public Division(int left, int right){
  6.         this.left = left;
  7.         this.right = right;
  8.     }
  9.     public void execute(){
  10.         try{  // 예외처리 시작.
  11.             System.out.println("Execute실행!");
  12.             int result = this.left / this.right;
  13.             System.out.println("나머니 연산결과 : " + result);  
  14.         } catch(ArrayIndexOutOfBoundsException e) {
  15.             System.out.println("예외처리 1 : " + e.getMessage());
  16.         } catch(ArithmeticException e) {
  17.             System.out.println("예외처리 2 : " + e.getMessage());
  18.         } catch(Exception e) {
  19.             System.out.println("예외처리 최종 : " + e.getMessage());
  20.         } finally {
  21.             System.out.println("execute의 예외처리 구문");
  22.         }
  23.        
  24.     }
  25. }
  26. public class compile{
  27.     public static void main(String[] args){
  28.         Division d = new Division(10);
  29.         d.execute();
  30.     }
  31. }

finally라고 하는것은 에러가 발생하는것에 상관없이 실행이 되는데, try catch 마지막에 finally 구문으로 넣어야 주어야한다. 또한 catch에 해당하는 인자 Exception e이 맨 마지막에 정의해야 한다. 예외처리도 다양한 종류가 있는데, 그것을 전체 포괄하는게 Exception 이므로 앞에서 정의 해버리면 뒤에 catch문은 당연히 실행이 되지 않으므로, 에러를 발생시킨다.

  1. public void execute(){
  2.         try{  // 예외처리 시작.
  3.             System.out.println("Execute실행!");
  4.             int result = this.left / this.right;
  5.             System.out.println("나머니 연산결과 : " + result);  
  6.         } catch(Exception e) // ---- 에러발생!!!!
  7.             System.out.println("예외처리 최종 : " + e.getMessage())
  8.         } catch(ArrayIndexOutOfBoundsException e) {
  9.             System.out.println("예외처리 1 : " + e.getMessage());
  10.         } catch(ArithmeticException e) {
  11.             System.out.println("예외처리 2 : " + e.getMessage());
  12.         } finally {
  13.             System.out.println("execute의 예외처리 구문");
  14.         }
  15.        
  16.     }

그래서 프로그래머들이 에러마다 다르게 (출력)정의를 하고싶다면, 발생한 에러 종류에 해당하는 Exception을 catch문에 써서 다르게 코드를 작성해주면 된다. 위에서 사용한 ArrayIndexOutOfBoundsException은 정의된 배열의 인덱스값을 넘어섰을경우에 발생한다.
ArithmeticException은 자바에서 정수를 나눌때 0으로 나누게되면 발생시키는 에러메시지이다.

이제는 우리는 다양한 코드를 짜면서 컴파일실행은 되지만 런타임때 발생하는 에러메시지가 출력되며 해당하는 에러를 찾을 수 있게되었다. 



댓글 없음:

댓글 쓰기

[Java] N-I/O(Non-Blocking) 파일 읽기 쓰기 - GatheringByteChannel, ScatteringByteChannel, ByteBuffer 사용.

우리는 지금까지 다음과 같이 살펴보았다. 1.  InputStream / OutputStream : 입, 출력 스트림을 바이트로 처리하여 읽기, 쓰기. 2.  FileInputStream / FileOutputStream : 입, 출력 스트림을 ...