에러와 예외
예외 클래스의 계층
checked Exception
unchecked exception
예외의 발생
public class SimpleException {
public static void main(String[] args) {
int[] intArray = { 10 };
System.out.println(intArray[2]);
System.out.println("프로그램 종료합니다.");
}
}
런타임 오류 발생 : 컴파일은 됨 (unchecked Exception)
다음과 같이 수정 가능하다.
public class SimpleException {
public static void main(String[] args) {
int[] intArray = { 10 };
try {
System.out.println(intArray[2]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("예외 발생");
e.print
}
System.out.println("프로그램 종료합니다.");
}
}
public class SimpleException {
public static void main(String[] args) {
int[] intArray = { 10 };
try {
System.out.println(intArray[2]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.printf("예외 발생 %s", e.getMessage());
e.printStackTrace();
}
System.out.println("프로그램 종료합니다.");
}
}
public class ExceptionHandlingFlow {
public static void main(String[] args) {
int num = new Random().nextInt(2);
try {
System.out.println("code 1, num: " + num);
int i = 1 / num;
System.out.println("code 2 - 예외 없음: " + i);
return;
} catch (ArithmeticException e) {
System.out.println("code 3 - exception handling 완료");
}
System.out.println("code 4");
}
}
try 블록에서 여러 종류의 예외가 발생할 경우
public class MultiExceptionHandling {
@SuppressWarnings("resource")
public static void main(String[] args) {
// TODO: 다음에서 발생하는 예외를 처리해보자.
try {
Class.forName("abc.Def"); // ClassNotFoundException
new FileInputStream("Hello.java"); // FileNotFoundException
DriverManager.getConnection("Hello"); // SQLException
} catch(ClassNotFoundException e) {
System.out.printf("클래스를 찾을 수 없습니다.: %s\n", e.getMessage());
}catch(FileNotFoundException e) {
System.out.printf("파일을 찾을 수 없습니다.: %s\n", e.getMessage());
} catch(SQLException e) {
System.out.printf("DB를 찾을 수 없습니다.: %s\n", e.getMessage());
} finally {
System.out.println("모든 예외 처리 완료");
}
// END
System.out.println("프로그램 정상 종료");
}
}
다중 catch 문장 작성 순서 유의 사항
발생하는 예외들을 하나로 처리
심각하지 않은 예외를 굳이 세분화 해서 처리하는 것도 낭비
I
를 사용해 하나의 catch 구문에서 상속관계가 없는 여러 개의 exception 처리
public class MultiExceptionHandling {
@SuppressWarnings("resource")
public static void main(String[] args) {
// TODO: 다음에서 발생하는 예외를 처리해보자.
try {
Class.forName("abc.Def"); // ClassNotFoundException
new FileInputStream("Hello.java"); // FileNotFoundException
DriverManager.getConnection("Hello"); // SQLException
} catch(ClassNotFoundException | FileNotFoundException e) {
System.out.printf("자원을 찾을 수 없습니다.: %s\n", e.getMessage());
} catch(SQLException e) {
System.out.printf("DB를 찾을 수 없습니다.: %s\n", e.getMessage());
} finally {
System.out.println("모든 예외 처리 완료");
}
// END
System.out.println("프로그램 정상 종료");
}
}
public class HierachyException {
@SuppressWarnings("resource")
public static void main(String[] args) {
String src = "./.project";
// TODO: 상속 관계를 고려하여 다음에서 예외를 처리해보자.
try {
FileInputStream input = new FileInputStream(src);
int readData = -1;
while ((readData = input.read()) != -1) {
System.out.print((char) readData);
}
} catch(FileNotFoundException e) {
System.out.printf("읽으려는 파일이 없습니다. : %s", e.getMessage());
} catch (IOException e) {
System.out.printf("파일 읽기에 실패해습니다. : %s", e.getMessage());
}
// END
System.out.println("파일 읽음 완료!");
}
}
public class ExceptionHandlingFlow {
public static void main(String[] args) {
int num = new Random().nextInt(2);
try {
System.out.println("code 1, num: " + num);
int i = 1 / num;
System.out.println("code 2 - 예외 없음: " + i);
return;
} catch (ArithmeticException e) {
System.out.println("code 3 - exception handling 완료");
} finally {
System.out.println("code 4 - 언제나 실행");
}
System.out.println("code 5");
}
}
public class InstallApp {
void copy() {
System.out.println("파일 복사");
}
void install() throws Exception {
System.out.println("설치");
if (Math.random() > 0.5) {
throw new Exception();
}
}
void delete() {
System.out.println("파일 삭제");
}
}
public class InstallApp {
void copy() {
System.out.println("파일 복사");
}
void install() throws Exception {
System.out.println("설치");
if (Math.random() > 0.5) {
throw new Exception();
}
}
void delete() {
System.out.println("파일 삭제");
}
}
를 다음과 같이 변경할 수 있다.
public class InstallAppTest {
public static void main(String[] args) {
InstallApp app = new InstallApp();
try {
app.copy();
//app.delete();
} catch(Exception e) {
//app.delete();
e.printStackTrace();
} finally {
app.delete();
}
}
}
주요 목적 : try 블록에서 사용한 리소스 반납
생성한 시스템 자원을 반납하지않으면 장래 resource leak 발생 가능 -> close처리
public void useStream() {
FileInputStream fileInput = null;
try {
fileInput = new FileInputStream("abc.txt");
fileInput.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInput != null) {
try {
fileInput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void useStreamNewStye() {
// TODO: useStream을 try~with~resource 문장으로 변경하세요.
try(FileInputStream input = new FileInputStream("abc.txt");){
input.read();
}catch(FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
// END
}
checked exception과 throws
public class ThrowsTest {
// TODO: 1. methodCall2()에서 uncheckedExceptionMethod()를 호출할 때 발생하는 예외를
// throws로 처리하세요.
// TODO: 2. methodCall2()에서 checkedExceptionMethod()를 호출할 때 발생하는 예외를
// throws로 처리하세요.
public static void main(String[] args){
try {
methodCall1();
} catch(ClassNotFoundException e){
e.printStackTrace();
} catch (ArithmeticException e) {
e.printStackTrace();
}
System.out.println("done");
}
private static void methodCall1()throws ClassNotFoundException {
methodCall2();
}
private static void methodCall2()throws ClassNotFoundException {
uncheckedExceptionMethod();
checkedExceptionMethod();
}
@SuppressWarnings("unused")
private static void checkedExceptionMethod() throws ClassNotFoundException {
Class.forName("Hello");
}
@SuppressWarnings("unused")
private static void uncheckedExceptionMethod() {
int i = 1 / 0;
}
}
메서드 재정의 시 조상 클래스 메서드가 던지는 예외보다 부모예외를 던질 수 없다.
class Parent{
void methodA() throws IOException{}
void methodB() throws ClassNotFoundException{}
}
public clas OverridingTest extends Parent{
@Override
void methodA() throws FileNotFoundException{
}
@Override
void methodB() throws Exception{
//더 넓은 Exception을 처리하려고 하므로 오류
}
}
하위 계층에서 발생한 예외는 상위계층에 맞는 예외로 바꿔서 던져야 한다.
Exception Chaining
public class ExceptionChaining {
public static void main(String[] args) {
OnlineShop shop = new OnlineShop();
// TODO: 03. shop을 통해 주문해보자.
shop.order();
// END
System.out.println("상품 주문 사용 완료!");
}
}
class OnlineShop {
public void order() {
// TODO: 02. 주문 처리 과정에서 발생하는 예외를 처리하고 IllegalStateException을 발생시켜보자.
try {
packaging();
delivery();
System.out.println("상품이 정상적으로 배송 되었습니다.");
} catch(RuntimeException e) {
new IllegalStateException(e); //chaining
}
// END
}
private void packaging() {
System.out.println("상품을 포장합니다.");
}
private void delivery() {
deliveryToWareHouse();
deliveryToCustomer();
}
private void deliveryToWareHouse() {
System.out.println("물류 창고로 배송합니다.");
}
private void deliveryToCustomer() {
System.out.println("고객에게 배송합니다.");
// TODO: 01. 임의로 RuntimeException 계열의 예외를 발생시켜 보자.
throw new RuntimeException("도로가 결빙입니다.");
// END
}
}