แหล่งที่มา: สื่อ คู่มือนี้อธิบายประโยชน์ของการลองด้วยทรัพยากรมากกว่าการลองจับในที่สุด นอกจากนี้คุณยังจะได้เรียนรู้ภายใต้เงื่อนไขที่ระงับข้อยกเว้นที่เกิดขึ้น และวิธีใช้การลองใช้ทรัพยากรกับทรัพยากรหลายรายการ
โครงสร้างtry with resourcesหรือที่เรียกว่าtry-with-resourcesเป็นกลไกการจัดการข้อยกเว้นใน Java ที่สามารถปิดทรัพยากร เช่น Java InputStream หรือ JDBC Connection ได้โดยอัตโนมัติ เมื่อทำงานกับทรัพยากรเหล่านั้นเสร็จแล้ว ในปี 2011 Oracle ได้เพิ่มความพยายามด้วยทรัพยากรให้กับไวยากรณ์ภาษา Java เพื่อให้แน่ใจว่าออบเจ็กต์ เช่น ซ็อกเก็ตเครือข่าย การเชื่อมต่อฐานข้อมูล และลิงก์ไฟล์และโฟลเดอร์จะถูกปิดอย่างสวยงามหลังจากใช้งาน ความล้มเหลวในการปิดทรัพยากรเหล่านี้หลังจากที่นักพัฒนาเปิดหมายเลขอ้างอิงอาจส่งผลให้เกิดการรั่วไหลของหน่วยความจำ เรียกใช้รูทีนการรวบรวมขยะที่สามารถป้องกันได้ และโอเวอร์เฮดของ CPU บนเซิร์ฟเวอร์

ก่อนจาวา 7
ใน Java หากคุณใช้ทรัพยากร เช่น สตรีมอินพุต/เอาท์พุต คุณจะต้องปิดทรัพยากรเหล่านั้นหลังการใช้งานเสมอ เนื่องจากสามารถส่งข้อ ยกเว้นได้ จึงต้องบรรจุไว้ใน บล็อก try-catch การ ปิดจะต้องเกิดขึ้นใน บล็อก สุดท้าย อย่างน้อยก็เป็นเช่นนั้นจนกระทั่ง Java 7 แต่มีข้อเสียหลายประการ:- คุณต้องตรวจสอบว่าทรัพยากรของคุณเป็นโมฆะหรือไม่ก่อนที่จะปิด
- การปิดตัวเองอาจทำให้เกิดข้อยกเว้น ดังนั้นคุณต้องลองจับ อีกครั้งในบล็อก สุดท้าย ของคุณ
- โปรแกรมเมอร์มักจะลืมปิดทรัพยากรของตน
จะใช้คำสั่ง try-with-resource ได้อย่างไร?
โอเปอเรเตอร์นี้เดิมเปิดตัวใน Java 7 และแนวคิดก็คือนักพัฒนาไม่จำเป็นต้องกังวลเกี่ยวกับการจัดการทรัพยากรที่พวกเขาใช้ในบล็อกtry -catch-finally อีกต่อไป สิ่งนี้สามารถทำได้โดยการขจัดความจำเป็นใน การบล็อก ในที่สุดซึ่งในทางปฏิบัติแล้วนักพัฒนาใช้เพื่อปิดทรัพยากรเท่านั้น ใน Java คำสั่ง try-with-resourcesคือ คำสั่ง tryที่ประกาศทรัพยากรตั้งแต่หนึ่งรายการขึ้นไป ทรัพยากรคือวัตถุที่ต้องปิดหลังจากโปรแกรมยุติลง เมื่อการเรียกใช้โค้ดออกจากบล็อกtry-with-resourcesทรัพยากรใดๆ ที่เปิดใน บล็อก try-with-resourcesจะถูกปิดโดยอัตโนมัติ โดยไม่คำนึงว่ามีข้อยกเว้นใดๆ เกิดขึ้นภายในบล็อกtry-with-resourcesหรือขณะพยายามปิดทรัพยากรหรือไม่ . หากต้องการใช้คุณลักษณะภาษา Java try-with-resourcesให้ใช้กฎต่อไปนี้:- อ อบเจ็กต์ทั้งหมดที่ควบคุมโดย คำสั่ง try-with-resourcesต้องใช้ อินเทอร์เฟซ AutoCloseable
- สามารถสร้างออบเจ็กต์AutoCloseable ได้ หลายรายการ ใน บล็อก try-with-resources
- ออบเจ็กต์ที่ประกาศใน คำสั่ง try- with -resourcesจะถูกดำเนินการในtry block แต่จะไม่อยู่ในcatchหรือ บล็อก ในที่สุด
- เมธอด close()ของอ็อบเจ็กต์ที่ประกาศใน บล็อก try-with-resourcesจะถูกเรียกใช้โดยไม่คำนึงว่ามีข้อยกเว้นเกิดขึ้นที่รันไทม์หรือไม่
- หากมีข้อยกเว้นเกิดขึ้นใน เมธอด close()ก็อาจถูกจัดประเภทเป็นข้อยกเว้นที่ถูกระงับ
ไวยากรณ์
try(declare resources here) {
// использовать ресурсы
}
catch(FileNotFoundException e) {
// обработка исключений
}
การใช้งาน try-with-resource ในทางปฏิบัติ
หากต้องการปิดโดยอัตโนมัติ ทรัพยากรจะต้องได้รับการประกาศและเตรียมใช้งานภายในtry :try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
writer.println("Hello World");
}
แทนที่ try-catch-finally ด้วย try-with-resources
วิธีที่ง่ายและชัดเจนในการใช้ ฟังก์ชัน try-with-resourcesคือการแทนที่บล็อกtry-catch-finally แบบดั้งเดิม และ ละเอียด ลองเปรียบเทียบตัวอย่างโค้ดต่อไปนี้ ตัวอย่างแรกคือ บล็อก try-catch-finally ทั่วไป :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();
}
}
และนี่คือโซลูชันใหม่ที่กระชับที่สุดโดยใช้try-with-resources :
try (Scanner scanner = new Scanner(new File("test.txt"))) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
ความแตกต่างระหว่าง try และ try-with-resource
เมื่อพูดถึงข้อยกเว้น จะมีความแตกต่างระหว่างบล็อก try - catch-finallyและ บล็อก try-with-resources ข้อยกเว้นถูกส่งออกไปทั้งในtry และในท้ายที่สุด block อย่างไรก็ตามวิธีการส่งคืนข้อยกเว้นที่เกิดขึ้นใน บล็อก สุดท้าย เท่านั้น สำหรับtry-with-resourcesหากมีข้อยกเว้นเกิดขึ้น ใน try block และใน คำ สั่งtry-with-resources เมธอดจะส่งคืนข้อยกเว้นที่เกิดขึ้นใน try block ข้อยกเว้นที่เกิดขึ้นจาก บล็อก try-with-resourcesจะถูกระงับ กล่าวคือ เราสามารถพูดได้ว่า บล็อก try-with-resourcesส่งข้อยกเว้นที่ถูกระงับเหตุใดฉันจึงควรใช้คำสั่ง try-with-resource
คำสั่งtry-with-resourcesช่วยให้มั่นใจว่าแต่ละทรัพยากรถูกปิดที่ส่วนท้ายของคำสั่ง หากเราไม่ปิดทรัพยากร สิ่งนี้อาจนำไปสู่การรั่วไหลของทรัพยากร และโปรแกรมอาจทำให้ทรัพยากรที่มีอยู่หมดไป สิ่งนี้จะเกิดขึ้นเมื่อคุณใช้ บล็อก try-catch- finally ก่อน 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ใช้ในการอ่านข้อมูล ทรัพยากรเหล่านี้เป็นทรัพยากรที่ต้องปิดหลังจากออกจากโปรแกรม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คือBufferedReader ข้อความประกาศสำหรับทรัพยากรนี้จะปรากฏอยู่ในวงเล็บหลังคีย์เวิร์ดtry คลาสBufferedReaderใน Java SE 7 และใหม่กว่าใช้ อิน เท อร์เฟซ java.lang.AutoCloseable เนื่องจาก อินสแตนซ์ BufferedReaderได้รับการประกาศใน คำสั่ง try-with-resource อินสแตนซ์เหล่านั้นจะถูกปิดโดยไม่คำนึงว่า คำสั่ง try จะออก ตามปกติหรือกะทันหัน (หาก เมธอด BufferedReader.readLine()ส่งIOException )
ข้อยกเว้นที่ถูกระงับ
หาก บล็อก tryส่งข้อยกเว้น และมีข้อยกเว้นอย่างน้อยหนึ่งรายการปรากฏใน บล็อก try-with-resourcesดังนั้นข้อยกเว้นที่เกิดจาก บล็อก try-with-resourcesจะถูกระงับ กล่าวอีกนัยหนึ่ง เราสามารถพูดได้ว่าข้อยกเว้นที่เกิดจากtry-with-resourcesจะถูกระงับข้อยกเว้น คุณสามารถตรวจจับข้อยกเว้นเหล่านี้ได้โดยใช้เมธอดgetSuppress() ของ คลาสThrowable ในตัวอย่างที่แสดงก่อนหน้านี้ มีข้อยกเว้นเกิดขึ้นโดย คำสั่ง try-with-resourcesภายใต้เงื่อนไขต่อไปนี้:- ไม่พบไฟล์test.txt
- การปิดวัตถุBufferedReader
ได้รับการระงับข้อยกเว้น
ใน Java 7 และใหม่กว่า สามารถรับข้อยกเว้นที่ถูกระงับได้โดยการเรียก เมธอด Throwable.getSuppressed()จากข้อยกเว้นที่ส่งมาจากtry block 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[i]);
}
}
ประโยชน์ของการใช้ทรัพยากรแบบลองกับ
- สามารถอ่านและเขียนโค้ดได้ง่าย การจัดการทรัพยากรอัตโนมัติ
- จำนวนบรรทัดของโค้ดลดลง
- เมื่อมีการเปิดทรัพยากรหลายรายการในtry-with-resourcesทรัพยากรเหล่านั้นจะถูกปิดในลำดับย้อนกลับเพื่อหลีกเลี่ยงปัญหาการขึ้นต่อกัน
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());
}
}
}
}
บทสรุป:
เข้าสู่การลองบล็อก Line =>line จากไฟล์ test.txt เข้าสู่การบล็อกในที่สุด
ดังที่คุณเห็นจากตัวอย่างด้านบน การใช้ บล็อก สุดท้ายเพื่อล้างทรัพยากรจะเพิ่มความซับซ้อนให้กับโค้ด สังเกตเห็นtry...catch 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 - ตัวแปรสุดท้ายที่มีประสิทธิภาพ
ก่อน Java 9 เราสามารถใช้เฉพาะตัวแปรใหม่ภายในtry-with-resources block :try (Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
// omitted
}
โปรดทราบว่านี่ค่อนข้างละเอียดเมื่อประกาศทรัพยากรหลายรายการ ตั้งแต่ Java 9 (อัปเดต JEP 213) เราสามารถใช้ตัวแปรสุดท้ายหรือ ตัวแปร สุดท้ายที่มีประสิทธิผลภายใน บล็อก try-with-resources :
final Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
try (scanner;writer) {
// omitted
}
พูดง่ายๆ ก็คือ ตัวแปรถือเป็นที่สิ้นสุด อย่างมีประสิทธิภาพ หากไม่มีการแก้ไขหลังจากการมอบหมายครั้งแรก แม้ว่าจะไม่ได้ทำเครื่องหมายไว้อย่างชัดเจนว่าเป็นที่สิ้นสุด ก็ตาม ดังที่แสดงไว้ด้านบน ตัวแปร สแกนเนอร์ได้รับการประกาศขั้นสุดท้าย อย่างชัดเจน เพื่อให้เราสามารถใช้กับ บล็อก try-with-resourcesได้ แม้ว่าตัวแปรตัวเขียนจะไม่เป็นขั้นสุดท้าย อย่างชัดเจน แต่จะไม่เปลี่ยนแปลงหลังจากการมอบหมายครั้งแรก ดังนั้นเราจึงสามารถใช้ ตัวแปร ตัวเขียนได้ ฉันหวังว่าวันนี้คุณจะเข้าใจวิธีจัดการกับข้อยกเว้นโดยใช้คำ สั่ง try-with-resource มากขึ้น มีความสุขในการเรียนรู้!
GO TO FULL VERSION