Enum/예외처리

Jihye Gim·2026년 3월 12일

Codeit SB11

목록 보기
7/22

개인 학습자료

자바의 열거형에 대해 학습하기

1. enum 정의하는 방법

- Java에서 enum은 미리 정의된 값들의 집합을 나타내는 타입이다. 예를 들어, 요일, 상태, 사이즈, 나침반 등 고정된 값일 때 자주 사용한다.
- 열거 타입은 변수가 미리 정의된 상수 집합이 될 수 있도록 하는 특별한 데이터 타입이다.
- 변수는 미리 정의된 값 중 하나와 같아야 한다.
- 상수이기 때문에 열거 타입의 필드 이름은 대문자로 되어 있다.
- 고정된 상수 집합을 표현해야 할 때는 언제든 열거형 타입을 사용해야 한다.
- 기본문법
	```
	public enum enum이름 {
		상수1, 상수2, 상수3, ...
	}
	```
	예시 1) 요일을 enum으로 정의
		public enum Day {
			SUNDAY,
			MONDAY,
			TUESDAY,
			WEDNESDAY,
			THURSDAY,
			FRIDAY,
			SATURDAY
		}  
	예시 2) 상품 사이즈 정의
		public enum size {
			SMALL, MEDIUM, LARGE, XLARGE
		}
	enum 사용 예시)
		Size size = Size.MEDIUM;
			if (size == Size.MEDIUM) {
				System.ou.tprintln("중간 사이즈입니다.");
			}
** enum은 클래스와 비슷하게 사용할 수 있고, 각각 값들은 인스턴스(상수)로 취급한다.
** 필요하다면, 생성자나 필드, 메서드도 추가해서 쓸 수 있다.

	

2. enum이 제공하는 메서드(values()와 valueOf())

- values() 메서드
	- enum에 정의된 모든 상수들을 배열(Array) 형태로 반환한다.
	- enum 타입에 자동으로 추가되는 static 메서드
	- 반복문(for-each)등에서 모든 enum 값을 순회할 때 자주 사용한다.
	- enum 타입을 정의하면, Java 컴파일러가 자동으로 static 메서드로 추가해 준다.
	- 배열이 저장된 순서는 enum 선언 순서와 같다.
	- 주로 for-each문으로 반복할 때 사용한다.
public enum Size {
		}
		for (Size s : Size.values()) {
			System.out.println(s);
		}
	출력:
	SMALL
	MEDIUM
	LARGE
- valueOf(String name) 메서드
	- 매개변수로 전달된 문자열과 이름이 일치하는 enum 상수를 반환한다.
	- 문자열 값을 enum 타입으로 변환할 때 사용한다.(예:외부 입력을 enum으로 매핑할 때)
	- static 메서드이고, Java가 enum 타입마다 자동 생성해준다.
	- 대소문자를 정확히 맞춰서 입력해야 한다.
	- 일치하는 상수가 없으면, `IllegalArgumentException` 예외가 발생한다.

	 예시
	Size size = Size.valueOf("MEDIUM");
	System.out.println(size); //MEDIUM

** 만약 존재하지 않는 값을 넣으면 IllegalArgumentException이 발생한다.

3. java.lang.Enum

  • java.lang.Enum 은 모든 enum 타입이 상속하는 추상(generic) 클래스이다.
  • Java에서 enum을 정의하면, 내부적으로 해당 enum 클래스가 자동으로 Enum 클래스를 상속받게 된다.
public enum Size { SMALL, MEDIUM, LARGE }

이 코드는 컴파일 하게 되면,

public final class Size Extends Enum<Size> {...}

이렇게 처리된다.

  • enum을 위한 여러 유용한 메서드와 속성을 제공한다.
    - String name(): 상수의 이름(문자열)을 반환(예:"SMALL") - 선언 그대로의 이름
    - int rdinal(): enum 상수가 정의된 순서의 인덱스(0부터)를 반환 (첫번째 상수는 0)
    - int compareTo(E other): enum상수의 선언순서(ordinal)기준으로 비교
    - boolean equals(Object other) : 두 enum 상수가 같은지 비교
    - String toString(): 보통 name()과 같지만, 오버라이딩 가능
    - Class<E> getDeclaringClass(): enum 클래스 객체 반환
    - hashCode(): enum 상수 의 해시코드를 반환하는 메서드, 주로 Map의 Key로 쓸 때나, Set에서 중복 판단 등을 할 때 내부적으로 호출한다.
    - 모든 enum 상수마다 고유의 haschCode()값이 있다.
    - Enum의 hashCode()구현은 Object클래스의 것과 유사하지만, 엔진이 보다 최적화 해서 제공한다.
    - 같은 enum 상수는 항상 동일한 해시코드를 반환한다.
    - ```
    public enum Size {
    SMALL, MEDIUM, LARGE
    }
    Size s1 = Size.SMALL;
    System.out.println(s1.hascode()); // 예: 503948392
    System.out.println(Size.SMALL.hashCode() == s1.hashCode()); //true
    		  ```
  • Java에서 모든 enum타입이 암묵적으로 상속하는 generic(추상) 클래스로, enum 타입의 타입 안정성을 높여준다.
  • enum을 만들면 실제로는 Enum 클래스를 상속받는 final class로 만들어진다.
  • 직접 상속하거나, 다른 클래스를 상속할 수 없다.
  • Java에서 enum은 반드시 java.lang.Enum만 상속할 수 있다.
  • 불변(immutable) 특성을 가진다.
  • enum 상수는 단 하나만 생성된다.(싱글턴)
  • enum은 java.lang.Enum만 상속 가능. 다른 클래스를 동시에 상속할 수 없다.
  • 그러나 인터페이스 구현(implement)할수 있다.
    - ```
    public interface Infoable {}
    public enum State implements Inforable { ON, OFF }
    	  ```
  • 예시
public enum Size {
	SMALL, MEDIUM, LARGE
}
Size s = Size.MEDIUM;

System.out.println(s.name());            // "MEDIUM"
System.out.println(s.ordinal());            // 1
System.out.println(s.toString());            // "MEDIUM"
System.out.println(s.getDeclaringClass());            // class Size
  • 상속 구조 예시(GeoCode)
java.lang.Object
 ->java.lang.Enum<GeoCode>
	 -> GeoCode

values(), valueOf() 등은 실제로 enum 타입을 정의할 때 컴파일러가 enum마다 자동으로 추가해주는 static 메서드다. 반면, java.lang.Enum의 메서드는 모두 각 enum 상수 인스턴스가 사용할 수 있는 인스턴스 메서드다.

예시코드:

public enum Size {
	SMALL, MEDIUM, LARGE	
}
Size s = Size.MEDIUM;

// Enum에서 상속된 메서드를 사용
System.out.println(s.name());     // "MEDIUM"
System.out.println(s.ordinal());  // 1
System.out.println(s.toString()); // "MEDIUM"
System.out.println(s.compareTo(Size.SMALL)); // 1

// enum에 자동 추가된 static 메서드를 사용
Size[] arr = Size.values();
Size fromStr = Size.valueOf("LARGE");

4.EnumSet

  • enum 상수들만 담을 수 있는 Set 컬렉션 클래스
  • 내부적으로 비트 플래그(비트 연산)를 사용해서, 매우 빠르고 메모리 효율적으로 다수의 enum값을 관리한다.
  • java.util.EnumSet 패키지에 있다.
  • null값을 허용하지 않는다. (null을 넣으면 NPE(NullPointerException발생)
public enum Day { MON, TUE }
EnumSet<DAY> set = EnumSet.noneOf(Day.class);
//null을 넣으려고 하면,
set.add(null); // 여기서 NullPointerException이 발생.
  • enum 타입을 위한 전용 Set: 오직 하나의 enum 타입만 저장 가능하다.
  • 빠른 속도: 일반적인 HashSet보다 훨씬 빠르게 동작한다.
  • 적은 메모리: 내부적으로 비트 연산으로 구현되어 있으므로, enum 상수가 수십~ 수백 개인 경우에도 효과적이다.
  • EnumSet은 생성자가 없고, 정적 메서드로 생성해야 한다.
public enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

// 모든 값
EnumSet<DAY> allDays = EnumSet.allOf(Day.class);

// 일부 값만
EnumSet<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);

// 비어있는 EnumSet
EnumSet<Day> empty = EnumSet.noneOf(Day.class);

사용 예시:

EnumSet<Day> workingDays = EnumSet.range(Day.MON, Day.FRI);
for (Day d : workingDays) {
	System.out.println(d);
}
//MON TUE WED THU FRI
  • add, remove, contains, size 등 Set에서 쓰는 기능 모두 지원한다.
    enum 상수의 집합을 표현하는 데 가장 효율적
    실행 속도와 메모리 차원에서 `HashSet 사용보다 훨씬 좋음
    ** 타입 안정성 보장(enum외에는 못 넣음)

<<첨부> : 열거 유형 (자바™ 튜토리얼 > Java 언어 학습 >클래스와 객체)
Enum (Java SE 17 & JDK 17)
enum in Java - GeeksforGeeks >


자바의 예외 처리(Exception Handling)에 대해 학습하기

1. 자바에서 예외 처리 방법(try, catch, throw, throws, finally)

  • 예외(Exception)란?
    - 프로그램 실행 중에 발생할 수 있는 에러 상황을 자바에서는 "예외(예외 상황, Exception)"라고 한다.
    - 예시: 0으로 나누기, 없는 파일 열기, 배열 범위 초과 접근 등
  • 예외 처리 방법
    - try-catch-finally 구문을 사용해서 예외를 처리한다.
// 기본구조
try {
	// 예외가 발생 할 수 있는 코드
} catch (예외타입 변수명) {
	// 예외가 발생했을 때 실행할 코드
} finally {
	// (선택) 항상 실행할 코드 (예외 발생 여부와 무관)
}	

예시:

try {
	int result = 10 / 0; // 여기가 예외 발색(ArithmeticException)
	System.out.println(result); // 실행되지 않음
} catch (ArithmeticException e) {
	System.out.println("0으로 나눌 수 없습니다.");
} finally {
	System.out.println("프로그램 종료");
}
//result
0으로 나눌 수 없습니다.
프로그램 종료
  • 여러 개의 catch문
    여러 종류의 예외를 구분해서 처리할 수 있다.
try {
	// 예외 발생 가능 코드
} catch (ArithmeticException e) {
	// 산술 예외 처리
} catch (NullPointerException e) {
	// Null Pointer 예외 처리
} catch (Exception e) {
	// 그 외의 모든 예외 처리(항상 마지막에 위치)
}
  • finally 블록은 예외 발생과 관계없이 항상 실행된다. 보통 파일 닫기, 소켓 종료 등 "정리 작업"에 사용한다.
  • 예외 던지기(throw, throws)
    - 직접 예외 발생시키기
    	```
    	throw new IllegalArgumentException("잘못된 인자입니다.");
    	```
    	- 메서드에서 예외를 미루기(throws)
    	```
    	public void readFile() throws IOException (
    		// 파일을 읽는 코드
    	)
    	```
    	이 경우, 호출한 쪽에서 try-catch로 책임지고 처리해야 한다.
  • 예외의 종류
    1. Checked 예외(커파일러가 체크)
    - 컴파일 시점에 반드시 처리해야 하는 예외
    - 예: IOException, SQLException 등
    - 처리 안하면 컴파일 에러!
    2. Unchecked 예외(컴파일러가 체크하지 않음)
    - 실행 중에 발생, 처리 강제X
    - 예: NullPointerException, ArithmeticException 등
    ** 예외는 꼭 필요한 곳에만 처리, 특정 예외만 캐치하는 습관, finally로 자원 정리 잊지 않기.

2. 자바가 제공하는 예외 계층 구조

예외 계층 구조의 최상위 : Trhowable

- 예외와 오류를 모두 포함하는 최상위 클래스.
- Java에서 catch될 수 있는 것은 모두 이 클래스를 상속한다.
```
java.lang.Object
	└─ java.lang.Throwable
```

Throwable의 하위: Error and Exception

Exception의 하위: Checked vs Unchecked

1) Checked Exception (컴파일러가 체크)

  • 반드시 try-catch로 처리하거나, throws로 던져서 위쪽에서 처리해야 한다.
  • 컴파일 단계에서 에러로 강제
  • IOException (입출력 오류)
  • SQLException (DB관련)
  • ClassNotFoundException
  • FileNotFoundException
    2) Unchecked Exception(RuntimeException)
  • 컴파일러가 예외 처리 강제 X
  • 대부분 프로그래밍 로직 실수에서 발생(런타임 예외)
  • 필요에 따라 처리할 수 있지만 강제 X
  • NullPointerException
  • ArrayIndexOutOfBoundsException
  • IllegalArgumentException
  • ArithmeticException
  • ClassCastException

3. Exception과 Error의 차이는?

Throwable의 하위: Exception vs Error
1) Exception
- 일반적인 예외 상황(입출력, 네트워크, 잘못된 로직 등)
- 직접처리(catch)하거나, throws로 전파

2) Error
- (심각한)시스템 오류나 JVM의 치명적 문제(메모리 부족 등)
- 개발자가 직접 처리하거나 catch해서 복구하지 않음
- OutOfMemoryError
- StackOverflowError
- VirtualMachineError

Throwable 
	├─ Error 
	└─ Exception

4. RuntimeException과 RE가 아닌 것의 차이는?

  • RuntimeException(런타임 예외)와 그렇지 않은 예외(즉 Checked Exception)의 가장 큰 차이는 컴파일러가 "예외 처리를 강제하는가"에 있다.
    1. RuntimeException(런타임 예외)
    - RuntimeException과 그 하위 예외들을 Unchecked Exception(언체크드 예외) 라고 부른다.
    - 실행(Runtime) 중에 발생하는 프로그래밍 로직상의 오류가 대표적이다.
    - 컴파일러가 try-catch나 throws 처리를 "강제하지 않음"
    - 예외 처리를 해도 되고, 안해도 됨(코드가 깨끗하게 컴파일 됨)
    - 주로 프로그래머 실수, 로직 오류 등 코드 내부에서 어쩔 수 없이 발생하는 예외
    - 프로그램의 논리 오류이므로, 코드 상에서 미리 방지하거나 빠르게 고쳐야 할 대상이다.
    2. Checked Exception(Checked 예외, RuntimeException이 아닌 Exception)
    - Exception 클래스 중, RuntimeException을 직접/간접적으로 상속하지 않은 예외
    - 대표적으로 I/O, 네트워크, DB 등 외부 환경 요인에서 주로 발생한다.
    - 컴파일러가 예외 처리(try-catch 또는 throws 선언)를 반드시 요구
    - 해당 예외를 처리하지 않으면 컴파일 조차 되지 않음.
    - 예외를 무조건 인지하고 대응책을 코드에서 마련해야 한다.
    예시코드
// RuntimeException - try-catch 없이 가능
public static void main(String[] args) {
	int[] arr = new int[3];
	System.out.println(arr[5]); //ArrayIndexOutBoundsExcepton, 컴파일OK, 실행중 에러!
}
// checked Exception - 반드시 처리 필요
public static void main(String[] args) {
	FileReader fr = new FileReader("test.txt"); // 컴파일 에러! 예외 처리 요구
}
// -> 다음처럼 처리해야 컴파일 OK
public static void main(String[] args) throws FileNotFoundException {
	FileReader fr = new FileReader("test.txt");
}
// 또는
try {
	FileReader fr = new FileReader("test.txt");
} catch (FileNotFoundException e) {
	// 예외 처리 코드
}

5. 커스텀한 예외 만드는 방법

  • 커스텀 예외를 만들어야 하는 경우는, 자바 기본 예외만으로 상황을 명확하게 표현하기 어려울때, 서비스나 도메인에 특화된 에러 상황을 정확히 구분, 전달하고 싶을 때, 직접 예외 클래스를 만들어 사용할수 있다.
  • Checked Exception을 만들려면 Exception을 상속받고,
  • Unchecked Exception(RuntimeException계열)은 RuntimeException을 상속받는다.
    기본예시
    (1) Checked Exception(컴파일 강제되는 예외)
public class MyCheckedException extends Exception {
	public MyCheckedException() {
		super();
	}
	public MyCheckedException(String message) {
		super();
	}
}     // 반드시 try-catch나 throws로 처리해야 컴파일 OK

(2) Unchecked Exception(컴파일이 강제되지 않는 예외)

public class MyUncheckedException extends RuntimeException {
	public MyUncheckedException() {
		super();
	}
	public MyUncheckedException(String message) {
		super(message);
	}
}

예외처리를 강제하지 않음, 필요에 따라 try-catch/throws
대부분 실무에서는 RuntimeException 상속 예외를 더 많이 쓴다고 한다.

  • 생성자 패턴 사용 형태
    public class MyException extends Exception {
    		  public MyException() { super(); }
    		  public MyException(String message) { super(message); }
    		  public MyException(String message, Throwable cause) { super(message, cause); }
    		  public MyException(Throwable cause) { super(cause); }
    }
  • 예외 발생 과 사용방법
    // 예외 발생시키기
    throw new MyCheckedException("사용자 정의 체크 예외!");
    
    // 또는
    throw new MyUncheckedException("사용자 정의 런타임 예외!");
    
    예외 처리 예시:
    try {
    	  throw new MyCheckedException("강제 예외 발생");
    } catch (MyCheckedException e) {
    	e.printStackTrace();
    }
  • 패키지나 도메인별로 이름을 분명하게(예:UserNotFoundExxception, InvalidOrderException)
  • 메시지, 발생 원인(cause)전달 가능하도록 생성자 활용!
  • Unchecked(Exception을 상속, RuntimeException을 상속) 선택은 예외 상황의 성격에 맞게.

<참고: Creating Exception Classes (The Java™ Tutorials > Essential Java Classes > Exceptions)>

profile
Rookie

0개의 댓글