예외처리(Exception)과 제네릭(Generics)에 대해 알아보자.
(1) 예외처리
자바에서 오동작이나 결과에 악영향을 미칠 수 있는 실행 중 발생한 오류를 예외처리라고 한다. 자주 발생하는 예외에 대한 정보는 다음과 같다.
자바는 예외처리를 위해 try-catch-finally문을 사용한다. 사용법은 다음과 같으며, finally 블록은 생략 가능하다.
try {
//예외가 발생할 가능성이 있는 실행문
}
catch (처리할 예외 타입 선언) {
//예외 처리문
}
finally {
//예외 발생 여부와 상관없이 무조건 실행되는 문장
}
예외처리의 최상위 클래스는 java.lang.Throwable 클래스이다. 이 클래스에 속해있는 메소드 두 개만 살펴보자면
- public String getMessage() : 예외의 원인을 담고 있는 문자열을 반환
- public void printStackTrace() : 예외가 발생한 위치와 호출된 메소드의 정보를 출력
import java.util.*; //이거 꼭 import 해줘야 한다
public class FinalTermTest {
public static void md1(int n) {
md2(n, 0);
}
public static void md2(int n1, int n2) {
int r = n1 / n2;
}
public static void main(String[] args) {
try {
md1(3);
}
catch(ArithmeticException | InputMismatchException e) {
e.getMessage();
e.printStackTrace();
}
System.out.println("프로그램 종료");
}
}
(2) 제네릭
'타입 매개 변수'를 지칭함. 자바에서 클래스 코드를 찍어내듯이 생산할 수 있도록 일반화시키는 도구이다. 'E', 'T', 'V'와 같이 하나의 대문자로 사용되며, 구체적인 타입을 지정하면 지정된 타입만 다룰 수 있는 구체화 된 클래스를 만들 수 있다. 가령 Vector<E>에서 E 대신 Integer와 같이 구체적인 타입을 지정하면, Vector<Integer>는 정수 값만 저장하는 벡터로, Vector<String>은 문자열만 저장하는 벡터로 사용할 수 있다. 특정 타입만 다루지 않고 여러 종류의 타입으로 변신할 수 있도록, 일반화시키기 위해 <E>를 사용하는 것이다. 여기서의 E를 '제네릭 타입'이라고 부른다.
관례적으로는 다음과 같이 사용한다.
- E : Element를 의미함(컬렉션의 요소)
- T : Type을 의미
- V : Value를 의미
- K : Key를 의미
컬렉션의 요소는 객체들만 가능하다. 무슨 말이냐 하면, int, char, double 같은 기본 타입의 데이터는 원칙적으로 컬렉션의 요소로 불가능하기 때문에, 제네릭 타입도 기본 타입으로는 선언 및 생성 불가능하다.
Vector<int> v = new Vector<int>(); (X)
Vector<Integer> v = new Vector<Integer>(); (O)
다음과 같은 예시를 보자. Apple과 Orange라는 클래스가 있고, Box 클래스는 말그대로 상자처럼 무엇이든 저장하고 꺼낼 수 있는, set(), get() 메소드를 이용한 클래스이다.
두 가지 문제 상황이 발생할 수 있다. 첫 째, 각 과일을 레퍼런스 타입으로 Box를 통해 받아오고 싶으면 형변환을 해야 한다. 둘 째, 사용자가 set() 메소드에 인스턴스가 아닌 문자열을 넣어버린다면? 아니면 정수를 넣어버린다면? 우리는 문자열이나 숫자가 아닌, 사과와 오렌지의 인스턴스(객체)를 상자에 넣었다 빼고 싶다.
import java.util.*;
class Apple {
public String toString() { return "I am an apple."; }
}
class Orange {
public String toString() { return "I am an orange."; }
}
class Box {
private Object ob;
public void set(Object o) { ob = o; }
public Object get() { return ob; }
}
public class FinalTermTest {
public static void main(String[] args) {
Box aBox = new Box();
Box bBox = new Box();
aBox.set("Apple"); // 이게 아니라 aBox.set(new Apple());
bBox.set("Orange"); // 이게 아니라 bBox.set(new Orange());
Apple ap = (Apple)aBox.get(); // 형변환 해야됨
Orange og = (Orange)bBox.get(); // 형변환 해야됨
}
}
제네릭 기반의 클래스를 정의하고 인스턴스를 생성하면 개선된 결과를 얻을 수 있다. 형변환을 할 필요가 없을 뿐더러, 사용자가 인스턴스가 아닌 다른 자료형을 넣으면 컴파일러가 오류를 발생시켜준다.
인스턴스 생성시 결정되는 자료형의 정보를 Object에서 T로 대체해보았다.
import java.util.*;
class Apple {
public String toString() { return "I am an apple."; }
}
class Orange {
public String toString() { return "I am an orange."; }
}
class Box<T> {
private T ob;
public void set(T o) { ob = o; }
public T get() { return ob; }
}
public class FinalTermTest {
public static void main(String[] args) {
Box<Apple> aBox = new Box<>(); //원래는 뒤의 다이아몬드 기호 안에도 Apple을 넣어줘야 하지만 빼도 상관X
Box<Orange> bBox = new Box<>(); //여기도!
//aBox.set("Apple");
//bBox.set("Orange");
//error: incompatible types: String cannot be converted to (Apple 혹은 Orange)
Apple ap = aBox.get(); // 형변환 하지 않음
Orange og = bBox.get(); // 형변환 하지 않음
}
}
'coding > Java' 카테고리의 다른 글
[Java] GUI 응용프로그램(2) - Event Listener (0) | 2020.12.21 |
---|---|
[Java] GUI 응용프로그램(1) - Layout, Panel, Component (0) | 2020.12.21 |
[Java] 배열과 상속 연습문제(1~3) (0) | 2020.12.21 |
[Java] 추상클래스, 추상메소드, 인터페이스 (0) | 2020.12.20 |
[Java] 상속과 참조변수, instanceof 연산자 (0) | 2020.12.20 |