[F-lab 모각코 챌린지 20일차] TIL

JeongheeKim·2023년 6월 20일

TIL

목록 보기
20/66

예외와 에러

자바의 모든 에러와 예외는 Throwable 클래스를 상속받는다. 예외 발생 시 예외 클래스로 부터 객체를 생성한다.

  • 에러
    • 컴퓨터 하드웨어의 고장으로 인해 어플리케이션 실행 오류 발생하는것
      에러에 대해서는 대처 방법이 없다.
  • 예외
    • 예외란 잘못된 코딩으로 인한 오류. 단, 예외는 예외처리를 통해 어플리케이션 종료를 방지하고 계속 실행 상태를 유지할 수 있다

예외의 종류

checked exception

  • checked exception은 프로그램이 제어하기 힘든 에러라 한다.
  • java에서는 compile시 checked exception에 대해 체크한다.
  • exception처리하지 않은 경우 compile되지 않는다.
  • 예) FileNotFoundException, IOExceptionSQLException

unchecked exception

  • 모든 unchecked exception은 Runtime Exception을 상속 받았으며, 컴파일 시 체크되지 않아서 unchecked exception라는 이름이 붙었다.
  • 컴파일러가 예외처리하거나 선언하도록 강제하지 않는다.
  • runtime exception이라 불리며, 프로그래밍 error 이다.
  • 프로그램 로직에 문제가 발생하여 복구 할 수 없음을 뜻한다.
  • runtimeException을 상속받아 다양한 unchecked exception을 만들수 있다.
  • 예) NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException

예외 처리방식

try-catch block OR throws

checked exception에 대해 try-catch블록으로 exception발생시 로그를 statck trace를 남기고 다음 순서 로직을 수행하거나 throws 키워드를 통해 해당 메서드를 호출한 메서드로 exception에 대한 내용을 전달 할 수있다.

public class Test {
    public static void readFile() throws IOException {
        BufferedReader bw = new BufferedReader(new FileReader("myFile.txt"));
        int read = bw.read();
        System.out.println("read = " + read);
        bw.close();
    }

    public static void main(String[] args) {
        try {
            readFile();
            System.out.println("exception 이후1");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        System.out.println("exception 이후2");

    }
}
java.io.FileNotFoundException: myFile.txt (지정된 파일을 찾을 수 없습니다)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:216)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:111)
	at java.base/java.io.FileReader.<init>(FileReader.java:60)
	at Test.readFile(Test.java:6)
	at Test.main(Test.java:14)
exception 이후2

위의 코드를 실행했을때 checked exception으로 인해 compile이 실패했다.

  1. try-catch를 통해 예외 감싸기
    readFile1()에서 호출한 readFile2()에서 checked exception이 발생하면, readFile1()으로 exception이 전파되어 try-catch블록으로 exception을 감싸고 exception에 대한 메세지를 남길 수 있다.
public class Test {
	public static void readFile1() {
        try {
            readFile2();
        } catch (IOException e) {
            System.out.println("readFile2에서 발생 !!");
            throw new IOException(e);
        }
	    }
    public static void readFile2() throws IOException {
        boolean checked = true;
        if(checked) {
            throw new IOException();
        }
    }
    public static void main(String[] args) throws IOException {
        readFile1();
        System.out.println("exception 이후2");
    }
}
readFile2에서 발생 !!
Exception in thread "main" java.lang.RuntimeException: java.io.IOException
	at Test.readFile1(Test.java:18)
	at Test.main(Test.java:28)
Caused by: java.io.IOException
	at Test.readFile2(Test.java:24)
	at Test.readFile1(Test.java:15)
	... 1 more
  1. throws로 상위 메서드로 전달

    readFile2에서 발생한 exception은 readFile1로 전달되고 따로 exception처리가 되지않아 최상위 main메소드까지 전달된다.

    • throws
      • 상위 메소드 레벨로 예외를 전달할때 사용
    • throw
      • throw 키워드를 이용해서 고의로 예외 발생 시 사용
        throw new IllegalArgumentException();
public class Test {
    public static void readFile1() throws IOException {
        readFile2();
    }

    public static void readFile2() throws IOException {
        boolean checked = true;
        if(checked) {
            throw new IOException();
        }
    }
    public static void main(String[] args) throws IOException {
        readFile1();
        System.out.println("exception 이후2");
    }
}
Exception in thread "main" java.io.IOException
	at Test.readFile2(Test.java:20)
	at Test.readFile1(Test.java:6)
	at Test.main(Test.java:24)
  1. try-with-resources

try-with-resources는 try블록이 끝나면 자원을 반납하는 기능을 가진다. try구문안에 전달할 수 있는 자원은 AutoCloseable인터페이스 구현체로 제한된다. 이로써 finally 구문에서 자원을 반납하지 않아도 된다.

try-finally를 이용하여 exception 발생 순서를 확인하고자 한다.

static String firstLineOfFile(String path) throws IOException {
		BadBufferedReader br = new BadBufferedReader(new FileReader(path));
		try{
			return br.readLine();
		} finally {
			br.close();
		}
	}

	public static void main(String[] args) throws IOException {
		String path = "application.properties";
		System.out.println("firstLineOfFiel(path) = " + firstLineOfFile(path));
	}
public class BadBufferedReader extends BufferedReader {
	public BadBufferedReader(Reader in, int sz) {
		super(in, sz);
	}

	public BadBufferedReader(Reader in) {
		super(in);
	}

	@Override
	public String readLine() throws IOException {
		throw new CharConversionException();
	}

	@Override
	public void close() throws IOException {
		throw new StreamCorruptedException();
	}
}
Exception in thread "main" java.io.StreamCorruptedException
	at BadBufferedReader.close(BadBufferedReader.java:28)
	at Item9.firstLineOfFile(Item9.java:41)
	at Item9.main(Item9.java:47)

디버깅 시 제일 처음 발생한 exception을 확인해야하므로 중요한데, 맨 처음 발생한 exception이 찍히는것이 아닌 가장 마지막에 발생한 Exception이 stack trace에 찍히게 된다.

위의 문제는 java7에서 등장한 try-with-resource를 통해 해결된다.

static String firstLineOfFile(String path) throws IOException {
		try(BufferedReader br = new BufferedReader(new FileReader(path))) {//resource block setting
			return br.readLine();
		}
	}

	public static void main(String[] args) throws IOException {
		String path = args[0];
		System.out.println("firstLineOfFiel(path) = " + firstLineOfFile(path));
	}

try-with-resource 구문을 통해 exception발생 순서를 확인할 수 있다.

Exception in thread "main" java.io.CharConversionException
	at BadBufferedReader.readLine(BadBufferedReader.java:23)
	at Item9.firstLineOfFile(Item9.java:38)
	at Item9.main(Item9.java:44)
	Suppressed: java.io.StreamCorruptedException
		at BadBufferedReader.close(BadBufferedReader.java:28)
		at Item9.firstLineOfFile(Item9.java:37)
		... 1 more
static void firstLineOfFile(String path, String path2) throws IOException {
		try(InputStream in = new FileInputStream(path);
			OutputStream out = new FileOutputStream(path2)) {//resource block setting
			byte[] buf = new byte[8 * 1024];
			int n;
			while((n = in.read(buf)) >= 0)
				out.write(buf, 0,n);

		}
	}

	public static void main(String[] args) throws IOException {
		String path = args[0];
		String path2 = args[1];
		firstLineOfFile(path, path2);
	}

resource가 여러개일 경우 try-with-resource구문을 사용하면 try구문안에 사용할 자원을 넣어주면 코드도 깔금해지고 자원이 닫히는것이 보장된다.

0개의 댓글