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

seongmin·2022년 9월 14일
0

Java

목록 보기
7/30
post-thumbnail

열거형(Enum)

  • 열거형은 여러 상수들을 보다 편리하게 선언할 수 있도록 만들어진 자바의 문법요소이며, 몇 가지로 한정된 변하지 않는 데이터를 다루는데 사용한다.

  • enum 을 사용하면 코드를 단순하고 가독성이 좋게 만들 수 있다는 장점이 있다. 또한 enum 으로 정의한 상수는 switch 문에서도 사용이 가능하다.

  • 여러 상수들을 보다 편리하게 선언하고 관리할 수 있게하며, 상수명의 중복을 피하고, 타입에 대한 안정성을 보장한다.

enum 열거형이름 { 상수명1, 상수명2, 상수명3, ...}
enum Seasons { SPRING, SUMMER, FALL, WINTER }
enum Frameworks { DJANGO, SPRING, NEST, EXPRESS }
  • 상수는 대소문자로 모두 작성이 가능하지만 관례적으로 대문자로 작성한다.
    각각의 상수들에는 따로 값을 지정해주지 않아도 자동적으로 0부터 시작하는 정수값이 할당되어 각각의 상수를 가리키게 된다.

  • 열거형에 사용하는 메서드

리턴 타입메소드 (매개변수)설명
Stringname()열거 객체가 가지고 있는 문자열을 리턴하며, 리턴되는 문자열은 열거타입을 정의할 때 사용한 상수 이름과 동일하다.
intordinal()열거 객체의 순번(0부터 시작)을 리턴한다.
intcompareTo(비교값)주어진 매개값과 비교해서 순번 차이를 리턴한다.
열거 타입valueOf(String name)주어진 문자열의 열거 객체를 리턴한다.
열거 배열values()모든 열거 객체들을 배열로 리턴한다.

제네릭(Generic)

  • 제네릭은 타입을 구체적으로 지정하는 것이 아니라, 추후에 지정할 수 있도록 일반화해두는 것을 의미한다. 즉, 작성한 클래스 또는 메서드의 코드가 특정 데이터 타입에 얽매이지 않게 해둔 것을 의미한다.

  • 제네릭을 사용하면 단 하나의 클래스만으로 모든 타입의 데이터를 저장할 수 있는 인스턴스를 만들 수 있다.

class Basket<T> {
    private T item;

    public Basket(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}
  • T 를 타입 매개변수라고 한다.
Basket<String> basket1 = new Basket<String>("기타줄");
  • 위와 같이 인스턴스화 하면 예제의 T 값이 모두 String 으로 간주된다.

제네릭 클래스

  • 제네릭이 사용된 클래스를 제네릭 클래스 라고 하며, 위에서 사용된 Basket 클래스가 제네릭 클래스이다.
타입매개변수 여러개 사용시 
class Basket<K, V> { ... }
  • 타입 매개변수는 임의의 문자로 지정할 수 있다. 위에서 사용한 T, K, V는 각각 Type, Key, Value의 첫 글자를 따온 것으로, Element의 E, Number의 N, Result의 R도 자주 사용된다.
class Basket<T> {
	private T item1; // O 
	static  T item2; // X 
}
  • 클래스 변수에는 타입 매개변수를 사용할 수 없다.
    클래스 변수는 모든 인스턴스가 공유하는 변수다. 만약, 클래스 변수에 타입 매개변수를 사용할 수 있다면 클래스 변수의 타입이 인스턴스 별로 달라지게 된다.
    -> static 이 붙은 변수 또는 메서드에는 타입 매개변수를 사용할 수 없다.
Cake<String> cake1 = new Cake<>("bread");
  • new Cake<…>은 아래와 같이 구체적인 타입을 생략하고 작성해도 된다. (참조변수의 타입으로부터 유추 가능)

  • 타입 매개변수를 선언할 때 아래와 같이 코드를 작성해주면 Basket 클래스를 인스턴스화할 때 타입으로 Flower
    클래스의 하위 클래스만 지정하도록 제한된다.

class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }

class Basket<T extends Flower> {
    private T item;
	
		...
}

public static void main(String[] args) {

		// 인스턴스화 
		Basket<Rose> roseBasket = new Basket<>();
		Basket<RosePasta> rosePastaBasket = new Basket<>(); // 에러
}
  • 특정 클래스를 상속 받으면서 동시에 특정 인터페이스를 구현한 클래스만 타입으로 지정할 수 있도록 제한하려면 & 를 사용한다.
    또한, 클래스를 인터페이스보다 앞에 위치시켜야 한다.
    (1) 참고
interface Plant { ... }
class Flower implements Plant { ... }
class Rose extends Flower implements Plant { ... }

class Basket<T extends Flower & Plant> { // (1)
    private T item;
	
		...
}

public static void main(String[] args) {

		// 인스턴스화 
		Basket<Flower> flowerBasket = new Basket<>();
		Basket<Rose> roseBasket = new Basket<>();
}

제네릭 메서드

  • 클래스 내부의 특정 메서드만 제네릭으로 선언할 수 있으며, 제네릭 메서드라고 한다.

  • 제네릭 메서드의 타입 매개변수 선언은 반환타입 앞에서 이루어지며, 해당 메서드 내에서만 선언한 타입 매개변수를 사용할 수 있다.

class Basket {
		...
		public <T> void add(T element) {
				...
		}
}
  • 제네릭 메서드의 타입 매개변수는 제네릭 클래스의 타입 매개변수와 별개의 것이다. 즉, 아래와 같이 동일하게 T 라는 타입 매개변수명을 사용한다 하더라도, 같은 알파벳 문자를 이름으로 사용하는 것일 뿐, 서로 다른 타입 매개변수로 간주된다.
class Basket<T> {                        // 1 : 여기에서 선언한 타입 매개변수 T와 
		...
		public <T> void add(T element) { // 2 : 여기에서 선언한 타입 매개변수 T는 서로 다름
				...
		}
}
  • 제네릭 메서드의 타입 지정은 메서드가 호출될 때 이루어진다.
Basket<String> basket = new Bakset<>(); // 위 예제의 1의 T가 String으로 지정됨
basket.<Integer>add(10);                // 위 예제의 2의 T가 Integer로 지정됨
basket.add(10);                         // 타입 지정을 생략 가능 
  • 클래스 타입 매개변수와 달리 메서드 타입 매개변수는 static 메서드에서도 선언하여 사용이 가능하다.
class Basket {
		...
		static <T> int setPrice(T element) {
				...
		}
}
  • 제네릭 메서드는 메서드가 호출되는 시점에서 제네릭 타입이 결정되므로, 제네릭 메서드를 정의하는 시점에서는 실제 어떤 타입이 입력 되는지 알 수 없다. 따라서 length() 와 같은 String 클래스의 메서드는 제네릭 메서드를 정의하는 시점에 사용할 수 없다.
class Basket {
    public <T> void print(T item) {
        System.out.println(item.length()); // 불가
    }
}
  • 모든 자바 클래스의 최상위 클래스인 Object 클래스의 메서드는 사용이 가능하다. 모든 클래스는 Object 클래스를 상속받기 때문이다. equals() , toString() 등이 포함된다.
class Basket {
    public <T> void getPrint(T item) {
        System.out.println(item.equals("Kim coding")); // 가능
    }
}

와일드카드

  • 와일드카드는 어떠한 타입으로든 대체될 수 있는 타입 파라미터를 의미하며, 기호 ? 로 와일드카드를 사용할 수 있다.

  • 일반적으로 와일드카드는 extendssuper 키워드를 조합하여 사용한다.

<? extends T>
<? super T>
  • <? extends T> 는 와일드카드에 상한 제한을 두는 것으로서, T와 T를 상속받는 하위 클래스 타입만 타입 파라미터로 받을 수 있도록 지정한다.

  • <? super T> 는 와일드카드에 하한 제한을 두는 것으로, T와 T의 상위 클래스만 타입 파라미터로 받도록 한다.

  • extendssuper 키워드와 조합하지 않은 와일드카드<?><? extends Object> 와 같다.

예외 처리

  • 예기치 않게 발생하는 에러에 대응할 수 있는 코드를 미리 사전에 작성하여 프로그램의 비정상적인 종료를 방지하고, 정상적인 실행 상태를 유지하기 위한 것.

에러

  • 컴파일 에러는 이름 그대로 “컴파일 할 때" 발생하는 에러를 가리킨다.

    주로 세미콜론 생략, 오탈자, 잘못된 자료형, 잘못된 포맷 등 문법적인 문제를 가리키는 신택스(syntax) 오류로부터 발생하기 때문에 신택스 에러(Systax Errors) 라고 부르기도 한다.

  • 런타임 에러는 코드를 실행하는 과정, 즉 런타임 시에 발생하는 에러를 가리킨다. 즉, 프로그램이 실행될 때 만나게되는 에러다.

    컴파일 에러가 주로 문법 요소와 관련한 신택스(syntax) 에러였다면 런타임 에러는 주로 개발자가 컴퓨터가 수행할 수 없는 특정한 작업을 요청할 때 발생한다.

예외 클래스의 상속 계층도

  • 자바의 모든 에러와 예외 클래스는 Throwable 클래스로부터 확장되며, 모든 예외의 최고 상위클래스는 Exception 클래스다.

  • 일반 예외 클래스

런타임 시 발생하는 RuntimeException 클래스와 그 하위 클래스를 제외한 모든 Exception 클래스와 그 하위 클래스들을 가리킨다.
컴파일러가 코드 실행 전에 예외 처리 코드 여부를 검사한다고하여 checked 예외 라 부르기도 한다.
주로 잘못된 클래스명(ClassNotFoundException)이나 데이터 형식(DataFormatException) 등 사용자편의 실수로 발생하는 경우가 많다.

  • 실행 예외 클래스

런타임 시 발생하는 RuntimeException 클래스와 그 하위클래스를 말한다.
컴파일러가 예외 처리 코드 여부를 검사하지 않는다는 의미에서 unchecked 예외 라 부르기도 한다.
주로 개발자의 실수에 의해 발생하는 경우가 많고, 자바 문법 요소와 관련이 있다.

try-catch문

try {
    // 예외가 발생할 가능성이 있는 코드를 삽입
} 
catch (ExceptionType1 e1) {
    // ExceptionType1 유형의 예외 발생 시 실행할 코드
} 
catch (ExceptionType2 e2) {
    // ExceptionType2 유형의 예외 발생 시 실행할 코드
} 
finally {
    // finally 블럭은 옵셔널
    // but, 포함되는 경우에는 예외 발생 여부와 상관없이 항상 실행
}
  • 예외 정보를 얻는 방법 (예외가 발생할 때 예외 객체로부터 해당 에러에 대한 정보를 얻음)

e.getMessage() : 에러의 원인을 간단하게 출력한다.

e.toString() : 에러의 Exception 내용과 원인을 출력한다.

e.printStackTrace() : 에러의 발생근원지를 찾아서 단계별로 에러를 출력한다.

예외 전가

  • 메서드의 선언부 끝에 아래와 같이 throws 키워드와 발생할 수 있는 예외들을 쉽표로 구분하여 나열해주면 된다.
반환타입 메서드명(매개변수, ...) throws 예외클래스1, 예외클래스2, ... {
	...생략...
}
  • 특정 메서드에서 모든 종류의 메서드가 발생할 가능성이 있는 경우 아래와 같이 작성할 수 있다.
void ExampleMethod() throws Exception {
}
  • throw 키워드를 사용하면 의도적으로 예외를 발생시킬 수 있다.
public class ExceptionTest {

    public static void main(String[] args) {
        try {
            Exception intendedException = new Exception("의도된 예외 만들기");
            throw intendedException;
        } catch (Exception e) {
            System.out.println("고의로 예외 발생시키기 성공!");
        }
    }
    
}

0개의 댓글