วิธีใช้ Try With Resource ใน Java

Feb 21 2023
วิธีจัดการกับข้อยกเว้นโดยใช้คำสั่ง try-with-resource โครงสร้าง Java try with resource หรือเรียกอีกอย่างว่า Java try-with-resources เป็นกลไกการจัดการข้อยกเว้นที่สามารถปิดทรัพยากรโดยอัตโนมัติ เช่น Java InputStream หรือการเชื่อมต่อ JDBC เมื่อคุณดำเนินการเสร็จสิ้น . Oracle ได้เพิ่มการลองใช้ด้วยการสร้างทรัพยากรให้กับภาษา Java ในปี 2554 เพื่อช่วยรับประกันว่าออบเจกต์ต่างๆ เช่น ซ็อกเก็ตเครือข่าย การเชื่อมต่อฐานข้อมูล และการอ้างอิงไปยังไฟล์และโฟลเดอร์จะถูกยกเลิกอย่างสมบูรณ์หลังการใช้งาน

วิธีจัดการข้อยกเว้นโดยใช้คำสั่ง try-with-resource

โครงสร้าง Java try with resourceหรือที่เรียกว่าJava try-with-resourcesเป็นกลไกจัดการข้อยกเว้นที่สามารถปิดรีซอร์สโดยอัตโนมัติ เช่น Java InputStream หรือ JDBC Connection เมื่อคุณดำเนินการเสร็จสิ้น

Oracle ได้เพิ่มการลองใช้ด้วยการสร้างทรัพยากรให้กับภาษา Java ในปี 2554 เพื่อช่วยรับประกันว่าออบเจกต์ต่างๆ เช่น ซ็อกเก็ตเครือข่าย การเชื่อมต่อฐานข้อมูล และการอ้างอิงไปยังไฟล์และโฟลเดอร์จะถูกยกเลิกอย่างสมบูรณ์หลังการใช้งาน การไม่สามารถปิดทรัพยากรเหล่านี้หลังจากที่นักพัฒนาเปิดที่จับอาจทำให้หน่วยความจำรั่ว ทริก เกอร์รูทีนการรวบรวมขยะที่หลีกเลี่ยงได้และทำให้ CPU ของเซิร์ฟเวอร์เครียด

· ก่อน Java 7
· จะใช้คำสั่ง try-with-resource ได้อย่างไร?
· เหตุใดฉันจึงต้องใช้คำสั่ง try-with-resource?
· ตัวอย่าง
· ข้อยกเว้นที่ถูกระงับ
· ข้อดีของการใช้ try-with-resources
· try-with-resources ด้วยหลาย Resources
· Java 9 — ตัวแปรสุดท้ายที่มีประสิทธิภาพ

ก่อน Java 7

ใน Java หากคุณใช้รีซอร์ส เช่น สตรีมอินพุตหรือเอาท์พุต คุณต้องปิดรีซอร์สทุกครั้งหลังใช้งาน นอกจากนี้ยังสามารถส่งข้อยกเว้นดังนั้นจึงต้องอยู่ในบล็อกtry-catch การปิดจะต้องอยู่ในบล็อกสุดท้าย นี่เป็นวิธีที่น้อยที่สุดจนถึง Java 7 สิ่งนี้มีข้อเสียหลายประการ:

  • คุณต้องตรวจสอบว่าทรัพยากรของคุณเป็นโมฆะหรือไม่ก่อนที่จะปิด
  • การปิดตัวเองอาจทำให้เกิดข้อยกเว้น ดังนั้นในที่สุด คุณ จึงต้องมีtry-catch อีกครั้ง
  • โปรแกรมเมอร์มักจะลืมปิดทรัพยากรของตน

จะใช้คำสั่ง try-with-resource ได้อย่างไร?

มันถูกเปิดตัวครั้งแรกใน Java 7 และแนวคิดทั้งหมดที่อยู่เบื้องหลังคือนักพัฒนาไม่จำเป็นต้องกังวลเกี่ยวกับการจัดการทรัพยากรสำหรับทรัพยากรที่ใช้ในบล็อก try-catch-final เพียงบล็อกเดียว สิ่งนี้ทำได้โดยการขจัดความจำเป็นใน การบล็อก ในที่สุดซึ่งนักพัฒนาใช้เพื่อปิดทรัพยากรในทางปฏิบัติเท่านั้น

ใน Java คำสั่ง try-with-resources เป็นคำสั่ง try ที่ประกาศทรัพยากรตั้งแต่หนึ่งรายการขึ้นไป ทรัพยากรเป็นวัตถุที่ต้องปิดหลังจากจบโปรแกรม เมื่อการดำเนินการออกจาก บล็อก try-with-resourcesทรัพยากรใดๆ ที่เปิดภายใน บล็อก try-with-resourcesจะถูกปิดโดยอัตโนมัติ โดยไม่คำนึงว่าจะมีข้อยกเว้นใดๆ เกิดขึ้นจากภายใน block try-with-resourcesหรือเมื่อพยายามปิด ทรัพยากร

หากต้องการใช้คุณลักษณะภาษาแบบลองกับทรัพยากรของ Java ให้ใช้กฎต่อไปนี้:

  • ออบเจ็กต์ทั้งหมดที่ได้รับการจัดการโดยคำสั่ง try ด้วยทรัพยากรจะต้องใช้อินเตอร์เฟส AutoCloseable
  • สามารถสร้างวัตถุ AutoCloseable หลายรายการได้ภายในบล็อก try with resource ของ Java
  • อ็อบเจกต์ที่ประกาศในคำสั่ง try ด้วยรีซอร์สมีขอบเขตภายในบล็อกการลอง แต่ไม่ใช่การดักจับและบล็อกสุดท้าย
  • วิธีการปิด () ของวัตถุที่ประกาศในการพยายามบล็อกทรัพยากรถูกเรียกใช้โดยไม่คำนึงว่าจะมีข้อยกเว้นเกิดขึ้นระหว่างการดำเนินการหรือไม่
  • หากมีการโยนข้อยกเว้นในเมธอด close() ก็อาจได้รับการจัดหมวดหมู่เป็นข้อยกเว้นที่ถูกระงับ

ทรัพยากรที่อ้างอิงโดยวัตถุ AutoCloseable จะถูกปิดเสมอ ถ้ามีการใช้คำสั่ง try with Resources และการรั่วไหลของหน่วยความจำที่อาจเกิดขึ้นซึ่งมักเกิดจากการจัดสรรทรัพยากรอย่างไม่ถูกต้องจะถูกกำจัด

ไวยากรณ์

try(declare resources here) {
    // use resources
}
catch(FileNotFoundException e) {
    // exception handling
}

พูดง่ายๆ ก็คือ หากต้องการปิดอัตโนมัติ ทรัพยากรจะต้องมีทั้งการประกาศและเริ่มต้นภายในการลอง :

try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
    writer.println("Hello World");
}

วิธีที่ง่ายและชัดเจนในการใช้ ฟังก์ชัน try-with-resources ใหม่ คือการแทนที่บล็อกtry -catch-final แบบดั้งเดิมและละเอียด

ลองเปรียบเทียบตัวอย่างโค้ดต่อไปนี้

บล็อก แรกคือ บล็อก try-catch-end ทั่วไป :

Scanner scanner = null;
try {
    scanner = new Scanner(new File("test.txt"));
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (scanner != null) {
        scanner.close();
    }
}"); background-repeat: no-repeat; background-position: center center; background-color: rgb(99, 177, 117);">Copy

try (Scanner scanner = new Scanner(new File("test.txt"))) {
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}

เมื่อพูดถึงข้อยกเว้น จะมีความแตกต่างใน การบล็อก try-catch-finalและบล็อก try-with-resources หากมีการโยนข้อยกเว้นในบล็อกลองและบล็อกสุดท้าย เมธอดจะส่งกลับข้อยกเว้นในบล็อกสุดท้าย

สำหรับ try-with-resources หากเกิดข้อยกเว้นในบล็อก try และในคำสั่ง try-with-resources เมธอดจะส่งกลับข้อยกเว้นที่เกิดใน try block ข้อยกเว้นที่เกิดจาก try-with-resources ถูกระงับ กล่าวคือ เราสามารถพูดได้ว่า block try-with-resources นั้นแสดงข้อยกเว้นที่ถูกระงับ

เหตุใดฉันจึงต้องใช้คำสั่ง try-with-resource

คำสั่ง try-with-resources ช่วยให้แน่ใจว่าทรัพยากรแต่ละรายการถูก ปิดเมื่อสิ้นสุดการดำเนินการคำสั่ง หากเราไม่ปิดทรัพยากร อาจก่อให้เกิดการรั่วไหลของทรัพยากร และโปรแกรมอาจทำให้ทรัพยากรที่มีอยู่หมดลงได้ นั่นคือสิ่งที่เกิดขึ้นส่วนใหญ่เมื่อคุณใช้try-catch-finally block

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

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

ในตัวอย่างนี้ หาก เมธอด readLineแสดงข้อยกเว้น และคำสั่งbr.close()ใน บล็อก สุดท้ายแสดงข้อยกเว้น แสดงว่าFileReaderรั่วไหล ดังนั้น ให้ใช้ คำสั่ง try -with-resources แทน การบล็อก สุดท้ายเพื่อปิดทรัพยากรของโปรแกรมของคุณ

ตัวอย่าง

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

import java.io.*;
class Main {
  public static void main(String[] args) {
    String line;
    try(BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
      while ((line = br.readLine()) != null) {
        System.out.println("Line =>"+line);
      }
    } catch (IOException e) {
      System.out.println("IOException in try block =>" + e.getMessage());
    }
  }
}

ข้อยกเว้นที่ถูกระงับ

ถ้าบล็อกการลองแสดงข้อยกเว้น และข้อผิดพลาดอย่างน้อยหนึ่งข้อเกิดขึ้นจากความพยายามด้วยทรัพยากร ข้อยกเว้นที่เกิดจากความพยายามด้วยทรัพยากรจะถูกระงับ กล่าวอีกนัยหนึ่ง เราสามารถพูดได้ว่า ข้อยกเว้นซึ่งเกิดจาก try-with-resources ถูกระงับข้อยกเว้น

คุณสามารถรับข้อยกเว้นเหล่านี้ได้โดยใช้เมธอด getSuppress() ของคลาส Throwable

ตัวอย่าง :

ในตัวอย่างข้างต้น ข้อยกเว้นสามารถเกิดขึ้นได้จาก คำสั่ง try-with-resourcesเมื่อ:

  • ไม่พบไฟล์test.txt
  • การปิดวัตถุBufferedReader

หากเกิดข้อยกเว้นจากทั้ง บล็อก tryและคำสั่ง t ry-with-resourcesข้อยกเว้นจาก บล็อก tryจะถูกโยนทิ้ง และข้อยกเว้นจาก คำสั่ง try-with-resourcesจะถูกระงับ

การดึงข้อยกเว้นที่ถูกระงับ

ใน Java 7 และใหม่กว่า สามารถเรียกคืนข้อยกเว้นที่ถูกระงับได้โดยการเรียก เมธอด Throwable.getSuppressed()จากข้อยกเว้นที่โยนโดยบล็อกtry

getSuppress()ส่งคืนอาร์เรย์ที่มีข้อยกเว้นทั้งหมดซึ่งถูกระงับโดยคำสั่ง try-with-resources ถ้าไม่มีการระงับข้อยกเว้นหรือการยับยั้งถูกปิดใช้งาน อาร์เรย์ว่างจะถูกส่งกลับ

เราได้รับข้อยกเว้นที่ถูกระงับในcatch block

catch(IOException e) {
  System.out.println("Thrown exception=>" + e.getMessage());
  Throwable[] suppressedExceptions = e.getSuppressed();
  for (int i=0; i<suppressedExceptions.length; i++) {
    System.out.println("Suppressed exception=>" + suppressedExceptions[i]);
  }
}

นี่คือข้อดีของการใช้ทรัพยากรแบบลอง:

  • โค้ดที่อ่านได้มากขึ้นและง่ายต่อการเขียน
  • การจัดการทรัพยากรอัตโนมัติ
  • จำนวนบรรทัดของโค้ดลดลง
  • เมื่อมีการเปิดทรัพยากรหลายรายการในการลองด้วยทรัพยากร ทรัพยากรนั้นจะปิดในลำดับที่กลับกันเพื่อหลีกเลี่ยงปัญหาการขึ้นต่อกัน

ก่อนที่ Java 7 จะแนะนำฟีเจอร์นี้ เราต้องใช้ บล็อก สุดท้ายเพื่อให้แน่ใจว่ารีซอร์สถูกปิดเพื่อหลีกเลี่ยงการรั่วไหลของรีซอร์ส

นี่คือโปรแกรมที่คล้ายกับตัวอย่างที่ 1 อย่างไรก็ตาม ในโปรแกรมนี้ เราได้ใช้บล็อกสุดท้ายเพื่อปิดทรัพยากร

ตัวอย่าง : ปิดทรัพยากรโดยใช้บล็อกสุดท้าย

import java.io.*;
class Main {
  public static void main(String[] args) {
    BufferedReader br = null;
    String line;
    try {
      System.out.println("Entering try block");
      br = new BufferedReader(new FileReader("test.txt"));
      while ((line = br.readLine()) != null) {
        System.out.println("Line =>"+line);
      }
    } catch (IOException e) {
      System.out.println("IOException in try block =>" + e.getMessage());
    } finally {
      System.out.println("Entering finally block");
      try {
        if (br != null) {
          br.close();
        }
      } catch (IOException e) {
        System.out.println("IOException in finally block =>"+e.getMessage());
      }
    }
  }
}

Entering try block
Line =>line from test.txt file
Entering finally block

สังเกตการลอง…จับบล็อกใน บล็อก สุดท้ายด้วยหรือไม่ นี่เป็นเพราะIOExceptionสามารถเกิดขึ้นได้ในขณะที่ปิด อินสแตนซ์ BufferedReaderภายใน บล็อก สุดท้าย นี้ ดังนั้นจึงถูกจับและจัดการได้เช่นกัน

คำสั่งtry-with-resources จัดการทรัพยากรโดยอัตโนมัติ เราไม่จำเป็นต้องปิดทรัพยากรอย่างชัดเจน เนื่องจาก JVM จะปิดทรัพยากรเหล่านั้นโดยอัตโนมัติ สิ่งนี้ทำให้โค้ดอ่านง่ายขึ้นและเขียนได้ง่ายขึ้น

ลองใช้ทรัพยากรด้วยทรัพยากรที่หลากหลาย

เราสามารถประกาศทรัพยากรหลายรายการได้ดีใน บล็อก try-with-resourcesโดยคั่นด้วยเครื่องหมายอัฒภาค:

try (Scanner scanner = new Scanner(new File("testRead.txt"));
    PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
    while (scanner.hasNext()) {
	writer.print(scanner.nextLine());
    }
}

ก่อน Java 9 เราสามารถใช้ตัวแปรใหม่ภายใน บล็อก try-with-resources เท่านั้น :

try (Scanner scanner = new Scanner(new File("testRead.txt")); 
    PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) { 
    // omitted
}"); background-repeat: no-repeat; background-position: center center; background-color: rgb(99, 177, 117);">Copy

final Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
try (scanner;writer) { 
    // omitted
}"); background-repeat: no-repeat; background-position: center center; background-color: rgb(99, 177, 117);">Copy

ดังที่แสดงไว้ด้านบน ตัวแปร สแกนเนอร์ได้รับการประกาศ อย่างชัดแจ้ง ในขั้นสุดท้ายดังนั้นเราจึงสามารถใช้กับบล็อกtry-with-resources แม้ว่า ตัวแปร ตัวเขียนจะยังไม่เป็นที่สิ้นสุดอย่างชัดเจน แต่จะไม่เปลี่ยนแปลงหลังจากการมอบหมายครั้งแรก ดังนั้น เราสามารถใช้ ตัวแปร ตัวเขียนได้เช่นกัน

มีความสุขในการเรียนรู้

เข้าร่วมกลุ่ม Mouad Oumous Java WhatsApp เข้าร่วม

เข้าร่วม Mouad Oumous Telegram Channel เข้าร่วม

สนับสนุนสิ่งพิมพ์ของเราโดยติดตาม

คำแนะนำเกี่ยวกับการแมปวัตถุด้วย ModelMapper ใน Java เริ่มต้นใช้งาน Spring Boot: บทช่วยสอนที่ครอบคลุมสำหรับผู้เริ่มต้น ความปลอดภัยของ Spring Boot | สปส. | OAuth2 กับ Okta คำถามสัมภาษณ์ตามสตรีม Java8 ที่พบบ่อยที่สุด - ส่วนที่ 2 การเข้ารหัส: แผ่อาร์เรย์ใน Javascript คำถามสัมภาษณ์ตามสตรีม Java8 ที่พบบ่อยที่สุด - ตอนที่ 1