반응형
참고자료
개요
이번에는 Java의 예외처리에 대해서 알아보도록 하겠습니다.
설명
프로그래밍을 하다 보면 프로그램에 오류가 나올 경우가 많이 있습니다.
그 오류는 크게 에러와 예외로 나뉘게 됩니다.
에러(error) 의 특징
- 개발자가 해결할 수 없는 치명적인 오류.
- 하드웨어의 잘못된 동작 또는 고장으로 인한 오류.
- 에러가 발생되면 프로그램 종료.
- 정상 실행 상태로 돌아갈 수 없음.
예외(exception)의 특징
- 개발자가 해결할 수 있는 오류
- 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인한 오류
- 예외가 발생되면 프로그램을 종료.
- 예외 처리 추가하면 정상 실행 상태로 돌아갈 수 있음,
- 예외가 발생하면 비정상적인 종료를 막고, 프로그램을 계속 진행할 수 있도록 우회 경로를 제공.
예외는 또한 크게 일반 예외와 실행 예외로 나뉩니다.
일반 (컴파일 체크) 예외의 특징
- 컴파일러는 발샐할 가능성을 발견하면 컴파일 오류를 발생.
- 개발자는 예외 처리 코드를 반드시 추가.
대표적인 일반 예외 ex)
일반 예외 | 발생 이유 |
ClassNotFoundException | 존재하지 않는 클래스를 사용하려고 할 때 발생. |
InterruptedException | 인터럽트되었을 때 발생. |
NoSuchFieldException | 클래스가 명시한 필드를 포함하지 않을 때 발생. |
NoSuchMethodException | 클래스가 명시한 메서드를 포함하지 않을 때 발생 |
IOException | 데이터 읽기 같은 입출력 문제가 있을 때 발생 |
실행 예외(RuntimeException) 의 특징
- 예외가 발생하면 JVM은 해당하는 실행 예외 객체를 생성
- 실행 예외는 컴파일러가 예외 처리 여부를 확인하지 않음. 따라서 개발자가 예외 처리 코드의 추가 여부를 결정.
대표적인 실행 예외
실행 에외 | 발생 이유 |
ArithmeticException | 0으로 나누기와 같은 부적절한 산술 연산을 수행할 때 발생. |
IllegalArgumentException | 메서드에 부적절한 인수를 전달할 때 발생. |
IndexOutOfBoundsException | 배열, 벡터 등에서 범위를 벗어난 인덱스를 사용할 때 발생. |
NoSuchElementException | 요구한 원소가 없을 때 발생. |
NullPointerException | null 값을 가진 참조 변수에 접근할 때 발생. |
NumberFormatException | 숫자로 바꿀 수 없는 문자열을 숫자로 변환하려 할 때 발생. |
이렇게 발생한 예외를 처리하는데에는 두 가지의 방법이 있습니다.
1. 예외를 잡아서 처리한다. try ~ catch 문
2. 예외를 떠넘긴다. throws 문
try-catch-finally 문
예외 발생시 프로그램 종료를 막고, 정상 실행 유지할 수 있도록 처리
일반 예외 : 반드시 작성해야 컴파일 가능.
실행 예외 : 컴파일러가 체크해주지 않으며 개발자 경험에 의해 작성
(정상 실행되었을 경우)
try {
// 예외 발생 가능 코드
} catch(Exception e) {
// 예외처리 실행되지 않음
} finally {
// 항상 실행
}
(예외가 발생 되었을 경우)
try {
//예외발생 이 밑으로 실행안됨
} catch(Exception e) {
// 여기가 실행됨
} finally {
// 항상 실행
}
다중 catch 문
여기선 catch의 순서가 중요합니다.
try {
// 1. ArrayIndexOutOfBoundsException 예외1 발생
// 2. NumberFormatException 예외2 발생
} catch(ArrayIndexOutOfBoundsException e) {
// 예외 처리 1 실행
} catch(NumberFormatException e) {
// 예외 처리 2 실행
}
throws : 예외 떠 넘기기
메서드에서 처리하지 않은 예외를 호출한 곳으로 넘김.
public void method1() {
try {
method2();
} catch(ClassNotFoundException e) {
// 예외 처리 코드
System.out.println("클래스가 존재하지 않습니다.");
}
}
public void method2() throws ClassNotFoundException { // 5번출에서 호출했으므로 예외를 처리
Class clazz = Class.forName("java.lang.String2");
}
오류내용을 직접 처리하는 방법에 대해서 알아보겠습니다.
public class Ex_01 {
public static void main(String[] args) {
int a = 100, b=0;
int result;
try {
if(b==0)
throw new Exception("0으로 나눌수 없습니다"); // 나누는 값 b가 0이면 8행을
// 실행하기 전에 오류가 발생한다.
result = a/b;
}catch (Exception e) { // 예외 타입을 Exception으로 변경한다.
System.out.print("발생 오류 =>");
System.out.println(e.getMessage());
}
}
}
그렇다면 저번 추상 클래스를 알아보면서 만든 게임을 수정해보도록 하겠습니다.
(Food.java)
벽을 만났을때 예외를 발생시켜 처리하도록 하였으며, 움직임을 랜덤 하게 움직이도록 하였습니다.
package java_2020_11_11;
public class Food extends GameObject {
public Food(int x, int y, int distance) {
super(x, y, distance);
}
@Override
public void move() { // 한 번 움직이는 과정 전개
int n = (int)(Math.random()*5); // 0,1,2,3,4 중에서 0인 경우 + 방향, 1인 경우 - 방향, 나머지 정지
if(n==0) x += distance;
else if(n==1) x -= distance;
try {
if(x < 0) throw new Exception("Food 이동 범위 이탈 Hold ");
}catch (Exception e) {
x=0;
System.out.println(e.getMessage());
}
try {
if(x >= Game.MAX_X) throw new Exception("Food 이동 범위 이탈 Hold ");
}catch (Exception e) {
x = Game.MAX_X - 1;
System.out.println(e.getMessage());
}
n = (int)(Math.random()*5);
if(n==0) y += distance;
else if(n==1) y -= distance;
try {
if(y < 0)throw new Exception("Food 이동 범위 이탈 Hold ");
}catch (Exception e) {
y=0;
System.out.println(e.getMessage());
}
try{
if(y >= Game.MAX_Y)throw new Exception("Food 이동 범위 이탈 Hold ");
}catch (Exception e) {
y= Game.MAX_Y - 1;
System.out.println(e.getMessage());
}
}
@Override
public char getShape() { // Fish의 모양 리턴
return 'F';
}
}
(Host.java)
마찬가지로 움직일때 벽을 만나면 정지시켜 놓고 예외를 발생시켜 처리하였습니다.
package java_2020_11_11;
import java.util.Scanner;
public class Host extends GameObject {
private Scanner scanner;
public Host(int x, int y, int distance) {
super(x, y, distance);
scanner = new Scanner(System.in);
}
@Override
public void move() {
System.out.print("왼쪽(a), 아래(s), 위(w), 오른쪽(d) >> ");
char c;
c = scanner.next().charAt(0);
try {
switch (c) {
case 'a': // left
x--;
if (x < 0) { // 예외처리를 만든다.
x = 0;
throw new Exception("왼쪽 으로 이동 범위를 초과하였습니다.\n다시 입력해주세요.");
}
break;
case 'd': // right
x++;
if (x >= Game.MAX_X) {
x = Game.MAX_X - 1;
throw new Exception("오른쪽 으로 이동 범위를 초과하였습니다.\n 다시 입력해주세요.");
}
break;
case 'w': // up
y--;
if (y < 0) {
y = 0;
throw new Exception("위쪽 으로 이동 범위를 초과하였습니다.\n 다시 입력해주세요.");
}
break;
case 's': // down
y++;
if (y >= Game.MAX_Y) {
y = Game.MAX_Y - 1;
throw new Exception("아래쪽 으로 이동 범위를 초과하였습니다.\n 다시 입력해주세요.");
}
break;
}
} catch (Exception e) {
System.out.print("발생 오류 => ");
System.out.println(e.getMessage());
}
}
@Override
public char getShape() { // Bear의 모양 리턴
return 'H';
}
}
(Monster.java)
장에물을 만나면 예외를 발생시키도록 하였으며 catch문에서 다중 if문을 사용하여 움직임을 어느 정도 랜덤 하게 하도록 하였습니다.
package java_2020_11_11;
public class Monster extends GameObject {
public Monster(int x,int y, int distance) {
super(x,y,distance);
}
@Override
protected void move() {
int n = (int)(Math.random()*3); // 0,1 중에서 0이면 + 1이면 - 2이면 안움직임
if(n==0) x+=distance;
else if(n==1) x-=distance;
try {
if(x<0) throw new Exception("가로길이 막혀 세로중 랜덤으로 이동");
}catch (Exception e) {
int s = (int)(Math.random()*2); // 위 , 아래 어디로 움직일지 랜덤으로 정한다.
x=0;
if(y!=0) { // 위 와 아래의 길이 막히지 않았다면 이동
if(y!=Game.MAX_Y) {
if(s==0) y++;
else if(s==0) y--;
}
}
System.out.print("발생 오류=> ");
System.out.println(e.getMessage());
}
try {
if(x>=Game.MAX_X) throw new Exception("가로길이 막혀 세로중 랜덤으로 이동");
}catch (Exception e) {
x=Game.MAX_X-1;
int s = (int)(Math.random()*2);
if(y!=0){
if(y!=Game.MAX_Y) {
if(s==0) y++;
else if(s==0) y--;
}
}
System.out.print("발생 오류=> ");
System.out.println(e.getMessage());
}
n = (int)(Math.random()*3);
if(n==0) y+=distance;
else if(n==1) y-=distance;
try {
if(y<0) throw new Exception("세로 길이 막혀 가로중 랜덤으로 이동");
}catch (Exception e) {
int s =(int)(Math.random()*2);
y=0;
if(x!=0) {
if(x!=Game.MAX_X) {
if(s==0) x++;
else if(s==1) x--;
}
}
System.out.println("발생 오류=> ");
System.out.println(e.getMessage());
}
try {
if(y>=Game.MAX_Y) throw new Exception("세로 길이 막혀 가로중 랜덤으로 이동");
}catch (Exception e) {
int s =(int)(Math.random()*2);
y=Game.MAX_Y-1;
if(x!=0) {
if(x!=Game.MAX_X) {
if(s==0) x++;
else if(s==1) x--;
}
}
System.out.println("발생 오류=> ");
System.out.println(e.getMessage());
}
}
@Override
protected char getShape() {
// TODO Auto-generated method stub
return '$';
}
}
(GameObject.java)
package java_2020_11_11;
public abstract class GameObject { // 추상 클래스
protected int distance; // 한 번 이동 거리
protected int x, y; // 현재 위치(화면 맵 상의 위치)
public GameObject(int startX, int startY, int distance) { // 초기 위치와 이동 거리 설정
this.x = startX; this.y = startY;
this.distance = distance;
}
public int getX() { return x; }
public int getY() { return y; }
public boolean collide(GameObject p) { // 이 객체가 객체 p와 충돌했으면 true 리턴
if(this.x == p.getX() && this.y == p.getY())
return true;
else
return false;
}
protected abstract void move(); // 이동한 후의 새로운 위치로 x, y 변경
protected abstract char getShape(); // 객체의 모양을 나타내는 문자 리턴
}
(Game.java)
package java_2020_11_11;
public class Game {
public static final int MAX_X = 20;
public static final int MAX_Y = 10;
private char map [][] = new char [MAX_Y][MAX_X];
private GameObject [] m = new GameObject[3];
int state; // 0: 게임 중, 1: Monster가 winner, 2:Human이 winner
public Game() {
for(int i=0; i<MAX_Y; i++)
for(int j=0; j<MAX_X; j++)
map[i][j] = '-';
m[0] = new Host(0, 0, 1);
m[1] = new Food(0, 1, 2);
m[2] = new Monster(5,4,2);
state = 0; // 게임 중
}
public void run() {
System.out.println("** Host의 Food 먹기 게임을 시작합니다.**");;
update(); // 초기 좌표에 따른 맵 설정
draw(); // 초기 게임 맵을 보여줌
while(!doesEnd()) {
clear(); // 현재의 맵 지움
for(int i=0; i<m.length; i++) {
m[i].move();
}
show();
update(); // 움직인 후 좌표 변경에 따른 맵 갱신
draw(); // 맵 그리기
}
}
private void show() {
for(int i=0;i<26;i++) {
System.out.println();
}
}
private void update() {
for(int i=m.length-1; i>=0; i--) // Food부터 먼저 그려서 Food를 먹는 경우 Food가 보이지 않기
map[m[i].getY()][m[i].getX()] = m[i].getShape();
}
private void clear() {
for(int i=0; i<m.length; i++)
map[m[i].getY()][m[i].getX()] = '-';
}
private void draw() {
System.out.println();
for(int i=0; i<MAX_Y; i++) {
for(int j=0; j<MAX_X; j++)
System.out.print(map[i][j]);
System.out.println();
}
}
private boolean doesEnd() {
try {
if(m[0].collide(m[1])) {// Host ate Food
System.out.println("Host Wins!!");
return true;
}
else if(m[0].collide(m[2])) {// Monster ate Host
System.out.println("Monster Wins!!");
return true;
}
else if(m[2].collide(m[1])) {// Monster 와 Food의 충돌
throw new Exception("Monster Food crush 발생!");
}
}catch (Exception e) {
int n = (int)(Math.random()*4); // 0 오른쪽 /1 왼쪽 /2 위쪽 /3 아래쪽
if(n==0) {
System.out.println(e.getMessage());
if(m[1].getX()==0) { // 왼쪽 끝에서 충돌이 일어난다면
m[1].x+=1; // 오른쪽으로 한칸 이동한다.
}
else if(m[1].getX()==Game.MAX_X) { // 오른쪽 끝에서 충돌이 일어나면
m[1].x-=1; // 왼쪽으로 한칸 이동한다.
}
else if(m[1].getY()==0) { // 맨 위에 줄에서 충돌이 발생한다면
m[1].y+=1; // 아래로 한칸 이동한다.
}
else if(m[1].getY()==Game.MAX_Y) { // 맨 아래 줄에서 충돌이 발생한다면
m[1].y-=1; // 위로 한칸 이동한다.
}else {
m[1].x++; // 벽에 막히지 않았으면 오른쪽 이동
}
}
else if(n==1) {
System.out.println(e.getMessage());
if(m[1].getX()==0) { // 왼쪽 끝에서 충돌이 일어난다면
m[1].x+=1; // 오른쪽으로 한칸 이동한다.
}
else if(m[1].getX()==Game.MAX_X) { // 오른쪽 끝에서 충돌이 일어나면
m[1].x-=1; // 왼쪽으로 한칸 이동한다.
}
else if(m[1].getY()==0) { // 맨 위에 줄에서 충돌이 발생한다면
m[1].y+=1; // 아래로 한칸 이동한다.
}
else if(m[1].getY()==Game.MAX_Y) { // 맨 아래 줄에서 충돌이 발생한다면
m[1].y-=1; // 위로 한칸 이동한다.
}
else {
m[1].x--; // 벽에 막히지 않았으면 왼쪽 이동
}
}
else if(n==2) {
System.out.println(e.getMessage());
if(m[1].getX()==0) { // 왼쪽 끝에서 충돌이 일어난다면
m[1].x+=1; // 오른쪽으로 한칸 이동한다.
}
else if(m[1].getX()==Game.MAX_X) { // 오른쪽 끝에서 충돌이 일어나면
m[1].x-=1; // 왼쪽으로 한칸 이동한다.
}
else if(m[1].getY()==0) { // 맨 위에 줄에서 충돌이 발생한다면
m[1].y+=1; // 아래로 한칸 이동한다.
}
else if(m[1].getY()==Game.MAX_Y) { // 맨 아래 줄에서 충돌이 발생한다면
m[1].y-=1; // 위로 한칸 이동한다.
}
else {
m[1].y++; // 벽에 막히지 않았으면 아래로 이동
}
}
else if(n==3) {
System.out.println(e.getMessage());
if(m[1].getX()==0) { // 왼쪽 끝에서 충돌이 일어난다면
m[1].x+=1; // 오른쪽으로 한칸 이동한다.
}
else if(m[1].getX()==Game.MAX_X) { // 오른쪽 끝에서 충돌이 일어나면
m[1].x-=1; // 왼쪽으로 한칸 이동한다.
}
else if(m[1].getY()==0) { // 맨 위에 줄에서 충돌이 발생한다면
m[1].y+=1; // 아래로 한칸 이동한다.
}
else if(m[1].getY()==Game.MAX_Y) { // 맨 아래 줄에서 충돌이 발생한다면
m[1].y-=1; // 위로 한칸 이동한다.
}
else {
m[1].y--; // 벽에 막히지 않았으면 위쪽으로 이동
}
}
show();
update();
draw();
return false;
}
return false;
}
public static void main(String[] args) {
Game game = new Game();
game.run();
}
}
반응형
'웹프로그래밍 > Java' 카테고리의 다른 글
Java 제네릭과 컬렉션 , Vector, ArrayList <E>, HashMap <K,V> 을 이용한 사전 (0) | 2021.03.24 |
---|---|
Java 추상클래스를 이용하여 간단한 게임 만들기(1) (0) | 2020.11.16 |