"อามิโกะ เท็นฮัท!"
"ฉันมีความสุขที่ได้เรียน Java กัปตัน!"
"สบายใจได้ Amigo วันนี้เรามีหัวข้อที่น่าสนใจมาก เราจะพูดถึงวิธีที่โปรแกรม Java โต้ตอบกับทรัพยากรภายนอก และเราจะศึกษาคำสั่ง Java ที่น่าสนใจมาก อย่าปิดหูไว้ดีกว่า"
"ฉันหูทั้งหมด"
"ขณะที่โปรแกรม Java ทำงาน บางครั้งโปรแกรมจะโต้ตอบกับเอนทิตีภายนอกเครื่อง Java เช่น กับไฟล์บนดิสก์ เอนทิตีเหล่านี้มักเรียกว่าทรัพยากรภายนอก"
“แล้วอะไรล่ะที่ถือว่าเป็นทรัพยากรภายใน?”
"ทรัพยากรภายในคือวัตถุที่สร้างขึ้นภายในเครื่อง Java โดยทั่วไปแล้ว การโต้ตอบเป็นไปตามโครงร่างนี้:

"ระบบปฏิบัติการติดตามทรัพยากรที่มีอยู่อย่างเข้มงวด และยังควบคุมการเข้าถึงร่วมกันจากโปรแกรมต่างๆ ตัวอย่างเช่น ถ้าโปรแกรมหนึ่งเปลี่ยนไฟล์ โปรแกรมอื่นจะไม่สามารถเปลี่ยนแปลง (หรือลบ) ไฟล์นั้นได้ หลักการนี้ไม่ใช่ จำกัด เฉพาะไฟล์ แต่ให้ตัวอย่างที่เข้าใจได้ง่ายที่สุด
"ระบบปฏิบัติการมีฟังก์ชัน (API) ที่อนุญาตให้โปรแกรมรับและ/หรือปล่อยทรัพยากร หากทรัพยากรไม่ว่าง เฉพาะโปรแกรมที่ได้รับมาเท่านั้นที่สามารถทำงานได้ ถ้าทรัพยากรนั้นว่าง โปรแกรมใดๆ ก็สามารถรับได้ มัน.
"ลองนึกภาพว่าสำนักงานมีแก้วกาแฟร่วมกัน ถ้ามีคนเอาแก้วไป คนอื่นจะรับไม่ได้อีกต่อไป แต่เมื่อแก้วถูกใช้งาน ล้าง และใส่กลับเข้าที่แล้ว ใครๆ ก็หยิบได้อีก"
"เข้าใจแล้ว มันก็เหมือนกับที่นั่งบนรถไฟใต้ดินหรือระบบขนส่งสาธารณะอื่นๆ ถ้าที่นั่งว่าง ใครก็นั่งได้ ถ้าที่นั่งว่าง คนที่นั่งก็จะเป็นคนควบคุม"
"ถูกต้อง และตอนนี้เรามาพูดถึงการรับทรัพยากรภายนอกทุกครั้งที่โปรแกรม Java ของคุณเริ่มทำงานกับไฟล์บนดิสก์ เครื่อง Java จะถามระบบปฏิบัติการเพื่อการเข้าถึงแบบเอกสิทธิ์เฉพาะบุคคล หากทรัพยากรนั้นว่าง เครื่อง Java จะได้รับ มัน.
"แต่หลังจากที่คุณทำงานกับไฟล์เสร็จแล้ว ทรัพยากร (ไฟล์) นี้จะต้องได้รับการปล่อยตัว กล่าวคือ คุณต้องแจ้งให้ระบบปฏิบัติการทราบว่าคุณไม่ต้องการอีกต่อไปหากคุณไม่ทำเช่นนี้ ทรัพยากรจะยังคงเป็น จัดโดยโปรแกรมของคุณ "
"นั่นฟังดูยุติธรรม"
"เพื่อให้เป็นเช่นนั้น ระบบปฏิบัติการจะรักษารายการของทรัพยากรที่ครอบครองโดยโปรแกรมที่กำลังรันอยู่ ถ้าโปรแกรมของคุณมีทรัพยากรเกินขีดจำกัดที่กำหนดไว้ ระบบปฏิบัติการจะไม่ให้ทรัพยากรใหม่แก่คุณอีกต่อไป
"มันเหมือนกับโปรแกรมที่สามารถกินหน่วยความจำทั้งหมด ... "
"อะไรทำนองนั้น ข่าวดีก็คือหากโปรแกรมของคุณยุติลง ทรัพยากรทั้งหมดจะถูกปล่อยโดยอัตโนมัติ (ระบบปฏิบัติการเองก็ทำเช่นนี้)"
“ถ้านั่นเป็นข่าวดี แสดงว่ามีข่าวร้ายหรือเปล่า”
"ใช่แล้ว ข่าวร้ายก็คือ หากคุณกำลังเขียนแอปพลิเคชันเซิร์ฟเวอร์..."
"แต่ฉันจะเขียนใบสมัครดังกล่าวหรือไม่"
"แอปพลิเคชันเซิร์ฟเวอร์จำนวนมากเขียนด้วยภาษาจาวา ดังนั้นเป็นไปได้มากว่าคุณจะเขียนแอปพลิเคชันเหล่านี้เพื่อการทำงาน อย่างที่ฉันพูด หากคุณกำลังเขียนแอปพลิเคชันเซิร์ฟเวอร์ เซิร์ฟเวอร์ของคุณจะต้องทำงานไม่หยุดเป็นเวลาหลายวัน สัปดาห์ เดือน ฯลฯ"
"กล่าวอีกนัยหนึ่งคือ โปรแกรมไม่ได้หยุดทำงาน และนั่นหมายความว่าหน่วยความจำจะไม่ถูกปล่อยออกมาโดยอัตโนมัติ"
"ถูกต้อง และถ้าคุณเปิดไฟล์ 100 ไฟล์ต่อวันและไม่ปิดมัน ในอีกไม่กี่สัปดาห์ แอปพลิเคชันของคุณจะถึงขีดจำกัดของทรัพยากรและหยุดทำงาน"
"งานที่มั่นคงเหลืออีกหลายเดือน! จะทำอะไรได้บ้าง"
"คลาสที่ใช้ทรัพยากรภายนอกมีวิธีพิเศษในการเผยแพร่: close()
.
"ต่อไปนี้เป็นตัวอย่างของโปรแกรมที่เขียนบางอย่างลงในไฟล์แล้วปิดไฟล์เมื่อทำงานเสร็จ นั่นคือทำให้ทรัพยากรของระบบปฏิบัติการว่างลง หน้าตาประมาณนี้:
รหัส | บันทึก |
---|---|
|
เส้นทางไปยังไฟล์. รับวัตถุไฟล์: รับทรัพยากร เขียนลงไฟล์ ปิดไฟล์ - ปล่อยทรัพยากร |
"อา... หลังจากทำงานกับไฟล์ (หรือทรัพยากรภายนอกอื่น ๆ) ฉันต้องเรียกใช้เมธอดclose()
บนวัตถุที่เชื่อมโยงกับทรัพยากรภายนอก"
"ใช่ ทุกอย่างดูเหมือนง่าย แต่ข้อยกเว้นสามารถเกิดขึ้นได้เมื่อโปรแกรมทำงาน และทรัพยากรภายนอกจะไม่ถูกปล่อยออกมา"
“แล้วมันแย่มาก ทำไงดี”
"เพื่อให้แน่ใจว่าclose()
มีการเรียกใช้เมธอดเสมอ เราจำเป็นต้องห่อโค้ดของเราใน บล็อก try
- catch
- finally
และเพิ่มclose()
เมธอดลงในfinally
บล็อก ซึ่งจะมีลักษณะดังนี้:
try
{
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
"หืม... มีอะไรผิดปกติที่นี่?"
"ถูกต้อง โค้ดนี้จะไม่คอมไพล์ เนื่องจากoutput
ตัวแปรถูกประกาศภายในtry{}
บล็อก ดังนั้นจึงมองไม่เห็นในfinally
บล็อก
มาแก้ไขกันเถอะ:
FileOutputStream output = new FileOutputStream(path);
try
{
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
“ตอนนี้ทุกอย่างโอเคไหม?”
"ไม่เป็นไร แต่จะไม่ทำงานหากมีข้อผิดพลาดเกิดขึ้นเมื่อเราสร้างวัตถุFileOutputStream
และสิ่งนี้อาจเกิดขึ้นได้ค่อนข้างง่าย
มาแก้ไขกันเถอะ:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
"และทุกอย่างทำงานตอนนี้หรือไม่"
"ยังมีข้อวิจารณ์อยู่บ้าง ประการแรก หากมีข้อผิดพลาดเกิดขึ้นเมื่อสร้างวัตถุFileOutputStream
ตัวแปรนั้นoutput
จะเป็นโมฆะ ความเป็นไปได้นี้จะต้องนำมาพิจารณาในfinally
บล็อก
" close()
ประการที่สอง เมธอดจะถูกเรียกใช้ในfinally
บล็อกเสมอ ซึ่งหมายความว่าไม่จำเป็นในtry
บล็อก รหัสสุดท้ายจะมีลักษณะดังนี้:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (output!=null)
output.close();
}
"แม้ว่าเราจะไม่พิจารณาบล็อกcatch
ซึ่งสามารถละเว้นได้ ดังนั้นโค้ด 3 บรรทัดของเราจึงกลายเป็น 10 แต่โดยพื้นฐานแล้ว เราเพิ่งเปิดไฟล์และเขียน 1"
“ฟู่... เป็นเรื่องที่ดีที่สรุปเรื่องนี้ได้ ค่อนข้างเข้าใจ แต่ค่อนข้างน่าเบื่อใช่ไหม”
"เป็นเช่นนั้น นั่นเป็นเหตุผลที่ผู้สร้างของ Java ช่วยเราโดยการเพิ่มน้ำตาลเชิงประโยค ตอนนี้เรามาดูไฮไลท์ของโปรแกรมหรือมากกว่านั้นคือบทเรียนนี้:
try
-พร้อมทรัพยากร
"เริ่มต้นด้วยเวอร์ชันที่ 7 Java มีtry
คำสั่ง -with-resources ใหม่
"มันถูกสร้างขึ้นอย่างแม่นยำเพื่อแก้ปัญหาด้วยการเรียกเมธอดที่จำเป็นclose()
"
"ฟังดูมีความหวัง!"
"กรณีทั่วไปดูค่อนข้างง่าย:
try (ClassName name = new ClassName())
{
Code that works with the name variable
}
"นี่คือการเปลี่ยนแปลงของtry
คำสั่ง อื่น ?"
"ใช่ คุณต้องเพิ่มวงเล็บหลังtry
คำหลัก จากนั้นสร้างวัตถุที่มีทรัพยากรภายนอกอยู่ภายในวงเล็บ สำหรับแต่ละวัตถุในวงเล็บ คอมไพเลอร์จะเพิ่มส่วนfinally
และการเรียกใช้close()
เมธอด
"ด้านล่างเป็นตัวอย่างที่เทียบเท่ากันสองตัวอย่าง:
รหัสยาว | รหัสที่มีการลองด้วยทรัพยากร |
---|---|
|
|
"เจ๋งมาก! โค้ดที่ใช้try
-with-resources นั้นสั้นกว่าและอ่านง่ายกว่ามาก ยิ่งเรามีโค้ดน้อย โอกาสพิมพ์ผิดหรือข้อผิดพลาดอื่นๆ ก็น้อยลง"
"ฉันดีใจที่คุณชอบ อย่างไรก็ตาม เราสามารถเพิ่มcatch
และfinally
บล็อกtry
คำสั่ง -with-resources ได้ หรือคุณไม่สามารถเพิ่มได้หากไม่จำเป็น
หลายตัวแปรในเวลาเดียวกัน
"คุณอาจพบกับสถานการณ์บ่อยครั้งเมื่อจำเป็นต้องเปิดไฟล์หลายไฟล์พร้อมกัน สมมติว่าคุณกำลังคัดลอกไฟล์ ดังนั้นคุณต้องมีวัตถุสองชิ้น: ไฟล์ที่คุณกำลังคัดลอกข้อมูลและไฟล์ที่คุณกำลังคัดลอกข้อมูล .
"ในกรณีนี้try
คำสั่ง -with-resources ให้คุณสร้างหนึ่งแต่หลายวัตถุในนั้น โค้ดที่สร้างวัตถุต้องคั่นด้วยเครื่องหมายอัฒภาค นี่คือลักษณะทั่วไปของคำสั่งนี้:
try (ClassName name = new ClassName(); ClassName2 name2 = new ClassName2())
{
Code that works with the name and name2 variables
}
ตัวอย่างการคัดลอกไฟล์:
รหัสสั้น | รหัสยาว |
---|---|
|
|
"เราจะว่าอย่างไรดี - try
ด้วยทรัพยากรเป็นสิ่งที่วิเศษมาก!"
"สิ่งที่เราสามารถพูดได้ว่าเราควรใช้มัน"
GO TO FULL VERSION