ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] try with resources란?
    Language/Java 2020. 2. 27. 22:40
    728x90
    반응형

    자바를 이용해 외부 자원에 접근하는 경우 주의해야할 점은 외부자원을 사용한 뒤 반납을 해줘야 한다는 점이다.

     

    1. 자원 반납과 finally

    1-1) 자원반납 문제 

    1
    2
    3
    4
    변수1 = new 자원객체1();  // 자원 할당
    변수1.작업();
    변수1.close();             // 자원 반납
     
     
     

    위 코드에서 작업() 메소드가 에러없이 실행된 경우라면 close() 메소드가 정상적으로 작동해서 자원을 반납한다.

    하지만 작업() 메소드에서 에러가 발생한다면 close( 메소드가 실행되지 않아서 자원이 반납하지 못하는 문제가 생긴다.

     

     

     

    1-2) finally 블럭에서 자원 반납

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    변수1 = null;
    변수2 = null;
    try {
       변수1 = new 자원객체1();
       변수2 = new 자원객체2();
       변수1.작업();
       변수2.작업();
       ...
    finally {
       if (변수1 != null) 변수1.close();
       if (변수2 != null) 변수2.close();
    }
     
     
     

    위처럼 finally 안에 close() 메소드를 쓰게 되면 finally는 에러와 관계없이 항상 실행되기 때문에 자원 반납이 가능해진다.

     

     

     

    2. try with resource 문법과 자원 반납

    자바 1.7에 추가된 try with resource 문법을 사용하면 훨씬 간결하게 자원 반납 문제를 해결할 수 있다.

     

    2-1) try wih resource 문법

    1
    2
    3
    4
    try (변수1 = new 자원객체1()) {
        ...
    }
     

    try with resource부터는 try 안에서 자원할당을 하면 자동으로 close() 메소드가 호출이 되기 때문에 finally 블록을 생략해도 된다. 

     

    1
    2
    3
    4
    5
    try (변수1 = new 자원객체1();
         변수2 = new 자원객체2()) {
        ...
    }
     
     

    자원할당이 여러개라면 위와 같이 구현한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    try (변수1 = new 자원객체1();
         변수2 = new 자원객체2()) {
        ...
        try (변수3 = new 자원객체3()) {
            ...
        }
    }
     
     

    try문장을 중첩하여 사용할 수도 있다.

     

    실행흐름이 try 블럭을 빠져 나갈 때, 자원객체의 close 메소드가 자동으로 호출된다. exception이 발생해서 실행흐름이 점프할 때에서, 자원객체의 close 메소드는 반드시 자동으로 호출된다. (자세한건 아래에 다시 설명한다)

     

     

    예제 코드와 함께 이해해보자 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import java.io.BufferedReader;
    import java.io.FileReader;
     
    public class Example1 {
     
        static void printFile(String 파일명) throws Exception {
            BufferedReader reader = new BufferedReader(new FileReader(파일명));
            String s;
            while ((s = reader.readLine()) != null) {
                System.out.println(s);
            }
            reader.close();
        }
     
        public static void main(String[] args) throws Exception {
            String 파일명 = "e:/temp/테스트.txt";
            printFile(파일명);
        }
    }
     
     
     

    만약 printFile 메소드를 실행하는 도중에 에러가 발생한다면 close() 메소드를 실행할 수 없기 때문에 자원 반납을 하지 못하는 문제가 발생한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import java.io.BufferedReader;
    import java.io.FileReader;
     
    public class Example2 {
     
        static void printFile(String 파일명) throws Exception {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(파일명));
                String s;
                while ((s = reader.readLine()) != null) {
                    System.out.println(s);
                }
            } finally {
                if (reader != null) reader.close();
            }
        }
     
        public static void main(String[] args) throws Exception {
            String 파일명 = "e:/temp/테스트.txt";
            printFile(파일명);
        }
    }
     
     
     

    이번 코드는 try ~ finally를 이용한 것이다. finally는 에러가 발생해도 반드시 실행되기 때문에 자원 반납이 가능하다.

     

     

    그러면 어떻게 try wtih resource를 썼다고 자원 반납을 자동으로 하는것일까?

    일단 먼저 생각할 것은 try() 안에 들어올 수 있는 것은 AutoCloseable 구현체뿐이다. 

    AutoCloseable 인터페이스 안에 close() 메소드가 존재한다. 따라서 AutoCloseable 인터페이스를 구현한 클래스는 close() 메소드를 구현해야 한다. 

     

    다음 예제 코드를 보자

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class MyResource implements AutoCloseable {
        public void MyResource() {
            System.out.println("자원이 할당됨");
        }
     
        public void 작업() throws Exception {
            System.out.println("작업 중 에러 발생");
            throw new Exception();
        }
     
        @Override
        public void close() throws Exception {
            System.out.println("자원이 반납됨");
        }
    }
     
     
    public class Example4 {
     
        public static void main(String[] args) throws Exception {
            try (MyResource resource = new MyResource()) {
                resource.작업();
            }
        }
    }
     
     
     

    위의 코드를 실행하면 close() 메소드가 실행되어 "자원이 반납됨" 이 출력되는 것을 확인할 수 있다. 

    반응형

    댓글

Designed by Tistory.