[01] 예외처리(Exception)
1) 이클립스상에서 개발시에 자바 클래스가 안정적으로 컴파일된 후
운영중에 발생하는 에러를 "예외"라고 한다.
예외는 코드상에서 발생하는 에러하고는 다르며 컴파일시에는
예외가 발생하지 않음.
마치 손상된 USB를 읽어오는 프로그램이 있다면 USB는 인식이되나
읽어 올 수 없음으로 경고창이 발생하는 경우.
예) 네트웍 장애, IO, DBMS 서버 다운, 저장 장치의 용량이 없는 경우등.
2) 예외가 발생하면 프로그램이 메시지 출력후 종료되어 심각한 문제가 발생
할 수 있으나 예외 처리를 하면, 예외가 발생되서 프로그램이 끝나는 것이
아니라 나머지 루틴이 정상적으로 실행됨으로 안정적인 프로그램이됨.
3) 기본 문법
- finally 블럭은 생략 가능하나, 선언되면 예외 발생과 관련없이 무조건 실행됩니다.
--------------------------------------------------------------------
try{
예외가 발생할 소지가 있는 코드를 개발자가 선별하여 지정해야하며,
"JDBC(DBMS), IO, NETWORK"관련 코드등에서 발생하는 예외는 Eclipse가 알려줍니다.
예) JDBC(DBMS): 데이터베이스 서버가 다운된 경우.
IO: USB 저장 장치가 여분이 없을 때
NETWORK: Hub에 이상이 생긴 경우, WiFi 작동 안됨.
}catch(Exception e){
예외 원인 출력, 예외 처리
Exception e 객체에는 발생한 예외의 정보를 가지고 있습니다.
System.out.println(e.toString());
예외가 발생되기까지의 메소드 호출 이력을 추적하여 출력합니다.
e.printStackTrace();
Log의 대상이 되어 파일로 기록 되어 서버 관리자가 체크함.
예) 데이터베이스 연결 종료 후 다른 서버로 재설정하며 원인 기록,
네트워크 연결 해제 후 다른 네트워크 장치 활성화하고 원인 기록,
WIFI 종료후 3G 작동 및 LTE작동 등 관련 데이터 기록
}finally{
예외와 상관 없이 무조건 실행되는 코드 블럭, 생략 가능
예) 데이터베이스 연결 종료 후 메모리 해제,
네트워크 연결 해제 후 메모리 해제,
WIFI 종료후 3G 작동 및 LTE작동 등의 필수 기능
}
* Eclipse는 자바 개발자의 예외 처리를 가이드하는 기능이 있어서,
예외 처리가 필요한 부분은 Eclipse가 알려주고 관련 코드도 자동 생성합니다.
--------------------------------------------------------------------
1. 예외가 발생되는 경우, 예외 처리 안한 경우
- cmd 창에서 '총점, 과목수' 2개의 정수를 입력받아 형변환하여 출력하세요.
[실행 화면]
/oop/bin>java oop2.Ex1 250 3
총점: 250
과목수: 3
평균: 83
/oop/bin>java oop2.Ex1 250 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at oop2.Ex1.main(Ex1.java:9)
▷ Ex1.java
-----------------------------------------------------------------------------------
package oop2;
public class Ex1 {
public static void main(String[] args) {
int tot = Integer.parseInt(args[0]);
int cnt = Integer.parseInt(args[1]);
int avg = tot / cnt;
System.out.println("총점: " + tot);
System.out.println("과목수: " + cnt);
System.out.println("평균: " + avg);
System.out.println("진행을 계속합니다.");
avg =avg + 10;
System.out.println("평균 추가 점수 부여: " + avg);
}
}
-----------------------------------------------------------------------------------
[과제] cnt 변수(분모)로 0이 입력되면 '0으로 나눌 수 없습니다.'를 출력하고
종료하는 프로그램을 작성하세요.
- 종료: System.exit(0);-----------------------------------------------------------------------------------package oop2;
public class Ex1 {
public static void main(String[] args) {
int tot = Integer.parseInt(args[0]);
int cnt = Integer.parseInt(args[1]);
if (cnt == 0){
System.out.println("0으로 나눌 수 없습니다.");
System.exit(0);
}
int avg = tot / cnt;
System.out.println("총점: " + tot);
System.out.println("과목수: " + cnt);
System.out.println("평균: " + avg);
System.out.println("진행을 계속합니다.");
avg =avg + 10;
System.out.println("평균 추가 점수 부여: " + avg);
}
}
-----------------------------------------------------------------------------------
2. 예외를 처리한 경우
- 예외가 발생해도 프로그램은 계속 실행됩니다.
[실행 화면]
/ws_java/oop2/bin>java oop2.Ex2 250 3
총점: 250
과목수: 3
평균: 83
진행을 계속 합니다.
평균 추가 점수 부여: 93
/ws_java/oop2/bin>java oop2.Ex2 250 0
java.lang.ArithmeticException: / by zero
at oop2.Ex2.main(Ex2.java:11)
진행을 계속 합니다.
평균 추가 점수 부여: 10
▷ Ex2.java
-----------------------------------------------------------------------------------
package oop2;
public class Ex2 {
public static void main(String[] args) {
int tot = 0;
int cnt = 0;
int avg = 0;
try {
tot = Integer.parseInt(args[0]);
cnt = Integer.parseInt(args[1]);
avg = tot / cnt;
System.out.println("총점: " + tot);
System.out.println("과목수: " + cnt);
System.out.println("평균: " + avg);
} catch (Exception e) {
String msg = e.toString();
System.out.println("예외 발생: " + msg);
} finally {
System.out.println("진행을 계속합니다.");
avg = avg + 10;
System.out.println("평균 추가 점수 부여: " + avg);
}
}
}
-----------------------------------------------------------------------------------
3. NullPointerException [중요]
- 객체를 생성하지않고 객체의 값이 null인 상태에서 메소드나 변수를 호출한 경우
NullPointerException이 발생합니다. (null: 메모리를 할당 받지 못한 상태, new가 실행 안됨)
이런 경우는 흔히 개발자의 판단 실수로 발생함으로 꼼꼼한 코드 테스트가 필요합니다.
- null: 메모리를 할당받지 못한 상태, 실행 불가능, 필드나 메소드를 호출 할 수
없습니다.
[실행 화면]
str: null <-- test1() method
Exception in thread "main" java.lang.NullPointerException
at oop2.ExceptionTest.test1(Ex3.java:7)
at oop2.Ex3.main(Ex3.java:26)str: null <-- test2() method
java.lang.NullPointerException
at oop2.ExceptionTest.test2(Ex3.java:14)
at oop2.Ex3.main(Ex3.java:29)
에러 원인 로그 파일에 기록됨
다음 코드 계속 실행str: null <-- test() method
예외 무시후 로직 계속 실행
▷ ExceptionTest.java
-----------------------------------------------------------------------------------package oop2;
public class ExceptionTest {
}
-----------------------------------------------------------------------------------
▷ Ex3.java -----------------------------------------------------------------------------------package oop2;
public class Ex3 {
public static void main(String[] args) {
ExceptionTest test = new ExceptionTest();
// test.test1();
// test.test2();
// test.test3();
}
}
-----------------------------------------------------------------------------------
package oop2;
public class ExceptionTest {
public void test1() {
String str = null; // 메모리에 변수명만 존재
System.out.println("str: " + str);
System.out.println("str.length(): " + str.length()); // java.lang.NullPointerException
}
public void test2() {
try {
String str = null; // 메모리에 변수명만 존재
System.out.println("str: " + str);
System.out.println("str.length(): " + str.length()); // java.lang.NullPointerException
} catch (Exception e) {
System.out.println("예외 발생 기록: " + e.toString());
}
System.out.println("시스템 정상 실행중...");
}
public void test3() {
try {
String str = null; // 메모리에 변수명만 존재
System.out.println("str: " + str);
System.out.println("str.length(): " + str.length()); // java.lang.NullPointerException
} catch (Exception e) {
//예외 관련 작업 없음, 무시
}
System.out.println("시스템 정상 실행중...");
}
}
-----------------------------------------------------------------------------------
4. throws 문의 사용
- 일반적으로 예외는 Class 내부에서 처리하나, 다른 클래스가 예외를 처리하도록
예외를 보내는 선언문
- throws는 예외를 현재 메소드에서 처리하지 않겠다는 의도로
try ~ catch를 사용할 필요가 없습니다.
- 메소드를 호출한 다른 클래스의 메소드가 예외를 처리하겠다는
의도를 명시적으로 선언한 것임.
[실행 화면]
▶ Ex4Use에서 예외 잡음.
java.lang.ArithmeticException: / by zero
at oop2.Ex4.calc(Ex4.java:6)
at oop2.Ex4Use.main(Ex4Use.java:10)
나머지 루틴 정상 실행
------------------------------------------------
▷ Ex4Use에서 예외 잡음.
java.lang.ArithmeticException: / by zero
at oop2.Ex4.calc2(Ex4.java:12)
at oop2.Ex4Use.main(Ex4Use.java:19)
나머지 루틴 정상 실행
------------------------------------------------
▷ Ex4.java
- new java.util.Date().toLocaleString()
. java.util 처럼 패키지를 클래스앞에 명시하면 import 선언이 필요 없습니다.
. 메소드를 한번만 호출한다면 객체 이름이 없는 무명 객체를 생성 할 수 있습니다.
-----------------------------------------------------------------------------------package oop2;
public class Ex4 {
public void calc(int tot, int cnt) {
int avg = tot / cnt;
System.out.println("avg: " + avg);
}
// 현재 메소드에서 예외를 처리하지않고,
// 예외 발생시 호출한 쪽으로 전달
public void calc2(int tot, int cnt) throws Exception {
int avg = tot / cnt;
System.out.println("avg: " + avg);
}
}
-----------------------------------------------------------------------------------
▷ Ex4Use.java
-----------------------------------------------------------------------------------package oop2;
public class Ex4Use {
public static void main(String[] args) {
Ex4 ex4 = new Ex4();
// ex4.calc(210, 0);
try {
// try 문에서 메소드를 호출하면 throws가 없어도
// 자동으로 예외가 전달되어 잡힘.
ex4.calc(210, 0);
} catch (Exception e) {
System.out.println("▶ Ex4Use에서 예외 잡음.");
e.printStackTrace();
}
System.out.println("나머지 루틴 정상 실행");
System.out.println("----------------------------------------------");
try {
ex4.calc2(230, 0);
} catch (Exception e) {
System.out.println("▷ Ex4Use에서 예외 잡음.");
e.printStackTrace();
}
System.out.println("나머지 루틴 정상 실행");
System.out.println("----------------------------------------------");
}
}
-----------------------------------------------------------------------------------
5. 시스템에 내장된 다양한 예외의 사용
[실행 화면]C:\ai3\ws_java\oop\bin>java oop2.Ex5
예외가 발생했습니다.
데이터 처리중입니다...
C:\ai3\ws_java\oop\bin>java oop2.Ex5 0
0으로 나눌 수 없습니다.
데이터 처리중입니다...
C:\ai3\ws_java\oop\bin>java oop2.Ex5 영
정수를 입력하세요. 예) 1 ~
데이터 처리중입니다...
C:\ai3\ws_java\oop\bin>java oop2.Ex5 3
객체가 생성되지 않았습니다.
데이터 처리중입니다...
▷ Ex5.java
-----------------------------------------------------------------------------------package oop2;
public class Ex5 {
public static void main(String[] args) {
try {
int year = Integer.parseInt(args[0]);
int avg = 2017 / year;
String str = null;
System.out.println(str.toLowerCase());
} catch (NumberFormatException e) {
System.out.println("정수를 입력하세요. 예) 1 ~ ");
} catch (ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다.");
} catch (NullPointerException e) {
System.out.println("객체가 생성되지 않았습니다.");
} catch (Exception e) {
System.out.println("예외가 발생했습니다.");
}
System.out.println("데이터 처리중입니다...");
}
}
-----------------------------------------------------------------------------------