classDirection{
staticfinal Direction EAST = new Direction(“EAST”);
staticfinal Direction SOUTH = new Direction(“SOUTH”);
staticfinal Direction WEST = new Direction(“WEST”);
staticfinal Direction NORTH = new Direction(“NORTH”);
privatefinal String name;
privateDirection(String name){
this.name = name;
}
}
2. Extends Enum
classMyEnum<? extendsMyEnum<T>> implementsComparable<T> {
static in id = 0;
int ordinal;
String name = “”;
publicintordinal(){ return ordinal; }
MyEnum(String name) {
this.name = name;
ordinal = id++;
}
publicintcompareTo(T t){
// t.ordinal()은 MyEnum<? extends MyEnum<T>> 때문에 에러 없이 사용가능하다.// MyEnum<T> 였다면 T에 ordinal()이 있는지 확인이 되지 않아 에러가 발생했을 것이다.return ordinal - t.ordinal();
}
}
3. Enum Abstract Method
3.1 Enum EX)
enumDirection{
EAST(1) {
Point move(Point p){ … }
},
SOUTH(2) {
Point move(Point p){ … }
},
WEST(3) {
Point move(Point p){ … }
},
NORTH(4) {
Point move(Point p){ … }
};
// protected인 이유는 추상 메서드를 구현하는 상수에서 접근 하기 위함이다.protectedfinalint value;
Direction(int value) { this.value = value }
abstract Point move(Point p);
}
3.2 Class EX)
abstractclassDirectionextendsMyEnum{
// 추상 클래스인 Direction을 생성하였기에 익명 클래스 형태로 추상 메서드인 move구현staticfinal Direction EAST = new Direction(“EAST”) {
Point move(Point p){ … }
}
// 추상 클래스인 Direction을 생성하였기에 익명 클래스 형태로 추상 메서드인 move구현staticfinal Direction SOUTH = new Direction(“SOUTH”) {
Point move(Point p){ … }
}
// 추상 클래스인 Direction을 생성하였기에 익명 클래스 형태로 추상 메서드인 move구현staticfinal Direction WEST = new Direction(“WEST”) {
Point move(Point p){ … }
}
// 추상 클래스인 Direction을 생성하였기에 익명 클래스 형태로 추상 메서드인 move구현staticfinal Direction NORTH = new Direction(“NORTH”) {
Point move(Point p){ … }
}
private String name;
privateDirection(String name){ this.name = name }
// Direction의 추상 메서드 move 선언abstract Point move(Point p);
}
프로그램이 실행 도중 발생하면 비정상적으로 프로그램이 종료되지만 발생할 수 있는 상황을 미리 예측하여 처리하는 것을 말한다. 예외 처리의 목적은 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하기 위함이다.
발생하는 예외를 처리하지 못하면 JVM의 예외 처리기가 받아서 예외를 화면에 출력한다.
* 프로그램의 오류
컴파일 에러 : 컴파일 과정 중 발생하는 에러
런타임 에러 : 프로그램 실행 도중 발생하는 에러
논리적 에러 : 실행은 되지만 의도와 다르게 동작하는 에러
컴파일러가 잘못된 구문들을 체크하여 컴파일 후 class 파일이 생성된다. 하지만 실행 도중 발생하는 잠재적 에러는 파악할 수 없다.
* 런타임 에러의 종류
에러 : OutOfMemory, StackOverFlow 등 발생하면 복구할 수 없는 심각한 상태를 말하며 프로그램 코드에 의해 수습될 수 없는 심각한 오류이다.
예외 : 발생하더라도 수습이 가능한 상태이며 프로그램 코드에 의해 수습될 수 있는 다소 미약한 오류이다.
2. 예외 클래스의 계층 구조
상속 계층도
예외 클래스를 나누면 Exception class와 RuntimeException class 두 가지로 나눌 수 있다.
RuntimeException 하위 클래스들은 프로그래머의 실수로 발생하는 예외이다. (uncheckd 예외) ex) IndexOutOfBoundException NullPointerException ClassCastException ArithmeticException
Exception 하위 클래스들은 사용자의 실수로 발생하는 예외이다.(checkd 예외) ex) FileNotFoundException ClassNotFoundException DataFormatException
3. 예외 처리하기 - try - catch문
publicclassSample{
publicintgetAge(){
try {
// 예외가 발생할 가능성이 있는 코드
} catch(ArithmeticException e1) {
// ArithmeticException이 발생할 경우 실행되는 코드
} catch(IOException e2) {
// IOException이 발생할 경우 실행되는 코드
}
}
}
try 다음에 여러 종류의 catch 블록이 올 수 있으며 해당 예외 발생 시 발생한 예외의 catch 문이 실행된다. catch에 없는 예외 발생 시 예외가 처리되지 않는다.
try - catch문은 실행 코드가 한 줄 이어도 중괄호 생략 불가능하다.
try - catch문안에 또 다른 try - catch 문이 올 수 있으며 같은 레벨에 여러 try - catch문이 올 수 있다.
4. try - catch 문에서의 흐름
* 실행 순서
try 블록 내에서 예외가 발생한 경우
발생한 예외와 일치하는 catch 블록이 있는지 확인
일치하는 catch 문을 찾았다면 - 해당 catch문을 실행하고 try - catch문을 빠져나간다. 일치하는 catch문을 못 찾았다면 예외 처리되지 않는다.
try 블록 내에서 예외가 발생하지 않는 경우
catch 문을 거치지 않고 try - catch 문을 빠져나간다.
try 안에서 예외가 발생할 때 발생한 라인 이하의 코드는 실행되지 않고 catch문으로 빠져나간다.
5. 예외의 발생과 catch 블록
catch문은 괄호와 블록으로 나뉜다.
괄호에는 예외 처리할 예외 타입의 참조 변수를 정의한다.
try {
...
} catch (ArithmeticException e) {
...
}
첫 번째 catch부터 마지막 catch까지 예외 인스턴스와 catch의 참조 변수 종류를 instanceof 연산자를 이용해 검사하고 검사 결과 true인 catch 블록을 만날 때까지 검사한다.
catch문에 'Exception'을 지정하면 모든 예외가 잡힌다. 그 이유는 모든 예외가 Exception의 자식이기 때문이다.
파이프 ( | )를 이용 시 클래스가 상위, 하위 관계에 있다면 컴파일 에러가 발생한다. 그 이유는 상위 클래스만 넣어도 예외 처리가 잡히기 때문이다.멀티 catch 블록을 사용 시 어떤 예외로 들어왔는지 모르기 때문에 예외 클래스들의 공통분모인 상위 멤버만 사용 가능하다. 또한 instanceof를 이용하여 예외처리해도 된다.
위의 예제에서 initCause(e) : 원인 예외를 e (IOException)으로 지정하였고 주로 여러 예외들을 묶어서 분류할 때 사용한다. 여러 클래스를 묶어 상위 클래스를 사용하면 상속 관계 변경, 실제 인스턴스 판단 미스 등의 이유로 인해 부담되는 이유로 사용한다.
* Exception 클래스의 상위인 Throwable에 initCause(), getCause()가 정의되어 있다.
static 키워드를 분인 클래스로 멤버 변수 위치에 선언되며 static 멤버처럼 다루어 진다. 조로 static 메서드에서 사용한다.
2.2. 인스턴스 클래스 (instance class)
static 키워드를 붙이지 않은 클래스로 멤버 변수 위치에 선언되며 인스턴스 멤버들과 관련된 작업을 진행할 때 사용한다.
2.3. 지역 클래스 (local calss)
메서드나 초기화 블럭에서 선언된다. 지역 클래스는 선언된 블록 안에서만 사용된다.
2.4. 익명 클래스 (anonymous class)
클래스 선언과 객체의 생성을 동시에 하는 단 하나의 객체만을 생성하는 일회성 이름 없는 클래스이다. 일회성이다 보니 생성자를 구현할 수 없으며, 단 하나의 클래스, 단 하나의 인터페이스를 상속받거나 구현할 수 있을 뿐인다.
익명 클래스는 매우 제한적인 용도로 사용되며, 구현해야 하는 메서드가 적거나 변수가 적을 때 사용한다.
* 익명 클래스 컴파일 시 파일 명
Outer.class
Outer$1.class
Outer$2.class
publicinterfaceAble{}
publicclassParent{}
publicclassOuter{
public Able a = new Able() {
publicint a;
}
public Parent a = new Parent() {
publicint a;
}
}
3. 내부 클래스의 선언
publicclassOuter{
classInstanceInner{} // instance 클래스staticclassStaticInner{} // static 클래스voidmethod(){
classLocalInner{} // local 클래스
}
}
4. 내부 클래스의 제어자와 접근성
final, abstract, private, protected와 같은 제어자 사용 가능하다.
instance, local 내부 클래스에서는 static 키워드를 사용할 수 없다.
모든 내부 클래스에서 final static 키워드를 사용할 수 있다.
static 내부 클래스에서만 static을 사용할 수 있다.
static과 instance의 효과를 그대로 사용한다. - static은 instance 사용 불가 - instance는 static 사용 가능
인스턴스 내부 클래스를 생성하려면 외부 클래스의 인스턴스부터 생성해야 한다.
* final은 상수이기 때문에 어떤 경우라도 static이 붙는 게 가능하다.
Outer oc = new Outer();
oc.new InstanceInner(); // Outer 클래스 생성 후 InstanceInner 클래스 생성