ใช้ปิดได้หรือใช้ AutoCloseable


129

ฉันอยู่ระหว่างการเรียนรู้ Java และฉันไม่พบคำอธิบายที่ดีเกี่ยวimplements Closeableกับimplements AutoCloseableอินเทอร์เฟซและอินเทอร์เฟซ

เมื่อผมดำเนินการinterface Closeable, Eclipse IDE public void close() throws IOExceptionของฉันสร้างวิธีการ

ฉันสามารถปิดสตรีมโดยpw.close();ไม่ใช้อินเทอร์เฟซได้ แต่ฉันไม่เข้าใจว่าฉันจะใช้close()วิธีนี้โดยใช้อินเทอร์เฟซได้อย่างไร และจุดประสงค์ของอินเทอร์เฟซนี้คืออะไร?

นอกจากนี้ฉันต้องการทราบ: ฉันจะตรวจสอบได้อย่างไรว่าIOstreamถูกปิดจริง ๆ หรือไม่?

ฉันใช้รหัสพื้นฐานด้านล่าง

import java.io.*;

public class IOtest implements AutoCloseable {

public static void main(String[] args) throws IOException  {

    File file = new File("C:\\test.txt");
    PrintWriter pw = new PrintWriter(file);

    System.out.println("file has been created");

    pw.println("file has been created");

}

@Override
public void close() throws IOException {


}

2
ผมคิดว่าทุกคนได้รับแล้วกล่าวว่า แต่บางทีคุณอาจมีความสนใจในบทความต่อไปนี้เกี่ยวกับลองสารสนเทศ: docs.oracle.com/javase/tutorial/essential/exceptions/... สิ่งนี้อาจเป็นประโยชน์ในการทำความเข้าใจคำตอบที่ระบุ
crusam

คำตอบ:


41

สำหรับฉันแล้วดูเหมือนว่าคุณจะไม่ค่อยคุ้นเคยกับอินเทอร์เฟซ AutoCloseableในรหัสที่คุณได้โพสต์ที่คุณไม่จำเป็นต้องใช้

คุณจะต้อง (หรือควร) นำไปใช้CloseableหรือAutoCloseableถ้าคุณกำลังจะใช้งานของคุณเองPrintWriterซึ่งจะจัดการไฟล์หรือทรัพยากรอื่น ๆ ที่จำเป็นต้องปิด

pw.close()ในการดำเนินงานของคุณก็พอที่จะเรียก คุณควรทำสิ่งนี้ในบล็อกสุดท้าย:

PrintWriter pw = null;
try {
   File file = new File("C:\\test.txt");
   pw = new PrintWriter(file);
} catch (IOException e) {
   System.out.println("bad things happen");
} finally {
   if (pw != null) {
      try {
         pw.close();
      } catch (IOException e) {
      }
   }
}

โค้ดด้านบนเกี่ยวข้องกับ Java 6 ใน Java 7 สามารถทำได้อย่างหรูหรามากขึ้น (ดูคำตอบนี้ )


3
ทำไมต้องใช้ a PrintWriter? โดยเฉพาะอย่างยิ่งAutoClosableวัตถุสามารถนำมาใช้ในหลาย ๆ สถานการณ์ได้มากกว่าเพียงPrintWriter...
glglgl

3
คุณมีสิทธิ์อย่างแน่นอน คำถามนั้นเกี่ยวกับPrintWriterฉันจึงพูดถึงคำถามนี้ให้เจาะจง
ไก่

7
เหตุใดจึงอธิบายสถานการณ์สำหรับ Java 6 ในบริบทของAutoCloseable? โชว์try-with-resourcesแทนดีกว่า…
ᴠɪɴᴄᴇɴᴛ

191

AutoCloseable(แนะนำใน Java 7) ทำให้สามารถใช้สำนวนtry-with-resources :

public class MyResource implements AutoCloseable {

    public void close() throws Exception {
        System.out.println("Closing!");
    }

}

ตอนนี้คุณสามารถพูดว่า:

try (MyResource res = new MyResource()) {
    // use resource here
}

และ JVM จะโทรclose()หาคุณโดยอัตโนมัติ

Closeable เป็นอินเทอร์เฟซรุ่นเก่า ด้วยเหตุผลบางอย่างเพื่อรักษาความเข้ากันได้แบบย้อนหลังนักออกแบบภาษาจึงตัดสินใจสร้างแบบแยกต่างหาก นี้จะช่วยให้ไม่เพียง แต่ทุกCloseableชั้นเรียน (เช่นการขว้างปาลำธารIOException) เพื่อใช้ในการลองกับทรัพยากร close()แต่ยังช่วยให้การขว้างปาข้อยกเว้นการตรวจสอบทั่วไปเพิ่มเติมจาก

หากมีข้อสงสัยให้ใช้AutoCloseableผู้ใช้ในชั้นเรียนของคุณจะขอบคุณ


107
เหตุผลง่ายๆคือ: พ่นCloseable.close() IOExceptionจำนวนมากของclose()วิธีการที่จะได้รับประโยชน์จากการลองกับทรัพยากรโยนข้อยกเว้นการตรวจสอบอื่น ๆ (เช่นjava.sql.Connection.close()เพื่อAutoCloseable.close()พ่นExceptionเปลี่ยนที่มีอยู่. Closeableสัญญาจะทำให้การใช้งานที่มีอยู่ทั้งหมด / ห้องสมุดอาศัยในสัญญาที่close()เพียงพ่นIOExceptionและไม่ทั้งหมด (การตรวจสอบข้อยกเว้น).
มาร์ค Rotteveel

4
@MarkRotteveel: +1 ขอบคุณครับ ฉันแก้ไขคำตอบเพื่อให้สอดคล้องกับข้อเสนอแนะและความคิดเห็นของคุณ
Tomasz Nurkiewicz

9
และยัง: Closeable.close()เป็นสิ่งที่จำเป็นต้องมี AutoCloseable.close()ไม่ใช่แม้ว่าจะยังคงแนะนำอย่างยิ่ง
Lukas Eder

2
นอกจากนี้อย่าใช้ค่าเริ่มต้นpublic void close( ) throws Exception- ใช้ข้อยกเว้นที่เฉพาะเจาะจงมากขึ้นหากคุณสามารถทำได้ (เช่น IOException)
gerardw

3
Closeableไม่รับประกันความเป็นส่วนตัว มันต้อง idempotence ในการดำเนินงานของผู้ใช้ของclose()วิธีการ และIOExceptionความเฉพาะเจาะจง / เหมาะสมขึ้นอยู่กับกรณีการใช้งาน
xdhmoore

71

CloseableขยายAutoCloseableและทุ่มเทให้กับสตรีม IO โดยเฉพาะ: มันพ่น IOException แทน Exception และเป็นสิ่งที่ไม่คาดคิดในขณะที่ AutoCloseable ไม่ได้ให้การรับประกันนี้

ทั้งหมดนี้อธิบายไว้ใน javadoc ของทั้งสองอินเตอร์เฟส

การใช้ AutoCloseable (หรือ Closeable) ช่วยให้สามารถใช้คลาสเป็นทรัพยากรของโครงสร้างแบบลองใช้กับทรัพยากรที่นำมาใช้ใน Java 7 ซึ่งช่วยให้สามารถปิดทรัพยากรดังกล่าวโดยอัตโนมัติเมื่อสิ้นสุดบล็อกโดยไม่ต้องเพิ่มบล็อกสุดท้ายที่ปิด ทรัพยากรอย่างชัดเจน

ชั้นเรียนของคุณไม่ได้เป็นตัวแทนของทรัพยากรที่สามารถปิดได้และไม่มีประเด็นใด ๆ ในการนำอินเทอร์เฟซนี้ไปใช้: IOTest ไม่สามารถปิดได้ ไม่ควรเป็นไปได้ที่จะสร้างอินสแตนซ์ด้วยซ้ำเนื่องจากไม่มีวิธีอินสแตนซ์ใด ๆ โปรดจำไว้ว่าการใช้อินเตอร์เฟซหมายถึงว่ามีความเป็นแบบความสัมพันธ์ระหว่างการเรียนและอินเตอร์เฟซ คุณไม่มีความสัมพันธ์ดังกล่าวที่นี่


5
เพียงใช้Closableสำหรับคลาสที่เกี่ยวข้องกับสตรีมและAutoClosableสำหรับคนอื่น ๆ ที่ต้องใช้คุณสมบัติปิดอัตโนมัติ
lospejos

7

นี่คือตัวอย่างเล็ก ๆ

public class TryWithResource {

    public static void main(String[] args) {
        try (TestMe r = new TestMe()) {
            r.generalTest();
        } catch(Exception e) {
            System.out.println("From Exception Block");
        } finally {
            System.out.println("From Final Block");
        }
    }
}



public class TestMe implements AutoCloseable {

    @Override
    public void close() throws Exception {
        System.out.println(" From Close -  AutoCloseable  ");
    }

    public void generalTest() {
        System.out.println(" GeneralTest ");
    }
}

นี่คือผลลัพธ์:

GeneralTest 
From Close -  AutoCloseable  
From Final Block

จะเป็นการดีกว่าที่จะเขียนผลลัพธ์ด้วยดังนั้นจึงไม่จำเป็นต้องมีโครงการทดลองสำหรับโค้ดสั้น ๆ เช่นนี้
raxetul

ในวิธีการปิด () เราไม่จำเป็นต้องปิดทรัพยากรอย่างชัดเจนใช่หรือไม่? มีเพียงคำสั่งพิมพ์เท่านั้น
Shailesh Waghmare

@ShaileshWaghmare ใช่ค่ะ แต่เพื่อวัตถุประสงค์ในการทดสอบฉันได้กล่าวถึงใน Code snip
Lova Chittumuri

@LovaChittumuri มันจะเหมือนthis.close()หรืออะไรในรหัสเพราะมันถูกเรียกโดยอัตโนมัติ (เพื่อให้แน่ใจ)
Shailesh Waghmare

@shailesh Waghmare คุณต้องการทดสอบฉัน
Lova Chittumuri

6

try-with-resourcesงบ

try-with-resources statementเป็นtryคำสั่งที่ประกาศหนึ่งหรือมากกว่าทรัพยากร A resourceคือออบเจ็กต์ที่ต้องปิดหลังจากโปรแกรมเสร็จสิ้น try-with-resources statementเพื่อให้แน่ใจว่าแต่ละทรัพยากรปิดท้ายของคำสั่ง อ็อบเจ็กต์ใด ๆ ที่ใช้งานjava.lang.AutoCloseableซึ่งรวมถึงอ็อบเจ็กต์ทั้งหมดที่ใช้งานjava.io.Closeableสามารถใช้เป็นทรัพยากรได้

ตัวอย่างต่อไปนี้อ่านบรรทัดแรกจากไฟล์ ใช้อินสแตนซ์ในBufferedReaderการอ่านข้อมูลจากไฟล์ BufferedReaderเป็นทรัพยากรที่ต้องปิดหลังจากโปรแกรมเสร็จสิ้น:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

ในตัวอย่างนี้ทรัพยากรที่ประกาศในคำสั่ง try-with-resources คือ BufferedReader คำสั่งประกาศจะปรากฏในวงเล็บทันทีหลังจากคำสำคัญลอง ชั้นBufferedReaderใน Java SE 7 java.lang.AutoCloseableและต่อมาการดำเนินการอินเตอร์เฟซ เนื่องจากBufferedReaderมีการประกาศอินสแตนซ์ในคำสั่ง try-with-resource อินสแตนซ์จะถูกปิดไม่ว่าคำสั่ง try จะเสร็จสมบูรณ์ตามปกติหรือในทันที (อันเป็นผลมาจากวิธีการBufferedReader.readLineขว้างปาIOException)

ก่อน Java SE 7 คุณสามารถใช้finallyบล็อกเพื่อให้แน่ใจว่าทรัพยากรถูกปิดโดยไม่คำนึงว่าคำสั่ง try จะเสร็จสมบูรณ์ตามปกติหรือในทันที ตัวอย่างต่อไปนี้ใช้finallyบล็อกแทนtry-with-resourcesคำสั่ง:

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }

}

โปรดอ้างถึงเอกสาร


6

เมื่อเร็ว ๆ นี้ฉันได้อ่านหนังสือ Java SE 8 Programmer Guide ii

ฉันพบบางอย่างเกี่ยวกับความแตกต่างระหว่างAutoCloseableกับCloseable.

AutoCloseableอินเตอร์เฟซที่เป็นที่รู้จักใน Java 7. Closeableก่อนที่อินเตอร์เฟซอีกดำรงอยู่เรียกว่า คล้ายกับสิ่งที่นักออกแบบภาษาต้องการโดยมีข้อยกเว้นดังต่อไปนี้:

  • Closeableจำกัด IOExceptionประเภทของข้อยกเว้นโยนไป
  • Closeable ต้องมีการนำไปใช้งานที่มีศักยภาพ

นักออกแบบภาษาเน้นความเข้ากันได้ย้อนหลัง AutoCloseableนับตั้งแต่การเปลี่ยนแปลงอินเตอร์เฟซที่มีอยู่เป็นที่ไม่พึงประสงค์ที่พวกเขาทำอย่างใดอย่างหนึ่งใหม่ที่เรียกว่า Closeableอินเตอร์เฟซใหม่นี้เป็นที่เข้มงวดน้อยกว่า เนื่องจากCloseableเป็นไปตามข้อกำหนด AutoCloseableจึงเริ่มใช้งานAutoCloseableเมื่อมีการเปิดตัวหลัง


1
แทนที่จะพูดว่า "อินเทอร์เฟซใหม่นี้เข้มงวดน้อยกว่าCloseable" ฉันขอแนะนำให้พูดว่า "อินเทอร์เฟซใหม่นี้สามารถใช้ในบริบททั่วไปได้มากขึ้นโดยที่ข้อยกเว้นที่เกิดขึ้นระหว่างการปิดไม่จำเป็นต้องเป็น IOException" ในจักรวาล Java การ "เข้มงวดน้อยกว่า" มีความรู้สึกเชิงลบเกี่ยวกับเรื่องนี้
Fountainhead
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.