- 컴파일 에러 : 문법상 오류
- 예외(Exception) : 문법상의 오류 가 아닌 '실행중' 에 발생되는 오류상황
-> (기본적으로) 예외 가 발생되면, 예외 관련 메세지 출력하고 프로그램이 종료 됩니다.
[Exception 화면 설명]
1. Exception 명
2. Exception 메세지
3. Exception 지점
[Exception 예시 코드1]
package com.lec.java.exception01;
import java.util.Scanner;
public class Exception01Main {
public static void main(String[] args) {
System.out.println("예외(Exception)");
System.out.println("[1] ArithmeticException");
int num1 = 123;
int num2 = 0;
// System.out.println("num1 / num2 = " + (num1 / num2));
System.out.println("[2] ArrayIndexOutOfBoundsException");
int[] numbers = new int[10];
// numbers[10] = 100;
System.out.println("[3] NegativeArraySizeException");
// int size = -1;
// int [] number2 = new int[size];
System.out.println("[4] NullPointerException(NPE)");
String str = null;
// System.out.println("스트링 길이: " + str.length());
System.out.println("[5] InputMismatchException");
Scanner sc = new Scanner(System.in);
// sc.nextInt();
sc.close();
} // end main()
} // enc class Exception01Main
try~catch를 사용하는 이유
1. if 문은 예외 처리 이외의 용도로 사용되기 때문에 프로그램 코드상에서 예외처리 부분을 구분하기가 쉽지 않다.
2. try {} 블럭은 '일반적인 흐름'을 ,catch {} 블럭을 '예외처리' 블럭으로 만듦으로 코드 분석이 훨씬 용이.
[예외처리 코드 예시1]
package com.lec.java.exception02;
public class Exception02Main {
public static void main(String[] args) {
System.out.println("예외(Exception) 처리");
int num1 = 123;
int num2 = 0;
int result = 0;
// if 문을 사용한 처리
if (num2 != 0) {
result = num1 / num2;
} else {
System.out.println("0으로 나눌 수 없습니다... ");
} // end if
System.out.println("결과: " + result);
// 위의 코드를 try~catch 로 만들어 처리
try {
// try{...} 코드 수행 블럭
result = num1 / num2;
System.out.println("결과: " + result);
} catch (ArithmeticException ex) {
// catch(){...} 예외 처리 블럭, 위의 try 블럭에서 발생되는 예외를 처리(handling)하는 코드들
System.out.println("0 으로 나누는 예외 발생");
System.out.println(ex.getMessage()); // 예외 메세지 (String)
}
System.out.println();
System.out.println("프로그램 종료...");
} // end main()
/*
특히 시스템 자원(resource), HW (파일, DB..) 등을 사용하는 프로그래밍에선
'예외' 가 언제든지 발생할수 있으므로 try ~ catch 가 필수적이다.
try {
// 1. DB connect
// 2. DB 테이블 접속/쿼리
// 3. SQL 문장 실행
// 4. 결과 출력
} catch (Exception e) {
// Exception 처리
}
if (DB connect 성공) {
if (DB table 쿼리 성공) {
if (SQL 문장 실행) {
System.out.println("결과"));
} else {
// SQL 문장 실패 처리
}
} else {
// DB 테이블 쿼리 실패 처리
}
} else {
// DB connect 실패 처리
}
*/
} // end class Exception02Main
[예외처리 코드 예시2]
package com.lec.java.exception03;
/* 예외 처리: try ~ catch
연습 01패키지에서 발생하던 예외들을 try~catch로 잡아보자
주의! : try 블럭 안에서 선언된 변수는 try 블럭안에서만 사용되는 지역변수가 된다.
catch 블럭등 다른 블럭에서도 사용 가능하게 하려면 try 바깥에서 선언해야 한다
*/
public class Exception03Main {
public static void main(String[] args) {
System.out.println("예외 처리: try ~ catch");
System.out.println();
System.out.println("[1] ArithmeticException");
// 주의! : try 블럭 안에서 선언된 변수는 try 블럭안에서만 사용되는 지역변수가 된다.
// catch 블럭 등 다른 블럭에서도 사용 가능하게 하려면 try 바깥에서 선언해야 한다.
int num1 = 0;
int num2 = 0;
try {
num1 = 123;
num2 = 0;
System.out.println("num1 / num2 = " + (num1 / num2));
} catch(ArithmeticException ex) {
System.out.println(num1 + " 은 " + num2 + "로 나누면 안돼요");
System.out.println(ex.getMessage());
ex.printStackTrace();
} // end try
System.out.println();
System.out.println("[2] ArrayIndexOutOfBoundsException");
try {
int[] numbers = new int[10];
numbers[100] = 111;
} catch (ArrayIndexOutOfBoundsException ex) {
System.out.println("예외 메세지: " + ex.getMessage());
} // end catch
System.out.println();
System.out.println("[4] NullPointerException");
try {
String str = null;
System.out.println("스트링 길이: " + str.length());
} catch (NullPointerException ex) {
System.out.println("예외 메세지: " + ex.getMessage());
} // end catch
System.out.println();
System.out.println("[5] ClassCastException");
try {
Object obj = new int[10];
String str = (String)obj;
} catch (ClassCastException ex) {
System.out.println("예외 메세지: " + ex.getMessage());
// 배열도 Object 클래스를 상속하므로 배열 인스턴스는 Object 의 참조변수로 참조가 가능하다
} // end catch
System.out.println("\n프로그램 정상종료");
} // end main
} // end class Exception03Main
package com.lec.java.exception04;
/* 예외 클래스의 상속 관계 (★필수 암기★)
java.lang.Object
|__ java.lang.Throwable
|
|__ java.lang.Exception : 복구 가능
| |
| |__ java.lang.RuntimeException
| | |__ ArithmeticException, NullPointerException, ...
| |
| |__ IOException, ParseException ...
|
|__ java.lang.Error : 복구 불가
... OutOfMemoryError, StackOverFlowError ...
getMessage(), printStackTrace() 등의 메소드는 Throwable 클래스에 정의
자식 클래스들은 Throwable에 정의된 메소드들을 사용할 수 있음
catch문은 여러개를 사용할 수는 있지만,
상위 예외 클래스를 하위 예외 클래스보다 먼저 사용할 수는 없다. (컴파일 에러)
※ 이클립스 단축키 : CTRL + T , class hierarchy (계층도) 보기
*/
public class Exception04Main {
public static void main(String[] args) {
System.out.println("try ~ catch ~ catch ");
int num1 = 123, num2 = 10, result = 0;
String str = "Java";
int[] numbers = new int[10];
// TODO : try ~ catch ~ catch .. 사용
try {
result = num1 / num2;
System.out.println("나눈 결과: " + result);
int length = str.length();
System.out.println("스트링 길이: " + length);
numbers[9] = 11111;
System.out.println("numbers: " + numbers[9]);
Object obj = new Exception04Main();
String str2 = (String)obj;
} catch(ArithmeticException ex) {
System.out.println("산술연산예외: " + ex.getMessage());
} catch(NullPointerException ex) {
System.out.println("Null 포인터 예외: " + ex.getMessage());
} catch(ArrayIndexOutOfBoundsException ex) {
System.out.println("배열 인덱스 예외: " + ex.getMessage());
} catch(Exception ex) { // 위의 catch 하는 예외들을 제외한 나머지들을 처리
System.out.println("예외 발생: " + ex.getMessage());
}
System.out.println();
System.out.println("프로그램 종료");
} // end main()
} // end class Exception04Main
multi-catch
- Java 7부터 하나의 catch문에서 여러개의 예외를 처리할 수 있는 방법을 제공
- 절대로 같은 상속레벨의 exception 들만 multi-catch 하기.
finally
- 예외(exception) 발생 여부와 상관없이 항상 실행되어야 할
- 코드들은 finally 블록 안에서 작성.
- 즉, finally 블록 안에 있는 코드들은 항상 실행이 됨.
예외가 발생하지 않을 때는, try 블록 안의 코드들이 모두 실행된 후 finally 블록의 코드들이 실행
예외가 발생할 때는, 해당 catch 블록의 코드들이 실행된 후에 finally 블록의 코드들이 실행
(주의)
try 블록이나 catch 블록 안에 return이 있더라도,
finally 블록 안의 코드들이 다 실행된 이후에
return이 실행되게 됨.
(주의)
try블럭, catch블럭, finally 블럭등에서 두루두루
사용할 변수는 try블럭 전에 선언하고, 초기화 까지 하자.
보통은 자원반납과 같은 것들을 할때 finally 활용
자원 : 키보드, 파일, 데이터베이스, 네트워크 ...
package com.lec.java.exception05;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Exception05Main {
public static void main(String[] args) {
System.out.println("multi-catch");
// Java 7부터 하나의 catch문에서 여러개의 예외를 처리할 수 있는 방법을 제공
// 절대로 같은 상속레벨의 exception 들만 multi-catch 하기.
// TODO : multi-catch 사용하기
try {
String str = "Java";
str.length();
int n = 123 / 0;
} catch(ArithmeticException
// | Exception // 다른상위 레벨의 예외를 같이 나열하면 안된다.
| NullPointerException
| ArrayIndexOutOfBoundsException ex) {
System.out.println(ex.getClass());
System.out.println(ex.getMessage());
}
System.out.println();
System.out.println("finally");
// 예외(exception) 발생 여부와 상관없이 항상 실행되어야 할
// 코드들은 finally 블록 안에서 작성.
// 즉, finally 블록 안에 있는 코드들은 항상 실행이 됨.
// 예외가 발생하지 않을 때에는 try 블록 안의 코드들이
// 모두 실행된 후에 finally 블록의 코드들이 실행
// 예외가 발생할 때는, 해당 catch 블록의 코드들이
// 실행된 후에 finally 블록의 코드들이 실행
// (주의)
// try 블록이나 catch 블록 안에 return이 있더라도,
// finally 블록 안의 코드들이 다 실행된 이후에
// return이 실행되게 됨.
System.out.println("#1 try{} 직전");
try {
System.out.println("#2 try{} 시작");
String str = null;
str.length();
// int [] numbers = new int[10];
// numbers[10] = 123;
System.out.println("#3 try{} 종료");
} catch(NullPointerException ex) {
System.out.println("#4 catch{}");
System.out.println("예외: " + ex.getMessage());
// return;
} finally {
System.out.println("#5 finally{}");
}
System.out.println("#6 try 종료후");
// try블럭, catch블럭, finally 블럭등에서 두루두루
// 사용할 변수는 try블럭 전에 선언하고, 초기화 까지 하자.
// 보통은 자원반납과 같은 것들을 할때 finally 활용
// 자원 : 키보드, 파일, 데이터베이스, 네트워크 ...
Scanner sc = new Scanner(System.in);
try {
System.out.println("정수 입력하세요");
sc.nextInt();
System.out.println("try블록 종료");
}catch(InputMismatchException ex) {
System.out.println("예외 메시지: " + ex.getMessage());
return; // 설사 리턴하더라도
}finally {
System.out.println("finally 수행");
sc.close(); // 자원 반납하는 부분은 반드시 finally{} 에서 처리
}
System.out.println();
System.out.println("프로그램 종료...");
} // end main
} // end class Exception05Main
throws
- 메소드 설계를 할 때 예외 처리를 직접 하지 않는 경우:
메소드 이름 뒤에 throws Exception을 추가하면,
예외가 발생한 경우에는 메소드를 호출한 곳으로 exception이 던져짐.
'Exception' 및 이를 '직접 상속받은' Exception 을 throws 하는 메소드의 경우,
이 메소를 호출하는 쪽에서 반.드.시 예외 처리 (handling) 해야 한다. 안하면 에러!- 반면 'RuntimeException' 및 이를 상속받은 예외를 throws 하는 메소드는 굳이 호출하는 쪽에서 매번 예외 처리 할 필요는 없다.
package com.lec.java.exception06;
public class Exception06Main {
public static void main(String[] args) /*throws Exception*/ /* TODO */ {
System.out.println("throws");
System.out.println();
TestClass test = new TestClass();
int result = test.divide(123, 0);
System.out.println("result = " + result);
System.out.println();
// divide2() 메소드가 throw Exception을 하고 있기 때문에
// 메소드를 호출하는 곳에서 예외 처리를 해주지 않으면 컴파일 에러
// 반드시 메소드 호출하는 곳에서 예외 처리를 해주어야 함.
try {
test.divide2(123, 0); // Unhandled exception
} catch (Exception e) {
e.printStackTrace();
}
// test.divide2(111, 0); // 만약에 try-catch 안할거면 main 메소드가 throws Exception 을 해줘야 한다.
// main() 메소드는 가상머신이 호출하는 메소드이다. 예외상황 처리는 가상머신에게 넘어간다
// 가상머신의 예외처리 순서
// 1 : getMessage 호출
// 2 : 예외상황이 발생해서 전달되는 과정 출력
// 3 : 프로그램 종료
// RuntimeException 및 그 자식 객체들을
// throws 하는 경우는 반드시 catch 안해줘도 에러는 안난다. > 그러나 죽음.
// test.divide3(222, 0); // RuntimeException 이므로 예외처리 필요x
String num = "123";
int n = Integer.parseInt(num);
// NumberFormatException r;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("프로그램 종료...");
} // end main()
} // end class Exception06Main
package com.lec.java.exception06;
public class TestClass {
// 메소드를 설계를 할 때
// 예외 처리를 메소드 내부에서 (try ~ catch) 로 처리
public int divide(int x, int y) {
int result = 0;
// TODO : try ~ catch 처리하기
try {
result = x / y;
} catch(ArithmeticException ex) {
System.out.println(ex.getMessage());
}
return result;
} // end divide()
// 메소드 설계를 할 때 예외 처리를 직접 하지 않는 경우:
// 메소드 이름 뒤에 throws Exception을 추가하면,
// 예외가 발생한 경우에는 메소드를 호출한 곳으로 exception이 던져짐.
// Exception 및 이를 '직접 상속받은' Exception 을 throws 하는 메소드의 경우,
// 이 메소드를 호출하는 쪽에서 반.드.시 예외 처리 (handling) 해야 한다. 안하면 에러!
// TODO : throws 사용하기
public int divide2(int x, int y) throws Exception {
return x / y;
} // end divide2()
// 반면 'RuntimeException' 및 이를 상속받은 예외를 throws 하는 메소드는
// 굳이 호출하는 쪽에서 매번 예외 처리 할 필요는 없다
// TODO : throws RuntimeException 사용하기
public int divide3(int x, int y) throws RuntimeException {
return x / y;
} // end divide3()
} // end class TestClass
- Exception 또는 RuntimeException 클래스를 상속 받아서 만듬
[예시코드1]
package com.lec.java.exception07;
import java.util.Scanner;
public class Exception07Main {
static Scanner sc = new Scanner(System.in);
// TODO : ScoreException 을 throws 하는 메소드 만들기
public static int inputScore() throws ScoreException {
int score = sc.nextInt();
if (score < 0 || score > 100) {
// ScoreException ex = new ScoreException();
ScoreException ex = new ScoreException(score + "값은 입력할수 없는 점수 (0 ~ 100)");
throw ex; // 생성한 예외 객체를 언제든지 인위적으로 throw
}
return score;
} // end inputScore()
public static void main(String[] args) {
System.out.println("예외 클래스 만들기, throw");
System.out.println();
// TODO : ScoreException 을 catch 해보자
try {
System.out.println("국어 점수 입력:");
int kor = inputScore();
System.out.println("kor = " + kor);
System.out.println("영어 점수 입력:");
int eng = inputScore();
System.out.println("eng = " + eng);
} catch (ScoreException ex) {
System.out.println(ex.getMessage());
} finally {
sc.close();
}
System.out.println("프로그램 종료");
} // end main()
} // end class Exception07Main
package com.lec.java.exception07;
// 우리가 만드는 예외 클래스
// Exception 또는 RuntimeException 클래스를 상속 받아서 만듬
// TODO : Exception 을 상속받아 예외 클래스 정의하기
public class ScoreException extends Exception {
// 생성자
public ScoreException() {
super("점수 입력 오류");
// Exception(String message) 생성자 호출
}
public ScoreException(String msg) {
super(msg);
}
} // end class ScoreException
[예시코드2]
package com.lec.java.exception08;
import java.util.Scanner;
public class Exception08Main {
static Scanner sc = new Scanner(System.in);
// TODO : AgeInputException 을 throws 하는 메소드 정의
public static int inputAge() throws AgeInputException {
System.out.println("나이 입력:");
int age = sc.nextInt();
// age 값이 음수이면
// AgeInputException 을 throw 하기
if(age < 0) {
AgeInputException ex = new AgeInputException();
throw ex;
}
return age;
} // end inputAge()
public static void main(String[] args) {
System.out.println("예외 클래스 만들기 2");
// 제대로 입력받을때까지 예외 처리 하면서 입력받게 하기
int age;
while(true) {
try {
age = inputAge();
System.out.println("나이: " + age);
break;
} catch (AgeInputException e) {
System.out.println(e.getMessage());
System.out.println("다시 입력하세요");
sc.nextLine();
}
}
sc.close();
System.out.println("프로그램 종료...");
} // end main()
} // end class Exception08Main
package com.lec.java.exception08;
// TODO : Exception 상속받은 예외 클래스 만들기
public class AgeInputException extends Exception {
public AgeInputException() {
super("나이 입력 오류");
}
} // end class AgeInputException
✨ Tips!