try{
예외가 발생할 수 있는 코드
} catch(예외 정보를 받을 파라미터){
예외 처리 코드
}
void m() {
try{
예외를 발생시키는 코드
}catch(Throwable ex){
예외 처리 코드
}
}
void m() throws 예외타입{
예외를 발생시키는 코드
}
public static int inputInt(String title) {
System.out.print(title);
String str = keyboardInput.nextLine();
try {
return Integer.parseInt(str);
}catch(Throwable ex) {
// 예외처리:
// => 예외가 발생했음을 알리는 메시지를 출력한다.
System.out.println("숫자가 아닙니다.");
// 예외 처리를 한 후에도 메서드는 값을 리턴해야 한다.
// 그런 사용자가 입력할 법한 값을 리턴하면 호출하는 쪽에서는 예외가 발생했는지 모른다.
// 그래서 다음과 같이 사용자가 입력할 것 같지 않은 아주 독특한 값을 리턴한다.
return -1121212;
}
}
int mainMenuNo = Prompt.inputInt("메뉴를 선택하세요[1..6](0: 종료) ");
// 메뉴 번호를 잘못 입력하는 상황이 발생했을 때, inputInput() 리턴 값 12121212를 리턴할 것이다.
// 이 경우를 고려해서 처리한다.
if(mainMenuNo == -12121212) {
continue;
}
→ 예외가 발생했음을 알리는 메시지를 출력한다.
// Prompt 클래스
System.out.println("숫자가 아닙니다.");
위와 같이 예외가 발생한 지점(Prompt 클래스)에서 출력을 하는 방식은 호출자(BoardHandler)의 예외 처리를 방해할 수 있다.
(메뉴 번호가 옳지 않습니다만 출력하고 싶은데, 숫자가 아닙니다 까지 출력하고 있다.)
⇒ 따라서, 호출한 쪽에서 출력을 하든 무시를 하든 적절하게 처리하라고 단순히 리턴값을 통해 예외 상황만 알리는것이 좋다.
try {
int mainMenuNo = Prompt.inputInt("메뉴를 선택하세요[1..6](0: 종료) ");
switch (mainMenuNo) {
case 0: break loop;
case 1: // 게시판
boardHandler.execute();
break;
case 2: // 독서록
readingHandler.execute();
break;
case 3: // 방명록
visitHandler.execute();
break;
case 4: // 공지사항
noticeHandler.execute();
break;
case 5: // 일기장
diaryHandler.execute();
break;
case 6: // 회원
memberHandler.execute();
break;
default: System.out.println("메뉴 번호가 옳지 않습니다!");
} // switch
}catch(Throwable ex) {
System.out.println("입력 값이 옳지 않습니다!");
}
try {
int menuNo = Prompt.inputInt("메뉴를 선택하세요[1..5](0: 이전) ");
displayHeadline();
switch (menuNo) {
case 0: return;
case 1: this.onList(); break;
case 2: this.onDetail(); break;
case 3: this.onInput(); break;
case 4: this.onDelete(); break;
case 5: this.onUpdate(); break;
default: System.out.println("메뉴 번호가 옳지 않습니다!");
}
displayBlankLine();
}catch(Throwable ex) {
System.out.printf("예외 발생: %s\n", ex.getMessage());
}
private void onDetail() {
System.out.printf("[%s 상세보기]\n", this.title);
int boardNo=0;
while(true) {
try {
boardNo = Prompt.inputInt("조회할 게시글 번호? ");
break;
}catch(Throwable ex0) {
System.out.println("입력값이 옳지 않습니다!");
}
...
}
}
private void onUpdate() {
System.out.printf("[%s 변경]\n", this.title);
int boardNo=0;
while(true) {
try {
boardNo = Prompt.inputInt("변경할 게시글 번호? ");
break;
}catch(Throwable ex) {
System.out.println("입력 값이 옳지 않습니다!");
}
}
...
}
private void onDelete() {
System.out.printf("[%s 삭제]\n", this.title);
int boardNo=0;
while(true) {
try {
boardNo = Prompt.inputInt("삭제할 게시글 번호? ");
break;
}catch(Throwable ex) {
System.out.println("입력 값이 옳지 않습니다!");
}
}
...
}
Object obj;
obj = new Object();
obj.toString(); ← Object의 toString() 메소드
Member m = new Member();
m.toString(); ← Object의 toString() 메소드
String s = new String("Hello");
s.toString(); ← String의 toString() 메소드
Object x = new String("Hello");
x.toString();
x.charAt(0); ← 컴파일 오류가 난다.
x.toString();
Object x = new String("Hello");
x.toString();
↑ x가 실제 가르키는 클래스(String class type)에서부터 메소드를 찾아 올라간다.
String 클래스가 toString()메소드를 오버라이딩 했기 때문에 Object의 메소드가 덮어씌워져서,
String클래스의 메소드가 쓰여지는 것이다.
x.charAt(0); ← 컴파일 오류가 난다.
x.toString(); ← 컴파일 OK!
ObjectList list = new ObjectList(); // 추상 클래스가 아니어서 객체로 직접 사용 가능!
list.add("홍길동");
list.add("임꺽정");
list.add("유관순");
list.add(null); //목록에 null을 넣을 수 있다.
list.add("안중근");
Object obj = list.get(0); // 실제 get()이 리턴하는 것은 String 객체이다.
System.out.println(obj.toString());
System.out.println(list.get(0)); // 따로 레퍼런스 변수 안만들고 바로 넣어줘도 된다.
- 컴파일러: 현재 레퍼런스 변수가 가르키는 클래스 타입에 사용하려는 메소드가 존재하는 지 여부만 따진다.
⇒ 원래 Object에도 toString()이 있기 때문에 컴파일러에게 안걸리는 것이다.
⇒ 하지만, obj.char(0) 이 메소드는 컴파일 오류가 난다. Object 클래스에 이 메소드가 존재하지 않기 때문이다.
- JVM: 컴파일러 실행 후에, 실행을 담당, 인스턴스 타입부터 따져서 올라간다.
→ String 클래스는 toString() 메소드를 오버라이딩 했기 때문에 String 클래스의 toString() 메소드를 가져온다.
→ 만약 String 클래스가 오버라이딩 안했으면 Object 클래스의 toString()이 가져와졌을 것이다.
ObjectList list = new ObjectList();
list.add("홍길동");
list.add("임꺽정");
list.add("유관순");
list.add(null); //목록에 null을 넣을 수 있다.
list.add("안중근");
Object obj = list.get(0);
System.out.println(obj.toString());
System.out.println(list.get(0));
obj = list.get(1);
System.out.println(obj.toString());
System.out.println(list.get(1)); // 쓸데 없이 변수에 담을 필요 없다. 바로println에게 넘겨주면 된다.
obj = list.get(2);
System.out.println(obj.toString());
System.out.println(list.get(4).toString());
System.out.println(list.get(4);
⇒ 그래서 이 코드에서 toString() 없어도 되는 것!
3번 인덱스에 null이 들어 있기 때문에 꺼낸 값도 null이다.
System.out.println(list.get(3));
100번 인덱스는 유효한 인덱스가 아니기 때문에 get()메소드가 null을 리턴한다.
System.out.println(list.get(100));
throw 예외 정보를 담은 객체;
public Object get(int index) throws Throwable{ // 단, 메서드 선언부에 어떤 예외를 던지는지 표시해야 한다!!
if(index <0 || index >= size) {
throw new Throwable("인덱스가 무효합니다!");
}
return elementData[index];
}
public boolean remove(int index)throws Throwable {
if(index <0 || index >= size) {
// 인덱스가 무효할 떄 false 를 리턴하는대신,
// 예외정보를 호출자에게 던진다.
// 예외 상황을 호출자에게 보고한다.
throw new Throwable("인덱스가 무효합니다!");
}
for(int i=index+1;i<size;i++) {
elementData[i-1]=elementData[i];
}
elementData[--size] = null;
return true;
}
@Override
public Board get(int boardNo) throws Throwable{
for (int i = 0; i < size(); i++) {
Board board = (Board)super.get(i);
if (board.no== boardNo) {
return board;
}
}
return null;
}
@Override
public boolean remove(int boardNo) throws Throwable{
for (int i = 0; i < size(); i++) {
Board board = (Board)super.get(i);
if (board.no == boardNo) {
return super.remove(i);
}
}
return false;
}
try {
Board board = this.boardList.get(boardNo);
if (board == null) {
System.out.println("해당 번호의 게시글이 없습니다!");
return;
}
System.out.printf("번호: %d\n", board.no);
System.out.printf("제목: %s\n", board.title);
System.out.printf("내용: %s\n", board.content);
System.out.printf("조회수: %d\n", board.viewCount);
System.out.printf("작성자: %s\n", board.writer);
Date date = new Date(board.createdDate);
System.out.printf("등록일: %tY-%1$tm-%1$td %1$tH:%1$tM\n", date);
// 정상적일 때 여기까지 진행한다.
}catch(Throwable ex) {
System.out.printf("예외 발생: %s\n", ex.getMessage());
}
public void execute() {
while (true) {
System.out.printf("%s:\n", this.title);
System.out.println(" 1: 목록");
System.out.println(" 2: 상세보기");
System.out.println(" 3: 등록");
System.out.println(" 4: 삭제");
System.out.println(" 5: 변경");
System.out.println();
try {
int menuNo = Prompt.inputInt("메뉴를 선택하세요[1..5](0: 이전) ");
displayHeadline();
switch (menuNo) {
case 0: return;
case 1: this.onList(); break;
case 2: this.onDetail(); break;
case 3: this.onInput(); break;
case 4: this.onDelete(); break;
case 5: this.onUpdate(); break;
default: System.out.println("메뉴 번호가 옳지 않습니다!");
}
displayBlankLine();
}catch(Throwable ex) {
System.out.printf("예외 발생: %s\n", ex.getMessage());
}
} // 게시판 while
}