원지의 개발
article thumbnail
728x90

1. 예외

  • 에러에 대한 처리
  • 예외처리 메커니즘 제공
  • 문제가 될 만한 부분을 사전에 예상하고 → 문제가 발생하면 이렇게 처리하라고 프로그래밍 하는 것
    목적: 실행이 멈추지 않게
에러 - 심각한 것 / 예외 - 미약한 것

컴파일러 에러 (Compile-time Error): 문법적으로 틀린 부분, 컴파일 할 때 발생하는 에러
런타임 에러 (& Runtime Exception, 실행 예외): (컴파일 과정에서) 실행 할 때 일어나는 에러 / 프로그램 종료
논리적 에러(Logical Error): 작성 의도와 다르게 동작 / 프로그램 종료 X

주요 실행 예외

  • NullPointException (NPE) - null값을 갖는 참조 변수 / dot(.)을 사용했을 때 발생
  • ArrayIndexOutOfBoundsException - 배열의 인덱스 범위 초과
  • NumberFormatException - 문자열→숫자로 변경하는 경우 발생
  • ClassCastException - 클래스 형변화 에러

1.1. 예외 처리 방법1: try ~ catch ~ finally 

try {
     모든 프로그램 코드
} catch (Exception e) {
    에러 발생시 처리할 내용
} finally {
   무조건 실행
}

  • catch 블럭{ } 여러개 가능 = 다중  catch
  • try 괄호 생략 불가

1.1.1. 다중 catch

  • 둘 이상의 예외 처리
주의! 상위 예외 클래스가 하위 예외 클래스보다 아래쪽에 위치해야 함
        예외 처리 클래스도 상속 관계를 가지는데, 주의하지 않으면 자식 클래스들이 실행 안됨

상속관계 확인: ctrl + t
Exception은 예외 클래스들의 부모클래스

1.2. 예제

더보기

RunTimeEx - 실행예외 되는 경우 4가지

<java />
package day10.exception.trycatch; import day06.inherit.good.Person; public class RunTimeEx { public static void main(String[] args) { // 실행예외(runtime) // String s = null; // if(s != null) { // s.charAt(0); // } // ArrayIndexOut // int[] arr = {1, 2, 3}; // arr[5] = 10; // ClassCast // Object o = new Object(); // Person p = (Person)o; // Person으로 생성된 객체만 Person으로 캐스팅 가능 // NumberFormat // String s = "홍길동"; // Integer.parseInt(s); // 숫자로 바꿔주는 기능 } }

TryCatchEx01

<java />
package day10.exception.trycatch; public class TryCatchEx01 { public static void main(String[] args) { int a = 10; int b = 0; System.out.println(a + b); try { System.out.println(a / b); System.out.println("이 문장은 실행이 될까요?"); // 실행 안됨, 위에서 에러 발생시 catch영역으로 바로 넘어감 // catch뒤에는 해당 예외를 처리할 수 있는 예외 종류가 들어갑니다. } catch (Exception e) { System.out.println("0으로 나눌 수 없습니다"); } System.out.println(a - b); } } ----------------------출력------------------- 10 0으로 나눌 수 없습니다 10
  • a+b, a-b의 경우는 예외가 없으므로 그대로 출력
  • 에러, 예외가 생길 것 같은 구문에 try-catch로 예외시 나올 문장(0으로 나눌 수 없습니다.) 출력
  • try{}의 경우 에러가 발생하는 순간 아래 부분은 실행이 안되고 바로 catch 영역으로 넘어감

TryCatchEx02

<java />
package day10.exception.trycatch; public class TryCatchEx02 { public static void main(String[] args) { String[] arr = {"홍길동", "이순신", "홍길자"}; int i = 0; while(i < 4) { try { System.out.println(arr[i]); } catch (Exception e) { System.out.println("범위를 벗어났습니다"); } finally { System.out.println("이 문장은 예외 여부와 상관없이 항상 실행됨"); } i++; } } } ---------------------------출력-------------------------- 홍길동 이 문장은 예외 여부와 상관없이 항상 실행됨 이순신 이 문장은 예외 여부와 상관없이 항상 실행됨 홍길자 이 문장은 예외 여부와 상관없이 항상 실행됨 범위를 벗어났습니다 이 문장은 예외 여부와 상관없이 항상 실행됨
  • String[] 배열 타입 arr에 초기화 된 값이 있음
  • while 반복문으로 i = 0 ~ 3까지 돌면서 배열값이 출력
  • 에러가 발생하면 catch 영역의 범위를 벗어났다는 문구 출력
  • finally영역은 예외 여부와 상관없이 반복을 돌때마다 출력

MultiCatchEx01 - 복습

<java />
package day10.exception.trycatch; public class MultiCatchEx01 { public static void main(String[] args) { // main의 args 사용방법 // run -> run configuration -> argments탭에 -> ${string_prompt} try { // main 메소드의 String[] args는 사용자가 입력한 값(문자열)을 args(파라미터)에 할당하는 것을 의미 String data1 = args[0]; String data2 = args[1]; int n1 = Integer.parseInt(data1); // String타입의 숫자를 int타입으로 변환 int n2 = Integer.parseInt(data2); System.out.println("두 수의 합: " + (n1 + n2)); String s = null; s.charAt(0); // string으로 저장된 문자열 중에서 한글자만 선택해서 char타입으로 변환 } catch (ArrayIndexOutOfBoundsException e) { System.out.println("매개값은 2개 입력하세요"); } catch (NumberFormatException e) { System.out.println("매개값은 숫자로 입력하세요"); } catch (Exception e) { // 어떤 실행 예외든 처리가 가능 (예외의 부모) (클래스의 상속 관계: ctrl + t) System.out.println("기타 예외 입니다"); } // System.out.println(args[0]); // System.out.println(args[1]); } }

 

실행을 여기서도 가능

1.2.1. TryCatchEx03 - 엔터 개행 제거

<java />
package day10.exception.trycatch; import java.util.Scanner; public class TryCatchEx03 { public static void main(String[] args) { // 입력과 예외처리 // 0을 입력하기 전까지 숫자를 입력 Scanner scan = new Scanner(System.in); while(true) { try { // 예외 발생 가능성이 있는 코드 System.out.print(">"); // 1. int num = Integer.parseInt( scan.nextLine() ); // nextLine은 엔터값을 포함해서 다시 받아줌 int num = scan.nextInt(); // 정수를 받음 (문자 입력하면 프로그램 멈춤, 예외, 에러 발생) if(num == 0) break; // // try 내부의 코드에서 에러 발생시 예외를 받아옴(catch가 실행되는 동안 프로그램 멈추지 않음) } catch (Exception e) { System.out.println("숫자로 입력하세요"); // 2. scan = new Scanner(System.in); // 내풀이 scan.nextLine(); // 3. 엔터개행을 제거 } } } } --------------------------출력------------------------ >1 >나 숫자로 입력하세요 >
  • nextint로 정수를 입력받고, 엔터를 치면 개행문자는 제거하지 않은 채 그대로 남겨줌
  • 남은 개행문자가 nextLine으로 입력 처리되어 문자를 받지 못하고 바로 개행
  • 오류를 해결하려면 nextLine전 scan.nextLine을 한번더 작성하여 개행문자 제거

1.2.2. Quiz16 - up/down 게임, 엔터 개행 제거

<java />
package quiz16; import java.util.Scanner; public class MainClass { public static void main(String[] args) { /* * up down게임 * * 1~100까지의 임의의 숫자를 1번 생성 * 반복문 안에서 스캐너를 이용해서 정답을 입력받습니다. * * 랜덤수가 입력받은 값보다 작으면 "더 큰수를 입력하세요" * 랜덤수가 입력받은 값보다 크면 "더 작은수를 입력하세요" * * 정답이라면 시도횟수: x회 를 출력하고 종료 * * 만약에 숫자가 아닌값이 들어온다면 예외를 처리하고, 다시 입력받으세요 */ Scanner scan = new Scanner(System.in); int ran = (int)((Math.random()*100) + 1); int count = 0; // 시도횟수 while(true) { try { System.out.println("정답입력>"); int answer = scan.nextInt(); count++; if(answer == ran) { System.out.println("정답"); System.out.println("시도 횟수: " + count); break; } else if(answer > ran) { System.out.println("더 작은수를 입력해라"); } else System.out.println("더 큰 수를 입력해라"); } catch (Exception e) { System.out.println("숫자로 입력해라"); scan.nextLine(); // while안 무한루프, catch영역에 들어오면 엔터를 강제로 제거 count++; // 잘못입력한 값도 시도횟수로 들어가야 하므로 } } } }

1.3. 예외 처리 방법2: throws (예외 떠넘기기) 

  • throws는 직접 처리하지 않고, 메서드 or 생성자를 호출한 곳으로 예외를  떠넘김
    = 메서드 호출자에게 예외를 던지는 방법
  • 예외가 일어나면 통으로 메서드 종료
  • throws 키워드가 붙은 메서드는 반드시 try 블록 내부에서 호출되어야 함. 
  • main도 throws 사용 가능
throws는 예외가 날 수 있는 프로그램 코드 → try-catch로 묶고 쓰라고 강요!!

1.3.1. 예외 강제 발생: throw

  • 예외를 직접 생성하는 방법으로 잘 사용되지는 않음
  • 예외를 강제 발생시키며 메서드를 강제 종료

1.3.2. ThrowsEx01

e.printStackTrace(): 예외 발생 당시의 호출스택(Call stack)에 있던 메소드의 정보와 예외 결과를 화면에 출력

<java />
package day10.exception.throws_; public class ThrowsEx01 { public static void main(String[] args) { // 메서드에서 예외처리 - throws // throws 구문이 붙어있는 메서드 ar 생성자를 호출할때는 예외를 대신 처리애햐 합니다. // 즉 메서드안에서 예외처리를 강요할 때 사용합니다. try { // 호출문장 안에서 예외처리 해줘야 함 greeting(0); greeting(1); greeting(2); greeting(3); greeting(4); } catch (Exception e) { System.out.println("배열 참조를 벗어났습니다"); } System.out.println("------------------"); try { calc(0); } catch (Exception e) { System.out.println("\"0으로 나눌 수 없습니다."); } System.out.println("------------------"); try { greeting(5); } catch (Exception e) { // 예외처리를 하면 예외의 내용을 알수가 없기 때문에, // 예외의 내용을 확인하기 위해서 catch영역에서는 항상 사용합니다. e.printStackTrace(); } System.out.println("프로그램 정상 종료"); } // main의 끝 // static private static String[] arr = {"안녕하세요", "hello", "니하오", "곤니찌와" }; public static void greeting(int index) throws Exception { System.out.println(arr[index]); } public static void calc(int num) throws ArithmeticException { System.out.println(10 / num); } }

1.3.3. ThrowsEx02 - 1

<java />
package day10.exception.throws_; public class ThrowsEx02 { // 생성자 public ThrowsEx02() throws Exception { System.out.println("생성자호출"); aaa(); System.out.println("생성자종료"); } public void aaa() throws Exception { System.out.println("aaa시작"); bbb(1); System.out.println("aaa종료"); } public void bbb(int i) throws Exception{ System.out.println("bbb시작"); // try { // System.out.println(i / 0); // 예외 // } catch (Exception e) { } System.out.println(i / 0); // 예외 System.out.println("bbb종료"); } } // MainClass package day10.exception.throws_; public class MainClass { public static void main(String[] args) { try { ThrowsEx02 ex = new ThrowsEx02(); } catch (Exception e) { System.out.println("0으로 나눌 수 없습니다"); } } } -------------------------호출--------------------- 생성자호출 aaa시작 bbb시작 0으로 나눌 수 없습니다
  • ThrowsEx02 - "생성자호출" - aaa() - "aaa시작" - bbb(1) - "bbb시작" - i/0 예외발생 - main의 "0으로 나눌 수 없습니다"문구 출력 - 종료

1.3.4. ThrowsEx02 - 2

<java />
package day10.exception.throws_; public class ThrowsEx02 { // 생성자 public ThrowsEx02() throws Exception { System.out.println("생성자호출"); aaa(); System.out.println("생성자종료"); // aaa()가 끝나고 실행 } public void aaa() throws Exception { System.out.println("aaa시작"); try { bbb(1); } catch (Exception e) { System.out.println("0으로 나눌 수 없습니다"); } System.out.println("aaa종료"); // bbb()가 끝나고 실행 } public void bbb(int i) throws Exception{ System.out.println("bbb시작"); // try { // System.out.println(i / 0); // 예외 // } catch (Exception e) { } System.out.println(i / 0); // 예외 System.out.println("bbb종료"); } } // main은 같음 -------------------------호출--------------------- 생성자호출 aaa시작 bbb시작 0으로 나눌 수 없습니다 aaa종료 생성자종료
  • ThrowsEx02 - "생성자호출" - aaa() - "aaa시작" - bbb(1) - "bbb시작"- 예외발생 - main의 "0으로 나눌 수 없습니다"문구 출력 - (bbb는 뒷부분 실행 X) - aaa()안의 bbb(1)실행 후 "aaa종료" - 같은 방식으로 위의 "생성자종료"

1.3.5. quiz16 - calculator

<java />
package quiz16; import java.util.Scanner; public class Calculator { public static int input() throws Exception { /* * 1. 스캐너 정수 2개를 입력을 받습니다. * 2. 입력된 값이 정수라면 합계를 반환합니다. * 3. 예외가 발생할 수 있는 상황이라면 throw를 이용해서 메서드를 종료하고 예외메시지를 전달해주면 됩니다 * 4. scan.close() 는 finally 문장에서 사용하세요 * 합계반환, 에러메시지 */ // Scanner scan = null; 변수를 밖에 선언, 지역변수는 초기화가 필수 // try안에 scan = new Scanner(System.in); 아래와 같음 Scanner scan = new Scanner(System.in); try { System.out.println("정수 입력1> "); int a = scan.nextInt(); System.out.println("정수 입력2> "); int b = scan.nextInt(); int sum = 0; sum = a + b; System.out.println("정수 합계: " + sum); return sum; } catch (Exception e) { throw new Exception("정수로 입력해라"); // 예외생성, throw문제가 생기면서 input()옆에 throws Exception 추가 } finally { scan.close(); System.out.println("입력을 종료"); } } }
  • Scanner scan = new Scanner(System.in);
                                  ∥
  • Scanner scan = null; (변수를 밖에 선언, 지역변수는 초기화가 필수)
    try안에 scan = new Scanner(System.in);
  • throw new Exception("정수로 입력해라");
    예외생성, throw문제가 생기면서 input()옆에 throws Exception 추가
<java />
package quiz16; public class MainClass2 { public static void main(String[] args) { try { Calculator.input(); } catch (Exception e) { e.printStackTrace(); System.out.println(e.getMessage()); } finally { // 여기서는 없어도 됨 System.out.println("입력을 종료합니다"); } } }
  • main에서 Calculator.input(); 출력
  • 예외구문 System.out.println(e.getMessage()); : throw new Exception에 적은 출력

오늘 하루

더보기

기억에 남는 부분

- main과 method에서 한꺼번에 try~catch 구문 사용 가능

- throws 키워드가 붙은 메서드는 반드시 try 블록 내부에서 호출 필수

 

어려운 부분

- nextInt, nextLine 개행문자 저장되는 부분 살짝 헷갈리지만 알겠음

- ThrowsEx02 부분 throws가 돌아가는 순서 확인

 

문제 해결 부분

- quiz16.Calculator class, main 두 부분에 예외 설정 가능
  e.printStackTrace();, System.out.println(e.getMessage()); 사용

 

728x90
profile

원지의 개발

@원지다

250x250