programing

AutoCloseable을 사용하여 여러 리소스 닫기 (리소스로 시도)

procenter 2021. 1. 14. 23:21
반응형

AutoCloseable을 사용하여 여러 리소스 닫기 (리소스로 시도)


시도를 통해 전달한 리소스는 리소스에 AutoCloseable이 구현 된 경우 자동으로 닫힙니다. 여태까지는 그런대로 잘됐다. 하지만 자동으로 닫 히려는 리소스가 여러 개있을 때 어떻게해야합니까? 소켓이있는 예;

try (Socket socket = new Socket()) {
    input = new DataInputStream(socket.getInputStream());
    output = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
} 

그래서 소켓이 제대로 닫힐 것이라는 것을 압니다. 이것은 try에서 매개 변수로 전달되기 때문입니다. 그러나 어떻게 입력과 출력이 제대로 닫혀 야할까요?


Try with resources는 괄호 안에 모두 선언하여 여러 리소스와 함께 사용할 수 있습니다. 문서 보기

링크 된 문서에서 발췌 한 관련 코드 :

public static void writeToFileZipFileContents(String zipFileName,
                                           String outputFileName)
                                           throws java.io.IOException {

    java.nio.charset.Charset charset =
         java.nio.charset.StandardCharsets.US_ASCII;
    java.nio.file.Path outputFilePath =
         java.nio.file.Paths.get(outputFileName);

    // Open zip file and create output file with 
    // try-with-resources statement

    try (
        java.util.zip.ZipFile zf =
             new java.util.zip.ZipFile(zipFileName);
        java.io.BufferedWriter writer = 
            java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
    ) {
        // Enumerate each entry
        for (java.util.Enumeration entries =
                                zf.entries();     entries.hasMoreElements();) {
            // Get the entry name and write it to the output file
            String newLine = System.getProperty("line.separator");
            String zipEntryName =
                 ((java.util.zip.ZipEntry)entries.nextElement()).getName() 
             newLine;
            writer.write(zipEntryName, 0, zipEntryName.length());
        }
    }
}

객체가 구현되지 않거나 AutoClosable( DataInputStreamdoes), try-with-resources 전에 선언되어야 하는 경우 해당 객체 를 닫을 적절한 위치 finally는 링크 된 문서에서도 언급 된 블록입니다.


걱정하지 마세요. 에서 소켓의 설명서 :

이 소켓을 닫으면 소켓의 InputStream 및 OutputStream도 닫힙니다.

close()입력 및 출력 개체를 명시 적으로 호출하지 않는 것에 대한 귀하의 우려를 이해 하며 실제로 다음과 같이 모든 리소스가 try-with-resources블록에 의해 자동으로 관리되도록하는 것이 일반적으로 더 좋습니다 .

try (Socket socket = new Socket();
     InputStream input = new DataInputStream(socket.getInputStream());
     OutputStream output = new DataOutputStream(socket.getOutputStream());) {
} catch (IOException e) {
} 

이것은 소켓 객체가 "여러 번 닫히는"효과를 가지지 만 아무런 해를 끼치 지 않아야합니다 (이것은 일반적으로 모든 구현이 close()멱 등성을 갖도록 권장되는 이유 중 하나입니다 ).


위의 답변 외에도 Java 9에 추가 된 개선 사항입니다.

Java 9 try-with-resources는 향상된 코드 작성 방법을 제공합니다. 이제 try 블록 외부에서 변수를 선언하고 try 블록 내부에서 직접 사용할 수 있습니다. 이로 인해 다음과 같은 이점을 얻을 수 있습니다.

  • try (효과적으로 최종 또는 최종) 외부에서 선언 한 리소스는 try 블록에 추가하기 만하면 자동 리소스 관리에 의해 자동으로 닫힐 수 있습니다.
    • try 블록 외부에서 선언 된 객체를 다시 참조하거나 Java 7에서 수행해야하는 것처럼 수동으로 닫을 필요가 없습니다.
    • 또한 깨끗한 코드를 작성하는 데 도움이됩니다.

try-with-resource 우리는 Java 9에서 이렇게 작성할 수 있습니다.

public void loadDataFromDB() throws SQLException {
Connection dbCon = DriverManager.getConnection("url", "user", "password");
try (dbCon; ResultSet rs = dbCon.createStatement().executeQuery("select * from emp")) {
    while (rs.next()) {
        System.out.println("In loadDataFromDB() =====>>>>>>>>>>>> " + rs.getString(1));
    }
} catch (SQLException e) {
    System.out.println("Exception occurs while reading the data from DB ->" + e.getMessage());
}

}

여기서 자동 리소스 관리는 dbCon & rs 개체를 자동으로 닫습니다.

위의 정의 사용 사례 목록을 더 잘 이해하려면 Java 7 코드를 찾으십시오.

예 1 :

public void loadDataFromDB() throws SQLException {
Connection dbCon = DriverManager.getConnection("url", "user", "password");
try (ResultSet rs = dbCon.createStatement().executeQuery("select * from emp")) {
    while (rs.next()) {
        System.out.println("In loadDataFromDB() =====>>>>>>>>>>>> " + rs.getString(1));
    }
} catch (SQLException e) {
    System.out.println("Exception occurs while reading the data from DB ->" + e.getMessage());
} finally {
    if (null != dbCon)
        dbCon.close();
}

}

예 2 :

// BufferedReader is declared outside try() block
    BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt"));

    try (BufferedReader inBr = br) {
            // ...
        }
    } catch (IOException e) {
        // ...
    }

위의 샘플에서 개체가 ouside인지 확인한 다음 수동으로 닫거나 다시 참조해야합니다. 또한 try 블록에 여러 개체가있는 경우에는 지저분 해 보이며 try 내부에서 선언하더라도 try 블록 외부에서는 사용할 수 없습니다.


위의 답변은 훌륭하지만 try-with-resources가 도움이되지 않는 경우가 있습니다.

이 코드 예제를 살펴보십시오.

private static byte[] getFileBytes(Collection<String> fileContent) throws CustomServiceException {
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(baos))) {
            for (String fileLine : fileContent) {
                writer.append(fileLine);
                writer.newLine();
            }
        }
        return baos.toByteArray();
    } catch (IOException e) {
        throw new CustomServiceException(SC_INTERNAL_SERVER_ERROR, "Unable to serialize file data.");
    }
}

In this example u can't just use try-with-resources block cause writer has to flush the output buffer to the underlying character stream so placing writer into try-with-resources block won't do the trick and method will return empty array.

ReferenceURL : https://stackoverflow.com/questions/30553139/close-multiple-resources-with-autocloseable-try-with-resources

반응형