throw [Throwable 객체];
throw new String("예외가 발생하였습니다"); // 컴파일 오류
throw new RuntimeException("예외가 발생하였습니다.");
public class Exam0111 {
static void m() {
throw new RuntimeException("예외가 발생했습니다!");
}
static void test() {
m();
// m() 메서드가 던진 예외를 받지 않으면?
// 즉시 현재 메서드의 실행을 멈추고 호출자에게 예외 처리를 위임한다.
// m() 메소드로부터 받은 예외 객체를 이 메서드 test()를 호출한 호출자에게 넘겨 버린다.
// 따라서 다음 출력 코드는 실행되지 않는다.
System.out.println("test() 호출됨!");
}
public static void main(String[] args) {
// 예외를 받았을 때 처리하는 문법
try {
test();
} catch (RuntimeException e) {
// 예외가 발생하면 catch 블록이 실행된다.
// 코드에서 던진 예외 객체는 catch의 파라미터가 받는다.
// catch 블록에는 예외에 대한 적절한 조치를 수행하는 코드를 둔다.
// 예) 다음과 같이 예외가 발생된 이유를 간단히 출력할 수 있다.
System.out.println(e.getMessage());
}
System.out.println("시스템을 종료합니다.");
}
}
1. java.lang.Error (시스템 오류)
2. java.lang.Exception (애플리케이션 오류)
import java.io.FileNotFoundException;
public class Exam0210 {
static void m1() throws Throwable {
throw new Throwable(); // OK!
// 예외를 던질 때 Throwable 클래스를 직접 사용하지 말라!
// 그 하위 클래스를 사용하라.
// 특히 애플리케이션 오류를 의미하는 Exception 클래스를 사용하라.
}
// 여러 개의 오류를 던지는 경우 메서드 선언부에 그대로 나열하라.
static void m2() throws FileNotFoundException, RuntimeException {
int a = 100;
if (a < 0)
throw new FileNotFoundException(); // OK!
else
throw new RuntimeException(); // OK!
}
public static void main(String[] args) {}
}
- Exception의 서브 클래스임에도 불구하고 RuntimeException 객체를 던질 경우, 메서드 선언부에 예외를 던진다고 표시하지 않아도 된다.
public class Exam0220 {
static void m() throws RuntimeException {
throw new RuntimeException(); // OK!
}
static void m2() {
throw new RuntimeException();
}
public static void main(String[] args) {}
}
static void m(int i) throws Exception, RuntimeException, SQLException, IOException {
if (i == 0)
throw new Exception();
else if (i == 1)
throw new RuntimeException();
else if (i == 2)
throw new SQLException();
else
throw new IOException();
}
public static void main(String[] args) {}
}
throw new Exception();
public static void main(String[] args) {
m(1); → 컴파일 오류 발생
}
public static void main(String[] args) throws Exception {
m(1);
}
public class Exam0430 {
static void m(int i) throws Exception, RuntimeException, SQLException, IOException {
if (i == 0)
throw new Exception();
else if (i == 1)
throw new RuntimeException();
else if (i == 2)
throw new SQLException();
else if (i == 3)
throw new IOException();
}
public static void main(String[] args) {
try {
m(4);
System.out.println("실행 성공!");
} catch (IOException e) {
System.out.println("IOException 발생");
} catch (SQLException e) {
System.out.println("SQLException 발생");
} catch (RuntimeException e) {
System.out.println("RuntimeException 발생");
} catch (Exception e) {
System.out.println("기타 Exception 발생");
}
}
}
- 여러 개의 예외를 받을 때 예외를 구체적으로 구분해서 처리하고 싶다면, 수퍼 클래스 변수로 먼저 받지 말라!
- 즉, 통쳐서 처리하고 싶을 때, 예외를 구분할 필요 없는 경우에는, 그냥 Exception으로 다 받아주면 된다는 뜻이다.
public class Exam0440 {
static void m(int i) throws Exception, RuntimeException, SQLException, IOException {
if (i == 0)
throw new Exception();
else if (i == 1)
throw new RuntimeException();
else if (i == 2)
throw new SQLException();
else if (i == 3)
throw new IOException();
}
public static void main(String[] args) {
try {
// try 블록에서 예외가 발생할 수 있는 메서드를 호출한다.
m(1);
} catch (Exception e) {
} catch (IOException e) {
→ 여기부터 컴파일러 에러 난다.
} catch (SQLException e) {
} catch (RuntimeException e) {
}
}
정상적으로 실행하든, 아니면 예외가 발생하여 catch 블록을 실행하든 finally 블록은 무조건 실행한다.
try 블록을 나가기 전에 무조건 실행해야 할 작업이 있다면, catch 블록이 없어도 finally 블록만 사용할 수 있다!
public static void main(String[] args) throws Exception {
try {
m(1);
// m()에서 발생된 예외는 try 블록에서 받지 않는다.
// 따라서 main() 호출자에게 위임한다.
// => 물론 main() 메서드 선언부에 위임할 예외의 종류를 표시해야 한다.
} finally {
System.out.println("마무리 작업 실행!");
}
}
public class Exam0620 {
public static void main(String[] args) {
Scanner keyScan = null;
try {
keyScan = new Scanner(System.in);
System.out.print("입력> ");
int value = keyScan.nextInt();
System.out.println(value * value);
} finally {
keyScan.close();
System.out.println("스캐너 자원 해제!");
}
}
}
try-with-resources 라는 문법을 사용하면 굳이 finally 블록에서 close()를 직접 호출할 필요가 없다.
⇒ 자동으로 처리한다.
try (java.lang.AutoCloseable 구현체) {...(구현체 사용)}
static void m() throws Exception {
try (
Scanner keyScan = new Scanner(System.in);
// FileReader 클래스도 java.lang.AutoCloseable 구현체이다.
FileReader in = new FileReader("Hello.java"); // OK!
) {
System.out.print("입력> ");
int value = keyScan.nextInt();
System.out.println(value * value);
}
}
A implements B{
...
}
A 클래스가 B인터페이스의 규칙을 이행한다.
인터페이스 == 규칙
static class C implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("C 클래스의 자원을 해제하였습니다.");
}
}
실무에서는 개발자에게 예외의 의미를 직관적으로 전달하기 위해,
RuntimeException 같은 평범한, 의미가 모호한 이름의 클래스를 사용하지 않고
대신에 기존 예외를 상속 받아 의미있는 이름으로 서브 클래스를 정의한 다음에 그 예외 클래스를 던지도록 프로그래밍한다.
import java.sql.Date;
import java.util.Scanner;
public class Exam0130 {
static Board read() throws BoardException {
try (Scanner keyScan = new Scanner(System.in)) {
Board board = new Board();
System.out.print("번호> ");
board.setNo(Integer.parseInt(keyScan.nextLine()));
System.out.print("제목> ");
board.setTitle(keyScan.nextLine());
System.out.print("내용> ");
board.setContent(keyScan.nextLine());
System.out.print("등록일> ");
board.setCreatedDate(Date.valueOf(keyScan.nextLine()));
return board;
} catch (Exception 원본오류) {
throw new BoardException("게시물 입력 도중 오류 발생!", 원본오류);
}
}
public static void main(String[] args) {
try {
Board board = read();
// read() 메서드의 선언부를 보면, BoardException을 던진다고 되엉 있다.
System.out.println("---------------------");
System.out.printf("번호: %d\n", board.getNo());
System.out.printf("제목: %s\n", board.getTitle());
System.out.printf("내용: %s\n", board.getContent());
System.out.printf("등록일: %s\n", board.getCreatedDate());
}catch(BoardException ex) {
ex.printStackTrace();
}
}
}
public class ListException extends RuntimeException{
private static final long serialVersionUID = 1L ; // 나중에 설명...
public ListException() {
super();
// TODO Auto-generated constructor stub
}
public ListException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public ListException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public ListException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public ListException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}
/*
* 목록에서 인덱스에 해당하는 항목을 찾아 리턴한다.
* @param index 목록에 저장된 항목의 인덱스
* @return 목록에 저장된 항목의 인덱
* @throws ListException 인덱스가 무효함.
* */
public Object get(int index) throws ListException{
if(index <0 || index >= size) {
throw new ListException("인덱스가 무효합니다!");
}
return elementData[index];
}
public boolean remove(int index) /*throws ListException*/ {
if(index <0 || index >= size) {
throw new ListException("인덱스가 무효합니다!");
}
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 ListException{
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) {
for (int i = 0; i < size(); i++) {
Board board = (Board)super.get(i);
if (board.no == boardNo) {
return super.remove(i);
}
}
return false;
}
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(Exception ex) {
System.out.printf("예외 발생: %s\n", ex.getMessage());
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(Exception ex) {
System.out.println("입력 값이 옳지 않습니다!");
}