it-swarm.dev

هل أستخدم Java 7 try-with-resources بشكل صحيح

أتوقع إغلاق القارئ المخزن مؤقتًا وقارئ الملفات والموارد التي تم إصدارها إذا تم الاستثناء.

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    try (BufferedReader br = new BufferedReader(new FileReader(filePath)))
    {
        return read(br);
    } 
}

ومع ذلك ، هل هناك شرط للحصول على جملة catch للإغلاق الناجح؟

تصحيح:

في الأساس ، الكود أعلاه في Java 7 مكافئ لما يلي لـ Java 6:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{

    BufferedReader br = null;

    try
    {
        br = new BufferedReader(new FileReader(filePath));

        return read(br);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        try
        {
            if (br != null) br.close();
        }
        catch(Exception ex)
        {
        }
    }

    return null;
}
83
Cheetah

هذا صحيح وليس هناك شرط لشرط catch. يقول Oracle Java 7 doc أن المورد سيتم إغلاقه بغض النظر حول ما إذا كان قد تم طرح استثناء بالفعل أم لا.

يجب عليك استخدام جملة catch فقط إذا كنت ترغب في الرد على الاستثناء. سيتم تنفيذ جملة catch {after المورد مغلق.

إليك مقتطف من البرنامج التعليمي Oracle :

المثال التالي يقرأ السطر الأول من ملف. يستخدم مثيل BufferedReader لقراءة البيانات من الملف. BufferedReader هو مورد يجب إغلاقه بعد انتهاء البرنامج:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
} // In this example, the resource declared in the try-with-resources statement is a BufferedReader.

... نظرًا لتعريف مثيل BufferedReader في بيان try-with-resource ، فسيتم إغلاقه بغض النظر عما إذا كانت عبارة try مكتملة بشكل طبيعي أو مفاجئ (نتيجة للأسلوب BufferedReader.readLine الذي يرمي IOException).

EDIT

فيما يتعلق بالسؤال الجديد المعدل:

ينفذ الكود في Java 6 catch وبعد ذلك كتلة finally. يؤدي هذا إلى استمرار احتمال فتح الموارد في الكتلة catch.

في بناء جملة Java 7 ، يتم إغلاق الموارد قبل الكتلة catch ، لذلك يتم إغلاق الموارد بالفعل أثناء تنفيذ حظر catch. تم توثيقه في الرابط أعلاه:

في عبارة try-with-resources ، يتم تشغيل أي catch أو block أخيرًا بعد إغلاق الموارد المعلنة.

101
yair

سيعمل استخدامك للتجربة مع الموارد بشكل جيد في هذه الحالة بالذات ، ولكنه ليس صحيحًا بشكل عام. لا ينبغي عليك ربط سلسلة من الموارد بهذا الشكل لأنها قد تؤدي إلى مفاجآت غير سارة. افترض أن لديك حجم المخزن المؤقت متغير:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    int sz = /* get buffer size somehow */
    try (BufferedReader br = new BufferedReader(new FileReader(filePath), sz))
    {
        return read(br);
    } 
}

افترض حدوث خطأ ما وانتهى بك الأمر sz كونه سلبي. في هذه الحالة ، سيتم إغلاق مورد الملف (الذي تم إنشاؤه عبر new FileReader(filePath))لاسيتم إغلاقه.

لتجنب هذه المشكلة ، يجب عليك تحديد كل مورد على حدة مثل هذا:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    int sz = /* get buffer size somehow */
    try (FileReader file = new FileReader(filePath);
         BufferedReader br = new BufferedReader(file, sz))
    {
        return read(br);
    } 
}

في هذه الحالة ، حتى إذا فشلت تهيئة brfile ، فلا يزال يتم إغلاقها. يمكنك العثور على مزيد من التفاصيل هنا و هنا .

68
Andrii Polunin