부트캠프

Java 열거형, 제네릭, 예외 처리

hunm719 2023. 1. 4. 22:09

1.열거형(enum; enumerated type) : 상수들을 보다 간편하게 관리할 때 유용하게 사용할 수 있는 자바의 문법 요소
 *상수는 변하지 않는 값을 의미, final 키워드로 선언

열거형에서 사용할 수 있는 메서드

 -상수명의 중복을 피하고, 타입에 대한 안전성을 보장
 -같은 효과의 다른 코드에 반해 훨씬 간결하고 가독성이 좋음
 -switch문에서도 작동이 가능(사용자 정의 타입은 switch문 사용시 에러발생)
  *switch문의 조건은 char, byte, short, int, Character, Byte, Short, Integer, String, enum 타입

 아래와 같은 예시로 사용
 enum 열거형이름 { 상수명1, 상수명2, 상수명3, ...}

 +상수명은 관례적으로 대문자로 작성
 +각각의 상수들에는 자동적으로 0부터 시작하는 정수값이 할당됨


2.제네릭(Generic) : 클래스나 메서드의 코드를 작성할 때, 타입을 구체적으로 지정하는 것이 아니라, 추후에 지정할 수 있도록 일반화해두는 것

2-1.제네릭 클래스 : 제네릭이 사용된 클래스

 (1)일반적으로 아래와 같은 예시로 사용
 class 클래스_명<T>

 -위의 예시에서 T를 타입(Type) 매개변수라고 하며, <>와 같이 꺽쇠 안에 넣어 클래스 이름 옆에 작성해줌으로써 클래스 내부에서 사용할 타입 매개변수를 선언할 수 있음.
 -타입 매개 변수 T를 선언하면, 클래스 몸체에서 T를 임의의 타입으로 사용할 수 있음.

 (2)타입 매개변수를 여러 개 사용할 경우, 아래와 같은 예시로 선언
 class 클래스_명<K, V> { ... }

 -타입 매개변수는 임의의 문자로 지정할 수 있음
 -T(Type), K(Key), V(Value), E(Element), N(Number), R(Result) 등을 주로 사용

 *static이 붙은 변수 또는 메서드에는 타입 매개변수를 사용할 수 없음(만약 사용할 수 있다면 클래스 변수를 통해 같은 변수를 공유하는 것이 아니게 되므로)

 (3)인스턴스화
 멤버를 구성하는 코드에 특정한 타입이 지정되지 않은 클래스이므로, 의도하고자 하는 타입을 지정해주어야 함
 -타입 매개변수에 치환될 타입으로 기본 타입을 지정할 수 없음
 -만약, int, double과 같은 원시 타입을 지정해야 하는 맥락에서는 Integer, Double과 같은 래퍼 클래스(wrapper class)를 활용

 (4)다형성 적용  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }
 
class Basket<T> {
    private T item;
 
    public T getItem() {
        return item;
    }
 
    public void setItem(T item) {
        this.item = item;
    }
}
 
class Main {
    public static void main(String[] args) {
        Basket<Flower> flowerBasket = new Basket<>();
        flowerBasket.setItem(new Rose());      // 다형성 적용
        flowerBasket.setItem(new RosePasta()); // 에러
    }
}
cs

 위의 예시를 보면
 -new Rose()를 통해 생성된 인스턴스는 Rose 타입이며, Rose 클래스는 Flower 클래스를 상속받고 있으므로, flowerBasket의 item에 할당될 수 있음
 -new RosePasta()를 통해 생성된 인스턴스는 RosePasta 타입이며, RosePasta 클래스는 Flower 클래스와 아무런 관계가 없기에, flowerBasket의 item에 할당될 수 없음


2-2.제한된 제네릭 클래스 : 제네릭 클래스에 상속(extends)를 사용한 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }
 
class Basket<extends Flower> {
    private T item;
    
        ...
}
 
class Main {
    public static void main(String[] args) {
    
        // 인스턴스화 
        Basket<Rose> roseBasket = new Basket<>();
        Basket<RosePasta> rosePastaBasket = new Basket<>(); // 에러
    }
}
cs

 -타입 매개변수를 선언할 때 위와 같이 코드를 작성해주면 Basket 클래스를 인스턴스화할 때 타입으로 Flower 클래스의 하위 클래스만 지정하도록 제한됨
 -특정 인터페이스를 구현한 클래스만 타입으로 지정할 수 있도록 제한할수도 있음. (해당 경우에도 extends 키워드 사용)
 -특정 클래스를 상속받으면서 동시에 특정 인터페이스를 구현한 클래스만 타입으로 지정할 수 있도록 제한하려면 extends 클래스_명 & 인터페이스_명 으로 사용


2-3.제네릭 메서드 : 클래스 내부의 특정 메서드만 제네릭으로 선언한 경우
 제네릭 메서드의 타입 매개변수 선언은 반환타입 앞에서 이루어지며, 해당 메서드 내에서만 선언한 타입 매개변수를 사용할 수 있음.

1
2
3
4
5
6
class Basket<T> {                       //클래스명 옆에서 선언한 타입 매개변수는 클래스가 인스턴스화될 때 타입이 지정됨
        ...
        public <T> void add(T element) {//제네릭 메서드의 타입 지정은 메서드가 호출될 때 이루어
                ...
        }
}
cs

 -제네릭 메서드의 타입 매개변수는 제네릭 클래스의 타입 매개변수와 서로 다른 것으로 간주됨.
 -메서드 타입 매개변수는 static 메서드에서도 선언 및 사용 가능(클래스 타입 매개변수에서는 불가능!)
 -제네릭 메서드 또한 메서드이기 때문에 여타 메서드와 비슷한 속성을 가짐
  *메서드가 호출되는 시점에서 제네릭 타입이 결정되므로 length()와 같은 String 클래스의 메서드는 제네릭 메서드를 정의하는 시점에 사용할 수 없음
  *equals(), toString() 같은 Object 클래스의 메서드는 사용 가능


2-4.와일드카드(Wild Card) : 어떠한 타입으로든 대체될 수 있는 타입 파라미터
 기호 ?로 와일드카드를 사용할 수 있고, 일반적으로 extends와 super 키워드를 조합하여 사용

 -<? extends T>는 와일드카드에 상한 제한을 두는 것으로서, T와 T를 상속받는 하위 클래스 타입만 타입 파라미터로 받을 수 있도록 지정
 -<? super T>는 와일드카드에 하한 제한을 두는 것으로, T와 T의 상위 클래스만 타입 파라미터로 받도록 함
 -extends 및 super 키워드와 조합하지 않은 와일드카드(<?>)는 <? extends Object>와 같음.(모든 클래스 타입을 타입 파라미터로 받을 수 있음)


3.예외 처리(Exception Handling) : 에러에 대응할 수 있는 코드를 미리 사전에 작성하여 프로그램의 비정상적인 종료를 방지하고, 정상적인 실행 상태를 유지하는 방법

 - 에러와 예외의 차이
   에러(error) : 한번 발생하면 복구하기 어려운 수준의 심각한 오류, 대표적으로 OutofMemoryError와 StackOverflowError
   예외(exception) : 잘못된 사용 또는 코딩으로 인한 상대적으로 미약한 수준의 오류

(1)컴파일 에러 : 컴파일 할 때 발생하는 에러
 -문법적인 문제를 가리키는 신택스(syntax) 오류로부터 발생하기 때문에 신택스 에러(Systax Errors)라고도 부름
 -자바 컴파일러가 오류를 감지하여 사용자에게 알려주기 때문에 상대적으로 쉽게 발견됨

(2)런타임 에러 : 코드를 실행하는 과정인 런타임 시에 발생하는 에러
 -주로 개발자가 컴퓨터가 수행할 수 없는 특정한 작업을 요청할 때 발생
 -자바 가상 머신(JVM)에 의해 감지됨


3-1.예외 클래스(Exception Class)
 -자바에서는 예외가 발생하면 예외 클래스로부터 객체를 생성하여 해당 인스턴스를 통해 예외를 처리함
 -자바의 모든 에러와 예외 클래스는 Throwable 클래스로부터 확장되며, 모든 예외 클래스는 Exception 클래스로부터 확장됨

예외 클래스의 상속 계층도

 (1)일반 예외 클래스(Exceptions)
  -컴파일러가 코드 실행 전에 예외 처리 코드 여부를 검사한다고하여 checked 예외라고도 부름
  -주로 사용자편의 실수로 발생하는 경우가 많음(ClassNotFoundException, DataFormatException..)

 (2)실행 예외 클래스(Runtime Exception)
  -컴파일러가 예외 처리 코드 여부를 검사하지 않는다는 의미에서 unchecked 예외라고도 부름
  -주로 개발자의 실수에 의해 발생하는 경우가 많고, 자바 문법 요소와 관련이 있음 (ClassCastException, NullPointerException..)

3-2.try-catch문
 -자바에서 예외 처리는 try - catch 블럭을 통해 구현이 가능하며 기본 구조는 아래와 같음

1
2
3
4
5
6
class Basket<T> {                       //클래스명 옆에서 선언한 타입 매개변수는 클래스가 인스턴스화될 때 타입이 지정됨
        ...
        public <T> void add(T element) {//제네릭 메서드의 타입 지정은 메서드가 호출될 때 이루어
                ...
        }
}
cs

 (1)try 블럭 안에는 예외가 발생할 가능성이 있는 코드를 삽입
   -작성한 코드가 예외 없이 정상적으로 실행되면 아래 catch 블럭은 실행되지 않고 finally 블럭이 실행
 
 (2)catch 블럭은 예외가 발생하는 경우에 실행되는 코드로, 여러 종류의 예외를 처리할 수 있음
   -모든 예외를 받을 수 있는 Exception 클래스 하나로 처리도 가능
   -catch 블럭이 여러 개인 경우, 일치하는 하나의 catch 블럭만이 실행되고 예외처리 코드가 종료되거나 finally 블럭으로 넘어감


3-3.예외 전가 : try-catch 문 외에 예외를 호출한 곳으로 다시 예외를 떠넘기는 방법
 아래와 같이 throws 키워드와 발생할 수 있는 예외들을 쉼표로 구분하여 나열함

1
2
3
반환타입 메서드명(매개변수, ...) throws 예외클래스1, 예외클래스2, ... {
    ...생략...
}
cs

 

 -특정 메서드에서 모든 종류의 예외가 발생할 가능성이 있는 경우 throws Exception(Exception 클래스)를 통해 모든 예외 클래스를 포함시킬 수 있음.

 +throw 키워드를 활용하면 의도적으로 예외를 발생시킬 수 있음

 

 

 

이미지 및 내용 출처 - code states