سؤال

هل هناك طريقة أنيقة لمعالجة الاستثناءات التي القيت في finally كتلة ؟

على سبيل المثال:

try {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
finally {
   try{
     resource.close();
   }
   catch( Exception ex ) {
     // Could not close the resource?
   }
}

كيف يمكنك تجنب try/catch في finally كتلة ؟

هل كانت مفيدة؟

المحلول

وأنا عادة القيام بذلك مثل هذا:

try {
  // Use the resource.
} catch( Exception ex ) {
  // Problem with the resource.
} finally {
  // Put away the resource.
  closeQuietly( resource );
}

وعلى صعيد آخر:

protected void closeQuietly( Resource resource ) {
  try {
    if (resource != null) {
      resource.close();
    }
  } catch( Exception ex ) {
    log( "Exception during Resource.close()", ex );
  }
}

نصائح أخرى

وأنا عادة استخدام إحدى الطرق closeQuietly في org.apache.commons.io.IOUtils:

public static void closeQuietly(OutputStream output) {
    try {
        if (output != null) {
            output.close();
        }
    } catch (IOException ioe) {
        // ignore
    }
}

إذا كنت تستخدم جافا 7، وresource تنفذ AutoClosable، يمكنك القيام بذلك (باستخدام InputStream كمثال):

try (InputStream resource = getInputStream()) {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}

ويمكن القول قليلا على القمة، ولكن من المفيد ربما لو كنت السماح استثناءات فقاعة حتى وأنت لا يمكن تسجيل أي شيء من داخل الأسلوب الخاص بك (على سبيل المثال لأنها مكتبة وكنت تفضل السماح للاستثناءات مقبض كود الدعوة و تسجيل):

Resource resource = null;
boolean isSuccess = false;
try {
    resource = Resource.create();
    resource.use();
    // Following line will only run if nothing above threw an exception.
    isSuccess = true;
} finally {
    if (resource != null) {
        if (isSuccess) {
            // let close throw the exception so it isn't swallowed.
            resource.close();
        } else {
            try {
                resource.close();
            } catch (ResourceException ignore) {
                // Just swallow this one because you don't want it 
                // to replace the one that came first (thrown above).
            }
        }
    }
}

وUPDATE: نظرت إلى هذا أكثر قليلا وجدت بلوق وظيفة كبيرة من شخص يعتقد بشكل واضح عن هذا أكثر مني: <لأ href = "http://illegalargumentexception.blogspot.com/2008/10/java ،، كيف لا إلى جعل-فوضى-من-stream.html "يختلط =" noreferrer "> http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of -stream.html يذهب خطوة أبعد ويجمع الاستثناءات اثنين الى واحد، وأنا أرى أنه مفيد في بعض الحالات.

كما جافا 7 أنت لم تعد بحاجة إلى وثيقة صراحة الموارد في أخيرا كتلة بدلا من ذلك يمكنك استخدام محاولةمع الموارد الجملة.حاول مع الموارد البيان هو محاولة بيان أن تعلن واحد أو أكثر من الموارد.مورد هو كائن يجب أن تكون مغلقة بعد البرنامج هو الانتهاء معها.حاول مع الموارد البيان يضمن أن كل مورد مغلقة في نهاية البيان.أي كائن أن تنفذ جافا.لانغ.AutoCloseable التي تشمل جميع الكائنات التي تنفذ جافا.io.Closeable ، ويمكن استخدام الموارد.

يفترض التعليمة البرمجية التالية:

try( Connection con = null;
     Statement stmt = con.createStatement();
     Result rs= stmt.executeQuery(QUERY);)
{  
     count = rs.getInt(1);
}

إذا كان أي استثناء يحدث قريب طريقة سوف يطلق على كل من هذه الموارد الثلاثة في عكس الترتيب الذي تم إنشاؤها.يعني أسلوب إغلاق سيكون أول من دعا على ResultSetm ثم بيان في النهاية كائن اتصال.

من المهم أيضا أن نعرف أن أي الاستثناءات التي تحدث عند إغلاق الطرق هي ما يسمى تلقائيا يتم قمعها.هذه قمعها استثناءات يمكن استردادها من قبل getsuppressed() طريقة تعريف في Throwable فئة.

المصدر: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

وتجاهل الاستثناءات التي تحدث في "النهاية" كتلة عموما هو <ط> فكرة سيئة ما لم يكن أحد يعرف ما هي تلك الاستثناءات سيكون وما الشروط التي سوف تمثل. في نمط استخدام try/finally العادي، وكتلة try يضع الأمور في الدولة لن تتوقع رمز الخارجي، وكتلة finally يعيد الدولة تلك الأشياء "إلى ما يتوقعه رمز الخارجي. كود الخارجي الذي يمسك استثناء تتوقع عموما أنه على الرغم من استثناء، تمت استعادة كل شيء إلى حالة normal. على سبيل المثال، لنفترض أن بعض التعليمات البرمجية بدء معاملة ومن ثم يحاول إضافة اثنين من السجلات. و"أخيرا" كتلة يؤدي إلى "صد إذا لم يرتكب" العملية. قد أعد المتصل لاستثناء تحدث أثناء تنفيذ العملية الثانية "إضافة"، ويمكن أن يتوقع أنه إذا أدرك هذا الاستثناء، سوف تكون قاعدة البيانات في الحالة التي كان قبل محاولة أي عملية. إذا، ومع ذلك، يحدث الاستثناء الثاني خلال التراجع، يمكن أن تحدث أمور سيئة إذا كان الطالب يجعل أي افتراضات حول حالة قاعدة البيانات. ويمثل عدم التراجع و<ط> الرئيسية الأزمة - واحد والتي لا ينبغي أن يتم ضبطهم من قبل كود تتوقع مجرد "فشل لاضافة التسجيلة" استثناء

وبلدي الميل الشخصي سيكون لديك أخيرا طريقة استثناءات الصيد التي تحدث والتفاف عليها في "CleanupFailedException"، مع الاعتراف بأن هذا الفشل يمثل مشكلة كبيرة ويجب أن لا يتم القبض مثل هذا الاستثناء على محمل الجد.

وحل واحد، وإذا كانت الاستثناءات هما فئتين مختلفتين

try {
    ...
    }
catch(package1.Exception err)
   {
    ...
   }
catch(package2.Exception err)
   {
   ...
   }
finally
  {
  }

ولكن في بعض الأحيان لا يمكنك تجنب هذه ثاني محاولة اللحاق. مثلا ليغلق تيار

InputStream in=null;
try
 {
 in= new FileInputStream("File.txt");
 (..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
 }
catch(SQLException err)
 {
 //handle exception
 }
finally
 {
 //at the end, we close the file
 if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
 }

وماذا كنت ترغب في تجنب كتلة إضافية؟ منذ كتلة وأخيرا يحتوي على العمليات "العادية" التي قد يقوم بطرح استثناء وتريد منع أخيرا لتشغيل تماما لديك لتصفية الاستثناءات.

إذا كنت لا تتوقع منع أخيرا بطرح استثناء وكنت لا تعرف كيفية التعامل مع استثناء أي حال (كنت مجرد تفريغ تتبع مكدس) السماح للفقاعة استثناء حتى الدعوة الى كومة (إزالة محاولة اللحاق من كتلة أخيرا).

إذا كنت ترغب في تقليل بكتابة هل يمكن تنفيذ كتلة حاول اللحاق "العالمي" الخارجي، والتي سوف التقاط كافة الاستثناءات التي القيت كتل أخيرا:

try {
    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }
} catch (Exception ex) {
    ...
}

بعد الكثير من النظر ، أجد البرمجية التالية أفضل:

MyResource resource = null;
try {
    resource = new MyResource();
    resource.doSomethingFancy();
    resource.close(); 
    resource = null;  
} finally {
    closeQuietly(resource)
}

void closeQuietly(MyResource a) {
    if (a!=null)
        try {
             a.close();
        } catch (Exception e) {
             //ignore
        }
}

أن قانون الضمانات التالية:

  1. الموارد يتم تحرير عند الانتهاء من التعليمات البرمجية
  2. استثناءات عند إغلاق الموارد لا تستهلك من دون معالجتها.
  3. رمز لا تحاول إغلاق الموارد مرتين ، لا لزوم لها استثناء سيتم إنشاؤه.

إذا يمكنك يجب اختبار لتجنب حالة الخطأ لتبدأ.

try{...}
catch(NullArgumentException nae){...}
finally
{
  //or if resource had some useful function that tells you its open use that
  if (resource != null) 
  {
      resource.Close();
      resource = null;//just to be explicit about it was closed
  }
}

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

هل يمكن ريفاكتور هذا في طريقة أخرى ...

public void RealDoSuff()
{
   try
   { DoStuff(); }
   catch
   { // resource.close failed or something really weird is going on 
     // like an OutOfMemoryException 
   }
}

private void DoStuff() 
{
  try 
  {}
  catch
  {
  }
  finally 
  {
    if (resource != null) 
    {
      resource.close(); 
    }
  }
}

وأنا عادة القيام بذلك:

MyResource r = null;
try { 
   // use resource
} finally {   
    if( r != null ) try { 
        r.close(); 
    } catch( ThatSpecificExceptionOnClose teoc ){}
}

والأساس المنطقي: إذا انتهيت مع الموارد، والمشكلة الوحيدة لقد تم إغلاقه، ليس هناك الكثير يمكنني القيام به حيال ذلك. فإنه لا معنى له إما لقتل الموضوع بأكمله إذا انتهيت مع الموارد على أي حال.

وهذه هي واحدة من الحالات على الأقل بالنسبة لي، وأنها آمنة لتجاهل أن فحص استثناء.

لهذا اليوم لم تتح لي أي مشكلة في استخدام هذا المصطلح.

try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

والمهمة. لا الاختبارات فارغة. الصيد واحد، وتشمل الحصول على والافراج عن الاستثناءات. بالطبع يمكنك استخدام تنفيذ حوالي لغة وليس لها سوى أن تكتب مرة واحدة لكل نوع الموارد.

وتغيير Resource من أفضل إجابة ل<لأ href = "https://docs.oracle.com/javase/ 7 / مستندات / المعهد / جافا / IO / Closeable.html "يختلط =" نوفولو noreferrer "> Closeable

وتيارات تنفذ Closeable وهكذا يمكنك إعادة استخدام طريقة لجميع تيارات

protected void closeQuietly(Closeable resource) {
    if (resource == null) 
        return;
    try {
        resource.close();
    } catch (IOException e) {
        //log the exception
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top