예외(Exception)
컴파일 에러 : 문법상 오류
예외(Exception) : 문법상의 오류가 아닌 '실행중' 에 발생되는 오류상황
(기본적으로) 예외 가 발생되면, 예외 관련 메세지 출력하고 프로그램이 종료 됩니다.
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 [] numbers2 = 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 {} 블럭을 '예외처리'
블럭으로 만듦으로 코드 분석이 훨씬 용이.
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 실패 처리
}
주의! : 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
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 활용
자원 : 키보드, 파일, 데이터베이스, 네트워크 ...
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
throws
메소드 설계를 할 때 예외 처리를 직접 하지 않는 경우:
메소드 이름 뒤에 throws Exception을 추가하면,
예외가 발생한 경우에는 메소드를 호출한 곳으로 exception이 던져짐.
'Exception' 및 이를 '직접 상속받은' Exception 을 throws 하는 메소드의 경우,
이 메소드를 호출하는 쪽에서 반.드.시 예외 처리 (handling) 해야 한다. 안하면 에러!
반면 'RuntimeException' 및 이를 상속받은 예외를 throws 하는 메소드는
굳이 호출하는 쪽에서 매번 예외 처리 할 필요는 없다.
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);
} 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);
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 클래스 만들어 사용하기 & throw
Exception 또는 RuntimeException 클래스를 상속 받아서 만듦
package com.lec.java.exception07;
import java.util.Scanner;
/* Exception 클래스 만들어 사용하기 & throw
Exception 또는 RuntimeException 클래스를 상속 받아서 만듬
*/
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 : Excetpion 을 상속받아 예외 클래스 정의하기
public class ScoreException extends Exception{
// 생성자
public ScoreException() {
super("점수 입력 오류");
// Exception(String message) 생성자 호출
}
public ScoreException(String msg) {
super(msg);
}
} // end class ScoreException
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
'JAVA' 카테고리의 다른 글
[JAVA] 문자열 메소드 (0) | 2022.02.17 |
---|---|
[JAVA] 정규표현식 (0) | 2022.02.17 |
[JAVA] 다형성, 추상 클래스, 인터페이스 (0) | 2022.02.09 |
[JAVA] 상속 (0) | 2022.02.09 |
[JAVA] 접근제한자, final, static (0) | 2022.02.09 |