본문 바로가기
Programming/JAVA(eclipse)

java 12일차_ 01. 예외처리

by yoon9i 2024. 3. 25.

1. 예외처리 ( exception handling )
1) 예외(exception)?
- 일반적으로 에러(error)라고 불리우는 사건이다.
- 예외가 발생되면 프로그램이 '비정상 종료' 된다.

2) 예외처리 ( exception handling )?
- 예외가 발생되면 '비정상종료' 되는데, 비정상 종료되는 프로그램을
  '정상 종료' 하도록 처리하는 방법이다.
- 정상종료 처리방법은 사용자에게 문제발생 이유를 
  알려주는 방법( 콘솔 또는 경고창 )도 포함됨.
  사용자가 이해하기 쉽도록 친절하게 알려줘야 한다. (ex) 한국어 )
- 잘못 알고 있는 경우는 문제발생된 상황을 해결해주는 것이 아니다.
  ( 불가능 함 )
  문제발생된 코드는 어쩔수 없이 실행이 안되고 이후의 코드를 실행해서
  main 끝까지 가도록 하는 작업이 개발자가 해야되는 예외처리이다.

package exam20_exception;

public class ExceptionTest01 {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		
		// 정상종료
		int n = 2;
		int result = 10 / n;
		System.out.println("1. 결과값: " + result); // >>> 5
		
		// 비정상종료
		int n2 = 0;
		int result2 = 10 / n2;
		System.out.println("2. 결과값: " + result2);
		/*
		 * >>>
		    ----- 프로그램 시작 -----
			Exception in thread "main" java.lang.ArithmeticException: / by zero
			at exam20_exception.ExceptionTest01.main(ExceptionTest01.java:15)
		 */
		
		// * 예외가 발생했으니 프로그램종료 멘트까지 가도록 예외처리를 해줘야한다.
		
		System.out.println("----- 프로그램 종료 -----");
	}
}

 

3) 예외처리 방법
가. 예외 클래스 제공 (* 이미지 참고 )
Object
         |
Throwable
-> Error: 개발자가 핸들링 불가
-> Exception ( * 예외처리시 사용하는 예외클래스의 최상위 ) 

1) Runtime Exception( 런타임계열: 런타임시(실행) 발생, 컴파일 unchecked 계열 )
ArithmeticException( ex) 10/0 )
ClassCastException (ex) 클래스 형변환시)
NullPointerException 
(ex) null 값을 가진상태로 메서드 호출시
ArrayIndexOutOfBoundsException
(ex) 없는 배열요소 접근시
                    ........

2) IOException, SQLException ( 비런타임계열: 컴파일시 발생, 컴파일 checked 계열 )
FileNotFoundException
                   .......

 

나. 예외클래스 + try ~ catch ~ finaly 문
- 예외가 발생된 곳에서 처리하는 방법이다.
- 문법:
          { // start main
  ...
try {
   실행문1;
   실행문2;
} catch ( 예외클래스1 변수 ) {
// 적합한 예외클래스를 지정(권장)
// 다형성 가능(비권장)

   예외발생시 처리하는 문장;
} catch ( 예외클래스2 변수 ) {
// Exception 최상위 클래스는 반드시 가장 마지막에 지정한다.
// 즉, 계층구조의 자식부터 catch 해야 된다. ( 컴파일 에러 발생 )

   예외발생시 처리하는 문장;
} finally {
   반드시 수행되는 문장; ( 파일 및 DB 연동시 close 작업)
}
  문장;
  문장;
  ....
} // end main

- 예외관련 정보 제공
e.printStackTrace( ); ==> 자체적으로 print 가능, 예외발생메세지,
        예외발생 line 정보, 예외클래스 정보 등 제공함.
       개발시 디버깅용으로 사용됨.
sysout( e.getMessage( ) ) ==> 예외발생메세지 제공.

- try~finally 문 가능 ( catch 문 없이 사용 가능 )
==> 예외처리 목적이 아닌 반드시 실행해야 되는 문장을 알려주는 용도로
       사용된다.
ex)
try {

} finally {

}

 

* 예외클래스제공

 

package exam20_exception;

public class ExceptionTest02_try_catch {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		
		try {
			// 정상종료
			int n = 2;
			int result = 10 / n;
			System.out.println("1. 결과값: " + result); // >>> 5
			
			// 비정상종료
			int n2 = 0;
			int result2 = 10 / n2;
			System.out.println("2. 결과값: " + result2);			
		} catch (ArithmeticException arithmeticException) {
			// 예외처리 코드구현 ==> 사용자에게 친절하게 예외 메세지를 알려주는 것이다.
			// 아무 예외클래스가 아닌 적합한 예외클래스 지정. 다형성 가능
			// 다형성 : RuntimeException , Exception ,... (권장안함)
			System.out.println("ArithmeticException: 0 으로 나누어 예외가 발생됨.");
			
		}

		System.out.println("----- 프로그램 종료 -----");
	}
}
package exam20_exception;

public class ExceptionTest02_try_catch2_예외메세지제공 {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		
		try {
			// 정상종료
			int n = 2;
			int result = 10 / n;
			System.out.println("1. 결과값: " + result); // >>> 5
			
			// 비정상종료
			int n2 = 0;
			int result2 = 10 / n2;
			System.out.println("2. 결과값: " + result2);			
		} catch (ArithmeticException arithmeticException) {
			// 예외처리 코드구현 ==> 사용자에게 친절하게 예외 메세지를 알려주는 것이다.
			// 아무 예외클래스가 아닌 적합한 예외클래스 지정. 다형성 가능
			// 다형성 : RuntimeException , Exception ,... (권장안함)
			System.out.println("ArithmeticException: 0 으로 나누어 예외가 발생됨." 
			+ arithmeticException.getMessage());
			// ArithmeticException: 0 으로 나누어 예외가 발생됨./ by zero
			
			arithmeticException.printStackTrace(); // 개발자가 디버깅시 주로 사용됨.
			/*
			 * java.lang.ArithmeticException: / by zero
				at exam20_exception.ExceptionTest02_try_catch2_예외메세지제공.main
				(ExceptionTest02_try_catch2_예외메세지제공.java:16)
			 */
			
			
		}

		System.out.println("----- 프로그램 종료 -----");
	}
}
package exam20_exception;

public class ExceptionTest02_try_catch3_다중catch문 {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		
		try {
			
			// 1. ArithmeticException 발생 가능한 코드
			int n = 2;
			int result = 10/n;
			System.out.println("결과값: " + result);
			
			// 2. NullPointerException 발생 가능한 코드
			String name = null;
			System.out.println("이름 길이: " + name.length());
			
			
			// 다중 catch 문은 계층구조의 자식부터 처리한다 예를들어 catch 문 처음으로 Exception 이나
			// RuntimeException 을 쓰게되면 자식 예외처리는 사용하지 못한다.
		} catch (ArithmeticException e) {
			System.out.println("0 으로 나누어 예외가 발생됨." + e.getMessage());			
		} catch (NullPointerException e) {
			System.out.println("name 값이 초기화 안되어 있음." + e.getMessage());
		} catch (Exception e) { // 가장 마지막 catch 문에 Exception 을 지정하는 방법이 관례.
			System.out.println("예외발생." + e.getMessage());
		}

		System.out.println("----- 프로그램 종료 -----"); // 정상종료
	}
}
package exam20_exception;

public class ExceptionTest02_try_catch4_finally문 {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		
		try {
			
			// 1. ArithmeticException 발생 가능한 코드
			int n = 2;
			int result = 10/n;
			System.out.println("결과값: " + result);
			
			// 2. NullPointerException 발생 가능한 코드
			String name = null;
			System.out.println("이름 길이: " + name.length());
			
			
			// 다중 catch 문은 계층구조의 자식부터 처리한다 예를들어 catch 문 처음으로 Exception 이나
			// RuntimeException 을 쓰게되면 자식 예외처리는 사용하지 못한다.
		} catch (ArithmeticException e) {
			System.out.println("0 으로 나누어 예외가 발생됨." + e.getMessage());			
		} catch (NullPointerException e) {
			System.out.println("name 값이 초기화 안되어 있음." + e.getMessage());
		} catch (Exception e) { // 가장 마지막 catch 문에 Exception 을 지정하는 방법이 관례.
			System.out.println("예외발생." + e.getMessage());
		} finally {
			// 예외가 발생되거나 안되거나 반드시 실행해야되는 문장처리
			// 일반적으로 파일사용 및 DB 연동시 close 작업처리
			System.out.println("finally문: 반드시 수행되는 문장");
		}

		System.out.println("----- 프로그램 종료 -----"); // 정상종료
	}
}
package exam20_exception;

public class ExceptionTest02_try_catch4_finally문2 {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		
		try {
			
			System.out.println("실행문");
			
		// 예외처리 목적이 아닌 반드시 수행해야되는 문장의 정보를 알려주는 목적
		} finally {
			// 예외가 발생되거나 안되거나 반드시 실행해야되는 문장처리
			// 일반적으로 파일사용 및 DB 연동시 close 작업처리
			System.out.println("finally문: 반드시 수행되는 문장");
		}

		System.out.println("----- 프로그램 종료 -----"); // 정상종료
	}
}

 

다. 예외클래스 + throws 예외클래스 문 ( 위임처리. ************* )
       - 예외가 발생된 곳이 아닌 다른 곳에서 위임 받아서 처리하는 방법이다.

       - 위임처리방법

       main(){               a(){                 b(){
                                                 //예외가 발생된 곳에서 예외처리
                                                  try{
         a();                 b();                  int n= 10/0; //ArithmeticException 발생
                                                  }catch(ArithmeticException e){

  }
     sysout("정상종료");
       }                     }                    }
     ##########################################################   
 
     main(){                               a()throws Arithmet~{                 b()throws ArithmeticException{
                                                                                                 //예외가 발생된 곳에서 예외처리가 아닌 위임방식
                                                                                                    ==> 메서드를 호출한 곳으로 위임한다.
      try{                                            
         a();                                       b();                                          int n= 10/0; //ArithmeticException 발생
      }catch(Ar~  e){
        e.printStackTrace();
      }
  
     sysout("정상종료");
     }                                            }                                                            }

 

package exam20_exception;

class Test {
	
	public void a() throws ArithmeticException {
		b();
	};
	
	public void b() throws ArithmeticException {
		int n = 0;
		int result = 10 / n;
		System.out.println("결과값: " + result);		
	};
}// end Test


public class ExceptionTest03_throws {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		Test t = new Test();
		try {
			t.a();			
		} catch (ArithmeticException arithmeticException) {
			// 정확한 예외클래스를 지정. 다형성 적용가능(권장안함)
			// 다형성: RuntimeException, Exception,...
			System.out.println(arithmeticException.getMessage());
		}

		System.out.println("----- 프로그램 종료 -----");
	}
}
package exam20_exception;

class Test2 {
	
	public void a() throws ArithmeticException, NullPointerException {
		b();
	};
	
	public void b() throws ArithmeticException, NullPointerException {
		// b 에서 발생할수 있는 모든 예외처리(ArithmeticException, NullPointerException)를 해줘야한다
		// 1. ArithmeticException 발생 가능한 코드
		int n = 2;
		int result = 10/n;
		System.out.println("결과값: " + result);
		
		// 2. NullPointerException 발생 가능한 코드
		String name = null;
		System.out.println("이름 길이: " + name.length());	
	};
}// end Test


public class ExceptionTest03_throws2_다중throws {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		Test2 t = new Test2();
		try {
			t.a();			
		} catch (ArithmeticException arithmeticException) {
			// 정확한 예외클래스를 지정. 다형성 적용가능(권장안함)
			// 다형성: RuntimeException, Exception,...
			System.out.println(arithmeticException.getMessage());
		} catch (NullPointerException nullPointerException) {
			// 정확한 예외클래스를 지정. 다형성 적용가능(권장안함)
			// 다형성: RuntimeException, Exception,...
			System.out.println(nullPointerException.getMessage());
		} catch (Exception exception) { // 마지막 catch 는 Exception 으로 처리한다. (관례)
			System.out.println(exception.getMessage());
		}

		System.out.println("----- 프로그램 종료 -----");
	}
}

 

4) Overriding 관련 throws 처리
부모:
public void a( ) throws ArithmeticException{ }

자식:
@Override
public void a( 같거나 확대 ) ( 축소 ) { } // 가능
@Override
public void a( 같거나 확대 ) throws ArithmeticException ( 축소 ) { } // 가능
@Override
public void a( 같거나 확대 ) throws RuntimeException ( 축소 ) { } // 불가능
@Override
public void a( 같거나 확대 ) throws Exception ( 축소 ) { } // 불가능
@Override
public void a( 같거나 확대 ) throws IOEException ( 축소 ) { } // 불가능

package exam20_exception;

import java.io.IOException;

class Super {
	public void a() throws ArithmeticException {}
	public void b() throws Exception {}
}

class Child extends Super {
	
	@Override
	public void b() throws IOException {} // 부모의 예외클래스보다 하위 클래스는 사용 가능
	
//	@Override
//	public void a(){} // 가능
//	@Override
//	public void a() throws ArithmeticException {} // 가능
	@Override
	public void a() throws RuntimeException {} // 가능
	
//	@Override
//	public void a() throws Exception {} // 부모의 예외클래스보다 상위클래스는 불가능
//	@Override
//	public void a() throws IOException {} // 부모의 예외클래스보다 상위클래스는 불가능 (확대개념)
}

public class ExceptionTest03_throws3_오버라이딩 {
	
	public static void main(String[] args) {
		System.out.println("----- 프로그램 시작 -----");
		
		
		System.out.println("----- 프로그램 종료 -----");
	}
}

 

2. Runtime 계열의 특징
- try~catch 또는 throws 방식으로 예외처리를 하는 것이 아니다.
  이유는 실제로는 실행할 때 예외가 발생되면 안되는 코드들이다.

- 다음 런타임계열은 조건문으로 처리해야 된다.

ArithmeticException( ex) 10/0 )
ex)
int n = 0;
if( n != 0)
int result = 10 / n;

ClassCastException (ex) 클래스 형변환시)
ex)
Employee e = new Manager( );
Manager m = (Manager)e;
Cat c = (Cat)e; // ClassCastException 발생
>>>
Employee e = new Manager( );
Manager m = (Manager)e;
if( e instanceof Cat )
Cat c = (Cat)e; 

NullPointerException 
(ex) null 값을 가진상태로 메서드 호출시
ex)
String name = null;
sysout( name.length( ) ); // NullPointerException 발생
>>>
String name = null;
if( name != null )
sysout( name.length( ) ); 

ArrayIndexOutOfBoundsException
(ex) 없는 배열요소 접근시


3. 비 런타임 계열

- IOException, SQLException
- 규칙: 반드시 try~catch 또는 throws 문을 이용해서 예외처리해야 된다. ( * )
          예외처리 안하면 컴파일 예외가 발생된다.

결론은 I/O 작업 또는 DB 연동작업시 무조건 예외처리를 해야 된다. ( * )

4. 명시적으로 예외를 발생시킬 수 있다. + 사용자정의 예외 클래스 작성

- 용도: 시스템은 실행문장을 예외로 처리하지 않는 정상적인 코드로
          인식하기 때문이다. 그런데 사용자는 문제있는코드로 인식 할수 있다.

ex) Random 클래스에서 랜던값이 0 일때

- 문법:
ex)
if( n == 0) throw new MyException("예외메시지"); // 강제적(명시적)으로 예외발생

- throw vs throws
throw: 명시적으로 에외 발생할 때
throws: 위임할때

- 사용자정의 예외 클래스 작성 방법:

public class MyException extends Exception {
        // 문자열 하나 저장가능한 생성자만 있으면 됨.
        // 필요시 추가로 변수, 메서드 지정 가능.
       public MyException(String message) {
super(message);
       }
}

 

package exam20_exception;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class ExceptionTest04_비런타임계열처리 {
	public static void main(String[] args) {
		
		File f = new File("C:\\java_study\\eclipse\\workspace\\HelloTest\\src\\exam20_exception\\ExceptionTest04_비런타임계열처리.java");
		
		// 입 출력을 할때 무조건 예외처리를 해야한다.
		try {
			FileReader fileReader = new FileReader(f);
			BufferedReader bufferedReader = new BufferedReader(fileReader);
			String s = bufferedReader.readLine(); // 한줄 읽기
			while ( s != null) {
				System.out.println(s);				
				s = bufferedReader.readLine(); // 한줄 읽기
			}
			
		} catch (FileNotFoundException e) { // -> new BufferedReader(fileReader); 예외처리
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) { // -> bufferedReader.readLine(); 예외처리
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}// end main
}

 

 

* 명시적으로 예외발생

package exam20_exception;

import java.util.Random;

//ArithmeticException: 0으로 나눴을때 발생하는 예외

// 사용자 클래스
class MyRandom {
	
	public int random() throws MyException { // throws: 위임할때 사용
		Random r = new Random();
		int n = r.nextInt(3); // 0, 1, 2
		
		// 조건문 추가 + throw
		// throw: 명시적으로 예외를 발생시키고 싶을때 사용
//		if(n == 0) throw new ArithmeticException("0 이 랜덤값 반환되어 예외발생"); 
		// 현재 이상황에서 적합하지 않은 예외클래스이다.(ArithmeticException)
		// 그래서 직접 '사용자정의 에외 클래스' 를 만들어줘야한다.
		
		// >>>
		
		if(n == 0) throw new MyException("0 이 랜덤값 반환되어 예외발생"); 
		
		return n;
	}
	
}// end class


public class ExceptionTest05_명시적예외발생 {
	public static void main(String[] args) {		
		System.out.println("----- 프로그램 시작 -----");
		
		MyRandom r = new MyRandom();
		try {
			 // 0 이 나오면 명시적으로 예외를 발생시키고 싶다. ( 시스템상으로는 예외x )
			// 명시적으로 예외를 발생시켰어도 예외처리를 해줘야 한다.
			int result = r.random();
			System.out.println("랜덤값: " + result);			
		} catch (MyException e) {
			// TODO: handle exception
			System.out.println(e.getMessage());
		}
		
		
		
		
		
		
		System.out.println("----- 프로그램 종료 -----");		
	}// end main
}
package exam20_exception;

// 사용자 정의 예외 클래스 작성 방법
public class MyException extends Exception {

	public MyException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}
	
}