개발은 재밌어야 한다
article thumbnail
Published 2022. 2. 17. 01:03
[자바 JAVA] 예외의 종류 JAVA
반응형

자바에서 자주 발생하는 예외들과 예외에 대한 처리들에 대해서 정리 해 보도록 하겠습니다.

 

에러와 예외


컴퓨터 하드웨어의 동작의 오작동 또는 고장으로 인해 응용프로그램 실행 오류가 발생하는 것을 자바에서는 에러(error)라고 합니다.

에러는 JVM 실행에 문제가 있다는 것이므로 JVM 위에서 실행되는 프로그램을 아무리 견고하게 만들어도 결국 실행 불능 상태가 되어버립니다.

자바에서는 에러 이외에 예외(exception)이라고 부르는 오류가 있다. 예외란 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인해 발생하는 프로그램 오류를 말한다. 예외가 발생되면 프로그램은 곧바로 종료된다는 점에서 에러와 동일하다.

그러나 예외는 예외처리(Exception Handling)을 통해 프로그램을 종료하지 않고 정상 실행 상태가 유지될 수 있도록 할 수 있다.

 

예외에는 두가지 종류가 있다. 하나는 일반 예외(Exception)이고, 다른 하나는 실행 예외(Runtime Exception)이다.

 

일반 예외는 컴파일 체크 예외라고도 하는데, 자바 소스를 컴파일하는 과정에서 예외 처리 코드가 필요한지 검사하기 때문이다.

만약 예외 처리 코드가 없다면 컴파일 오류가 발생하게 된다.

 

실행예외는 컴파일하는 과정에서 예외 코드를 검사하지 않는 예외를 말한다. 컴파일 시 예외 처리를 확인하는 차이일 뿐, 두가지 예외 모두 예외 처리가 필요하다. 

 

자바에서는 예외를 클래스로 관리한다. JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성한다.그리고 나서 예외 처리 코드에서 예외 객체를 이용할 수 있도록 해준다.

 

모든 예외 클래스는 아래와 같이 java.lang.Exception 클래스를 상속받는다.

일반 예외와 실행 예외 클래스를 구별하는 방법은 일반 예외는 Exception을 상속받지만 RuntimeException을 상속받지 않는 클래스들입니다.

실행 예외는 다음과 같이 일반예외와 같이 Exception을 상속받지만 Exception을 상속받은  java.lang.RuntimeException의 상속받는 예외들을 실행 예외의 클래스들입니다.

 

 

 

자주 발생하는 실행 예외의 대표적인 케이스들을 알아 보겠습니다.


1. NullPointerException(NPE)

정말 정말 자주 출몰하는 에러입니다.널포인터익셉션이라고 부르기 길어서 줄여서 NPE라고도 부르기도 합니다.이 예러는 객체 참조가 없는 상태, 즉 null 값을 가지고 있는 참조 변수로 객체 접근 연산자인 도트(.)를 사용했을때 발생합니다.즉, 해당 객체가 null인 상태에서의 접근을 했을때 해당 값이 null에 대한 접근을 하여 발생하는 에러로 객체가 없는 상태에서 객체를 사용하려 하였으나 해당 객체는 없는 상태이기 때문에 발생하는 에러라고 볼 수 있습니다.

 

EX) 예시

public class NullPointerExceptionExample {
	public static void main(String[] args) {
    	String data = null;
        System.out.println(data.toString());
    }
 }

 

결과

data라는 변수에 null값을 세팅을 했기 때문에 출력부분에서 data.toString()을 통해 해당 객체의 toString()값을 출력하고 싶었으나 해당 객체는 null이기 때문에 null에는 toString()을 사용할 수 없기 때문에 NullPointerException 에러가 발생하는 것을 확인 할 수 있습니다.

 

 

2. ArrayIndexOutOfBoundsException

배열을 다룰때 주로 발생하는 예외인데요. 

배열에서 할당된 배열의 인덱스 범위를 초과해서 사용할 경우 발생하는 에러입니다.

예를 들어 길이가 3인 int[] arr = new int[3] 배열을 선언했다고 가정하면

arr[0]

arr[1]

arr[2]

해당 배열에서 사용할 수 있는 인덱스의 범위로는 위의 arr[0], arr[1], arr[2]만을 사용할 수 있는데, arr[3]이나 arr[4]등 해당 인덱스의 범위에 벗어나는 경우에는 ArrayIndexOutOfBoundsException가 발생합니다.

public class NullPointerExceptionExample {
	public static void main(String[] args) {
    	int[] arr = new int[3];
    	for (int i = 0; i <=3; i++) {
    		arr[i] = i;
    	}
    }
 }

위의 경우 i가 3까지 for문에 도달하기 때문에 for문의 마지막이 arr[3] = 3이 되는 데 할당된 배열의 인덱스를 넘기 때문에 ArrayIndexOutOfBoundsException 발생하는 것을 볼 수 있습니다.

 

 

public class ArrayIndexOutOfBoundsExceptionExample {
	public static void main(String[] args) {
    	int[] arr = new int[3];
    	int i = 0;
    	while(i <= 3)
    	{
	    	try {
	    		arr[i] = i;
	    		i++;
	    	} catch (ArrayIndexOutOfBoundsException e) {
	    		System.out.println("ArrayIndexOutOfBoundsException 에러 발생");
			}
    	}
    }
 }

해당 코드를 동작하면 어떻게 될까요?

계속해서 ArrayIndexOutOfBoundsException 가 발생이 되는 코드입니다.

그럼 배열에 할당만 하고 catch에서 에러가 발생했다고 하고 멈추는 방법은 어떻게 해야할까요?

b

catch부분에 break를 넣어 더이상 while이 돌지 않도록 하게 끔 하는 것입니다.

arr에는 arr[0], arr[1], arr[2]에 0,1,2까지 잘 들어갔고 catch에서 인덱스 오류가 났으니 이제 그만 하도록 break해서 해당 while문을 벗어나도록 예외를 처리하였습니다.

 

 

3. NumberFormatException

프로그램을 개발하다가 보면 문자열로 되어있는 데이터를 숫자로 변경하는 경우가 매우 자주 발생하곤 합니다.

문자열을 숫자로 변경하는 방법은 여러 가지가 있지만 가장 많이 사용되는 코드는 아래와 같습니다.

 

반환 타입 메소드명(매개변수) 설명
int Integer.parseInt(String s) 주어진 문자열을 정수로 변환해서 리턴
Doblue Double.parseDouble(String s) 주어진 문자열을 실수로 변환해서 리턴

이외에도 Float.parseFloat(String s)등과 같이 문자열을 특정 수로 변경할 수 있습니다.

Integer와 Doble은 포장(Wrapper) 클래스라고 하는데

여기서 Wrapper 클래스란 본 자료타입(primitive type)을 객체로 다루기 위해서 사용하는 클래스들을 래퍼 클래스(wrapper class)라고 합니다.

만약 parseXXX() 메소드들을 이용하여 문자열을 숫자로 변환할 수 있지만 매개변수로 오는 문자열이 숫자로 변환이 되는 값이면 숫자를 리턴하지만, 숫자로 변환될 수 없는 문자가 온다면 java.lang.NumberFormatException을 발생시키게 됩니다.

public class NumberFormatExceptionExample {
	public static void main(String[] args) {
    	String corretData = "100";  // 문자열 100은 숫자로 변환 할 수 있는 값이다.
    	String wrongData = "A100";  // 문자열 A100은 숫자로 변환 할 수 있는 값이다.
    	
    	int value1 = Integer.parseInt(corretData);
    	int value2 = Integer.parseInt(wrongData);
    	
    	System.out.println(value1);
    	System.out.println(value2);
    }
 }

correctData는 정상적으로 실행이 Integer로 변환이 가능하지만

String의 A100은 정상적인 숫자가 아니기 때문에 Integer값으로 변환할 수 없기 때문에 NumberFormatException이 발생하게 됩니다.

 

 

4. ClassCastException

타입 변환(Casting)은 상위 클래스와 하위 클래스간에 발생하고 구현 클래스와 인터페이스 간에도 발생한다.

이러한 관계가 아니라면 클래스는 다른 클래스를 타입으로 변환할 수 없다.

억지로 타입변환을 시도할 경우  ClassCastException이 발생한다. 

 

예제

public class ClassCastExceptionExample {
	static class Animal {}
	static class Dog extends Animal{}
	static class Cat extends Animal{}

	
	public static void main(String[] args) {
		// Dog 객체 생성
    	Dog dog = new Dog();
    	changeDog(dog);
    	
    	// Cat 객체 생성
    	Cat cat = new Cat();
    	changeDog(cat); 
    }
	public static void changeDog(Animal animal) {
		Dog dog = (Dog) animal; // ClassCastException 발생 가능
	}
}

changeDog에서 Cat에 대한 객체를 Dog 객체로 변환 하고자 할때 Dog 객체는 Dog객로 캐스팅하여 할당하는 것이 가능하지만 Cat 객체는 Cat객체로서 Dog객체로서 억지로 형변환을 시도할때 ClassCastException에러가 발생할 수 있습니다.

public class ClassCastExceptionExample {
	static class Animal {
		public void bark() {
			System.out.println("울음소리");
		}
	}
	static class Dog extends Animal {
		public void bark() {
			System.out.println("왈왈");
		}
	}
	static class Cat extends Animal {
		public void bark() {
			System.out.println("야옹");
		}
	}

	
	public static void main(String[] args) {
		// Dog 객체 생성
    	Dog dog = new Dog();
    	chageDog(dog);
    	
    	// Cat 객체 생성
    	Cat cat = new Cat();
    	chageDog(cat); 
    }
	public static void chageDog(Animal animal) {
		if (animal instanceof Dog) {
			Dog dog = (Dog) animal; 
			dog.bark();
		} else {
			Cat cat = (Cat) animal;
			cat.bark();
		}
	}
}

이렇게 Dog객체는 Dog객체에 해당 하는 객체를 Cat객체는 Cat객체에 맞게 처리하면 예외 처리를 할 수 있습니다.

 

 

 

 

 

 

 

 

반응형
profile

개발은 재밌어야 한다

@ghyeong

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!