에러와 예외

예외 클래스의 계층

checked Exceptionunchecked 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
}
}
