예외 처리 (이론)
이번 글에서는 예외처리의 이론적 개념을 정리할 것이다:)
▶오류의 종류
에러(Error) | 예외(Exception) |
하드웨어의 잘못된 동작 또는 고장으로 인한 오류 | 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인한 오류 |
에러가 발생되면 프로그램 종료 | 예외가 발생되면 프로그램 종료 |
정상 실행 상태로 돌아갈 수 없음 | 예외처리 추가하면 정상 실행 상태로 돌아갈 수 있음 |
** 예외 ; 경험론적 코딩 기법
why? 미리 경험하여 겪어봐야 예외가 발생하는 것을 알고, 예외를 예상해서 써주는 것이기 때문.
** 예외처리를 추가한다 ; 예외가 발생했을때 그부분을 실행하지않도록 한다.
▶예외의 종류
- 일반(컴파일 체크) 예외 ; 예외 처리 코드 없으면 컴파일 오류 발생
- 실행 예외 (Runtime Exception) ; 예외 처리 코드를 생략하더라도 컴파일이 되는 예외, 경험에 따라 예외 처리 코드 작성 필요.
1. NullPointerException ; 객체 참조가 없는 상태
- null값 갖는 참조변수로 객체 접근 연산자인 도트(.) 사용했을 때 발생
String data = null;
System.out.println(data.toString());
//data에 값이 없는데 읽으려하는 것. 잘못 참조했다는 예외 발생!
2. ArrayIndexOutOfBoundsException ; 배열에서 인덱스 범위 초과하여 사용할 경우 예외 발생
public static void main(String[] args) {
String data1 = args[0];
String data2 = args[1];
System.out.println("args[0]:"+data1);
System.out.println("args[1]:"+data2);
}
//인덱스 범위가 얼만지 모르는데 접근하는 것. 예외 발생!
//입력 범위 미설정 에러
예외 처리를 ifelse로도 처리해줄 수 있다. if (args.length ==2)이면 실행하는 식으로.
if(args.length ==2) {
String data1 = args[0];
String data2 = args[1];
System.out.println("args[0]:" + data1);
System.out.println("args[1]:" + data2);
} else {
System.out.println("[실행 방법]");
System.out.print("java ArrayIndexOutOfBoundsExceptionExample ");
System.out.print("값1 값2");
}
3. NumberFormatException ;문자열 데이터를 숫자로 변경 시 문자가 포함돼있을 경우 예외 발생.
▶정수로 변경하는 방법
반환 타입 | 메소드명 (매개변수) |
Int | Integer.parseInt(String s) |
double | Double.parseDouble(String s) |
public static void main(String[] args) {
String data1 = "100";
String data2 = "a100";
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
int result = value1 + value2;
System.out.println(data1 + "+" + data2 + "=" + result);
}
//문자 a의 포함으로 숫자 data2로 변경 불가 에러.
4. ClassCastException ; 타입 변환이 되지 않을 경우 발생. (다운 캐스팅할 때 발생)
예제로 보면,
정상 코드
Animal ani = new Dog();
Dog dog = (Dog) ani;
RemoteControl rc = new Television();
Television tv = (Television) rc;
예외 발생 코드
Animal ani = new Dog();
Cat cat = (Cat) ani; //Animal로 업캐스팅된 개가 고양이로 다운캐스팅하려할 경우 발생
RemoteControl rc = new Television();
Audio audio = (Audio) rc;
예외 발생을 위해서 if문으로 방지할 수 있는데,
if (ani instanceof Dog) {
Dog dog = new ani;
}
if (rc instanceof Television) {
Television tv = new rc;
}
예외처리를 if문 -instanceof로 해줄 수 있다.
▶예외처리 전용 코드가 따로 있다. try - catch - finally 블록
(예외가 어느 반경에서 일어날 건지 예상해놓고 미리 설정해놓는게 try 범위이다.)
(1) 예외 던지기(catch)
try{
오류가 날 수도 있는 문장->오류가 안나면 catch()는 실행X
}catch(예외이름 객체명) {
오류 발생 시 실행할 문장
}
-if문으로 잡을 수 없는 걸 catch로 잡는 것.
(2) 하나의 문장에서 예외가 여러개 발생
try{
오류가 날 수도 있는 문장
}catch(예외이름1 객체명1) {
오류 발생 시 실행할 문장
}catch(예외이름2 객체명2) {
오류 발생 시 실행할 문장
}
(3) finally{} 추가
try{
오류가 날 수도 있는 문장
}catch(예외이름 객체명) {
오류 발생 시 실행할 문장
}finally{
예외발생 여부에 상관없이 무조건 실행할 문장
}
(4) 예외 OR
try{
오류가 날 수도 있는 문장
}catch(예외이름1 | 예외이름2 객체명) { //OR연산자
둘 중 하나라도 발생 시 실행할 문장
}
기초 예제
----------------------------------------------------------------------------------------
1. 예외 발생 코드
public class Try{
public static void main(String[] args) {
System.out.println(10/0);
System.out.println("종료");
}
}
Why? 나누기에서 분모는 0이 될 수 없으니까.
2. 예외 처리 코드
public class Try {
public static void main(String[] args) {
try {
System.out.println(10/0);
} catch (ArithmeticException e) { //예외 이름은 너무 다양해서 보통 Exception으로 두지만, 알면 예외이름으로 적기.
System.out.println("0으로 나눌 수 없습니다.");
}
System.out.println("종료");
}
}
▶객체 e로 예외를 받는 것.
▶예외가 발생하는 범위 이외의 문장이 실행되려면 예외를 잘 처리해줘야함.
이렇게 예외처리를 해주게되면 에러가 발생하지 않으면서, 어떤 오류가 발생한지도 알 수없다.
어떤 예외인지 알수있는 방법은?
.getMassage() ; 오류 이름 출력
.printStackTrace() ; 오류 내용 출력
기초 예제 2
----------------------------------------------------------------------------------------
1. 예외 발생 코드
public class Try2 {
public static void main(String[] args) {
int[] arData = new int[5];
for(int i=0;i<100;i++) {
arData[i]=i+1;
}
}
}
Why? 길이가 5인 배열에 인덱스 100까지 대입하려했기 때문.
2. 예외 처리 코드
public class Try2 {
public static void main(String[] args) {
int[] arData = new int[5];
for(int i=0;i<100;i++) {
System.out.println(i);
try {
arData[i] = i+1; //i=6일 때, 오류가 발생하면
}
} catch { //break안하면 95번 에러처리.
break; //이 문장 실행된 후,
}
System.out.println("정상 종료" //catch 밖 문장까지 실행됨.
}
}
5까지 돌아가고, try문에서 에러처리되는거니까 6번 반복된다는 점!
엘레베이터 예제
----------------------------------------------------------------------------------------
▶Lift 종류는 다양하니까 추상클래스 or 인터페이스로 생성해야 한다.
1. 추상클래스 Lift 코드
public abstract class Lift {
static final int floor = 0; //공유의 목적인 static
abstract void up();
abstract void down();
abstract void start(String choice);
absrtact void stop();
abstract void go();
}
Q. 왜 인터페이스가 아닌 추상클래스? 인터페이스의 상수는 외부에서 바꿀 수 없다. 추상클래스의 상수로 만들어야, 외부에서 층수를 랜덤으로 변경 가능하다.
2. 상속 클래스 Elevator 코드
public class Elevator extends Lift {
abstract void up() {
}
abstract void down() {
}
abstract void start(String choice) {
}
absrtact void stop() {
}
abstract void go() {
}
}
곧 다시 수정하러 오겠다