프로그램 실행 중 예기치 못한 사건을 예외라고 한다. 예외 상황을 미리 예측하고 처리할 수 있는데, 이렇게 하는 것을 예외 처리라고 한다.
public class ExceptionExam {
public static void main(String[] args) {
int i = 10;
int j = 5;
int k = i / j;
System.out.println(k);
System.out.println(main 종료!!);
}
}
위 코드에서 j를 0으로 바꾸면 ArithmeticException이 발생하면서 프로그램이 종료된다.
프로그래머는 j라는 변수에 0이 들어올지도 모르는 예외 상황을 미리 예측하고 처리할 수 있다.
public class ExceptionExam {
public static void main(String[] args) {
int i = 10;
int j = 0;
try{
int k = i / j;
System.out.println(k);
}catch(ArithmeticException e){
System.out.println("0으로 나눌 수 없습니다. : " + e.toString());
}finally {
System.out.println("오류가 발생하든 안하든 무조건 실행되는 블록입니다.");
}
}
}
실행결과
0으로 나눌 수 없습니다. : java.lang.ArithmeticException: / by zero
오류가 발생하든 안하든 무조건 실행되는 블록입니다.
Exception 처리하지 않았을때는 프로그램이 강제 종료되었는데 catch라는 블록으로 Exception을 처리하니 강제종료되지 않고 잘 실행되는 것을 알 수 있다.
try블록에서 여러종류의 Exception이 발생한다면 catch라는 블록을 여러개 둘 수 있다.
Exception클래스들은 모두 Exception클래스를 상속받으므로, 예외클래스에 Exception을 두게 되면 어떤 오류가 발생하든지 간에 하나의 catch블록에서 모든 오류를 처리할 수 있다.
throws는 예외가 발생했을때 예외를 호출한 쪽에서 처리하도록 던져준다.
public class ExceptionExam2 {
public static void main(String[] args) {
int i = 10;
int j = 0;
int k = divide(i, j);
System.out.println(k);
}
public static int divide(int i, int j){
int k = i / j;
return k;
}
}
정수를 매개변수로 2개를 받아들인 후 나눗셈을 한 후 그 결과를 반환하는 divide메소드
main메소드에서는 divde메소드를 호출
다음과 같이 divide메소드를 수정
public class ExceptionExam2 {
public static void main(String[] args) {
int i = 10;
int j = 0;
int k = divide(i, j);
System.out.println(k);
}
public static int divide(int i, int j) throws ArithmeticException{
int k = i / j;
return k;
}
}
메소드 선언 뒤에 throws ArithmeticException 이 적혀있는 것을 알 수 있다. 이렇게 적어놓으면 divide메소드는 ArithmeticException이 발생하니 divide메소드를 호출하는 쪽에서 오류를 처리하라는 뜻이다.
package javaStudy;
public class ExceptionExam2 {
public static void main(String[] args) {
int i = 10;
int j = 0;
try{
int k = divide(i, j);
System.out.println(k);
} catch(ArithmeticException e){
System.out.println("0으로 나눌수 없습니다.");
}
}
public static int divide(int i, int j) throws ArithmeticException{
int k = i / j;
return k;
}
}
throw는 오류를 떠넘기는 throws와 보통 같이 사용된다.
public class ExceptionExam3 {
public static void main(String[] args) {
int i = 10;
int j = 0;
int k = divide(i, j);
System.out.println(k);
}
public static int divide(int i, int j){
int k = i / j;
return k;
}
}
위의 코드를 에러가 발생하지 않게 수정
public class ExceptionExam3 {
public static void main(String[] args) {
int i = 10;
int j = 0;
int k = divide(i, j);
System.out.println(k);
}
public static int divide(int i, int j){
if(j == 0){
System.out.println("2번째 매개변수는 0이면 안됩니다.");
return 0;
}
int k = i / j;
return k;
}
}
public class ExceptionExam3 {
public static void main(String[] args) {
int i = 10;
int j = 0;
int k = divide(i, j);
System.out.println(k);
}
public static int divide(int i, int j) throws IllegalArgumentException{
if(j == 0){
throw new IllegalArgumentException("0으로 나눌 수 없어요.");
}
int k = i / j;
return k;
}
}
divide 메소드를 호출 한 쪽에서의 오류 처리
public class ExceptionExam3 {
public static void main(String[] args) {
int i = 10;
int j = 0;
try{
int k = divide(i, j);
System.out.println(k);
}catch(IllegalArgumentException e){
System.out.println("0으로 나누면 안됩니다.");
}
}
public static int divide(int i, int j) throws IllegalArgumentException{
if(j == 0){
throw new IllegalArgumentException("0으로 나눌 수 없어요.");
}
int k = i / j;
return k;
}
}
Exception 클래스를 상속 받아 정의한 checked Exception
RuntimeException 클래스를 상속 받아 정의한 unChecked Exception
RuntimeException을 상속받은 BizException객체
public class BizException extends RuntimeException {
public BizException(String msg){
super(msg);
}
public BizException(Exception ex){
super(ex);
}
}
BizService클래스는 업무를 처리하는 메소드를 가지고 있다고 가정한다.
public class BizService {
public void bizMethod(int i)throws BizException{
System.out.println("비지니스 로직이 시작합니다.");
if(i < 0){
throw new BizException("매개변수 i는 0이상이어야 합니다.");
}
System.out.println("비지니스 로직이 종료됩니다.");
}
}
앞에서 만든 BizService를 이용하는 BizExam클래스
public class BizExam {
public static void main(String[] args) {
BizService biz = new BizService();
biz.bizMethod(5);
try{
biz.bizMethod(-3);
}catch(Exception ex){
ex.printStackTrace();
}
}
}
실행결과
비지니스 로직이 시작합니다.
비지니스 로직이 종료됩니다.
비지니스 로직이 시작합니다.
javaStudy.BizException: 매개변수 i는 0이상이어야 합니다.
at javaStudy.BizService.bizMethod(BizService.java:7)
at javaStudy.BizExam.main(BizExam.java:9)
시스템 운영에 대한 기록
오류가 발생 했을 때 그 오류에 대한 기록을 남겨 디버깅을 용이하게 함
로그 파일에 기록하는 코드를 추가하여 필요한 정보가 로그로 남을 수 있도록 한다
디버깅, 시스템 에러 추적, 성능, 문제점 향상들을 위해 사용
어느정도까지 로그를 남길 것인가?
너무 적은 로그 : 정확한 시스템의 상황을 파악하기 어려움
너무 많은 로그 : 빈번한 file I/O의 오버헤드와 로그 파일의 백업 문제등...
자바에서 기본적으로 제공되는 log package
파일이나 콘솔에 로그 내용을 출력할 수 있음
jre/lib/logging.properties 파일을 편집하여 로그의 출력방식 로그 레벨을 변경 할 수 있음
logging 패키지에서 제공하는 로그 레벨은 severe, warning, info, config, fine, finer, finest 임
오픈소스로는 log4j를 많이 사용하고 있음