keyword - enum, generic, exception, collection
상수형을 열거해놓아 사용하기 쉽게 선언해놓은것. 보통 대문자로 표현한다.
enum Grade {FRESHMAN, SOPHOMORE, JUNIOR, SENIOR}
//사용할때는
Grade.FRESHMAN
Grade.SOPHOMORE
클래스나 메서드를 작성할 때, 타입을 확정적으로 명시하지 않고 사용자가 원하는 대로 대입해서 사용할 수 있게 만들어 놓은 것.
Generic Class
class Person<t> {
private T race;
Person(T race) {
this.race = race;
}
}
Person이라는 클래스의 race라는 변수는 타입이 T라고 적혀있다. 이것을 타입 매개변수라고 하는데, 아직 뭐가 될지 안정했고, 클래스를 생성할 때 정해주겠다는 의미이다. 위에 작성한 클래스는 Person의 race(인종)이 뭐가 될지 모르기 때문에 제네릭으로 선언한 상태이다.
Person<Asian> Syu = new Person<Asian>(new Asian("상유"));
위 코드의 의미는, Perosn의 제네릭 타입을 Asian으로 설정하여 생성한다는 의미이다.
주의할점
class Person<T, K, V, E> { };
static 변수에는 타입 매개변수를 지정할 수 없다.
=> static 변수는 공통 인스턴스인데, 타입이 각 개체마다 다르면 무슨 의미가 있나?
제네릭 클래스를 인스턴스화 할때, primitive형을 사용할 수 없다.
=> wrapper class 사용
Person<Integer> Syu = new Person<Integer>(89);
타입 매개변수에 조건을 걸 수도 있다. 제한된 제네릭이라고 한다.
class Asian {}
class Korean extends Asian {}
class Japanese extends Asian {};
class Chinese extends Asian {};
class Person<T extends Asian> { }
Person의 타입 매개변수로 Asian을 상속받은 클래스만 들어올 수 있다. Asian클래스를 상속받은 Korean이나 Janpanese, Chinese등이 들어올 수 있겠다. 또한 특정 클래스를 상속받은 클래스 뿐만 아니라, 특정 인터페이스를 구현한 클래스로 한정할 때에도 똑같이 extends 키워드를 사용한다.
특정 클래스도 상속받고, 특정 인터페이스도 구현한 클래스만 한정해서 타입 매개변수로 받고 싶다면, &연산자로 클래스 먼저 적고, 인터페이스를 나중에 적는다.
interface hotTemper {}
class Asian {}
class Korean extends Asian implements hotTemper {}
class Japanese extends Asian {};
class Chinese extends Asian {};
class Person<T extends Asian & hotTemper> { }
Generic Method
클래스 전체보다는 클래스 내부의 일부 메서드에만 제네릭을 설정하는 것이다.
class Person<T> {
...
public <T> void printName(T person) {
...
}
}
반환 타입 앞에 타입 매개변수를 작성한다.
와일드카드
제네릭의 문제점은 불공변이라는 것이었다. 예를 들어 collection에서는 printCollection처럼 모든 타입 변수에서 공통적으로 사용할 수 있는 메서드를 만들 수가 없었으며, 그러한 문제점을 해결하기 위해서 와일드카드가 도입되었다.
제네릭 : 지금은 이 타입을 모르지만, 이 타입이 정해지면 그 타입 특성에 맞게 사용하겠다!
와일드 카드 : 지금도 이 타입을 모르고, 앞으로도 모를 것이다!
List<?> list;
// 1. 원소를 꺼내 와서는 Object에 정의되어 있는 기능만 사용하겠다.
// equals(), toString(), hashCode()…
// 2. List에 타입이 뭐가 오든 상관 없다.
// 나는 List 인터페이스에 정의되어 있는 기능만 사용하겠다.
// size(), clear().. 단, 타입 파라미터와 결부된 기능은 사용하지 않겠다! add(), addAll()
List<T> list;
// 1. 원소를 꺼내 와서는 Object에 정의되어 있는 기능만 사용하겠다.
// equals(), toString(), hashCode()…
// 2. List에 타입이 뭐가 오든 상관 없다.
// 나는 List 인터페이스에 정의되어 있는 기능만 사용을 하고,
// 타입 파라미터와 결부된 기능도 사용하겠다.
@Test
public void sampleCode2() {
List<Integer> integerList = Arrays.asList(1, 2, 3);
printList1(integerList);
printList2(integerList);
}
static void printList1(List<?> list) {
## 1. 와일드 카드는 list에 담긴 원소에는 전혀 관심이 없기 때문에
원소와 관련된 add 메소드를 사용할 수 없다.
## 2. 단, null은 들어갈 수 있다.
list.add(list.get(1)); // 컴파일 실패
}
static <T> void printList2(List<T> list) {
## 1. 제네릭은 list에 담긴 원소에 관심을 갖기 때문에
원소와 관련된 add 메소드를 사용할 수 있다.
## 2. 당연히 null도 들어갈 수 있다.
list.add(list.get(1)); // 컴파일 성공
}
출처: https://vvshinevv.tistory.com/55?category=692309
에러는 심각한 수준, 예외(exception)는 경미한 수준의 타입 에러 같은 부분.
예외 클래스
컴파일러는 RuntimeException은 경미한 예외라고 생각하며, 이 외에 Exception클래스의 하위 예외들은 try/catch 문으로 예외 처리를 강제하고 있다.
byte[] list = {'a', 'b', 'c'};
try {
System.out.write(list);
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("finally");
}
finally{} 는 예외가 나든 안나든 무조건 실행되는데, 필수는 아니다.