Java 7 kaynakla deneme sürümünü doğru kullanıyor muyum?


87

İstisna atılırsa arabelleğe alınmış okuyucunun ve dosya okuyucunun kapanmasını ve kaynakları serbest bırakmasını bekliyorum.

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

Bununla birlikte, catchbaşarılı bir kapatma için bir maddeye sahip olma şartı var mı?

DÜZENLE:

Esasen, Java 7'deki yukarıdaki kod, Java 6 için aşağıdakine eşdeğerdir:

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;
}

Sorunuzu tekrar okuduktan sonra, iyi anladığımdan emin değilim. Lütfen açıklar mısınız?
Maroun

Selam. Cheetah, catchJava 6 için ilk örneğinizin rolünü anlamaya çalışıyorum . Yani catch (Exception ex) { throw ex; }- sadece istisnayı yeniden fırlatıyor, hiçbir şey yapmıyor, herhangi bir zarar görmeden kolayca kaldırılabilir. Yoksa bir şey mi kaçırıyorum?
Sasha

Yanıtlar:


103

Bu doğru ve catchmaddeye gerek yok . Oracle java 7 doc, bir istisna gerçekten atılıp atılmadığına bakılmaksızın kaynağın kapatılacağını söylüyor .

catchYalnızca istisnaya tepki vermek istiyorsanız bir cümle kullanmalısınız . catchBloğu icra edilecektir sonra kaynak kapalıdır.

Oracle'ın öğreticisinden bir pasaj :

Aşağıdaki örnek, bir dosyadan ilk satırı okur. Dosyadan veri okumak için BufferedReader'ın bir örneğini kullanır. BufferedReader, program kendisiyle bittikten sonra kapatılması gereken bir kaynaktır:

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 örneği, kaynakla dene deyiminde bildirildiğinden, try deyiminin normal şekilde mi yoksa aniden mi tamamlandığına bakılmaksızın kapatılır (BufferedReader.readLine yönteminin bir IOException oluşturmasının bir sonucu olarak).

DÜZENLE

Yeni düzenlenen soruyla ilgili olarak:

Java 6'daki kod catch, finallybloğu ve ardından bloğu çalıştırır . Bu, kaynakların hala potansiyel olarak catchblokta açılmasına neden olur .

Java 7 sözdiziminde, kaynaklar kapalı öncecatch bloğun, yani kaynaklar zaten sırasında kapalıdır catchblok yürütme. Bu, yukarıdaki bağlantıda belgelenmiştir:

Bir kaynakla dene deyiminde, bildirilen kaynaklar kapatıldıktan sonra herhangi bir catch veya nihayet bloğu çalıştırılır.


69

Kaynaklarla deneme kullanımınız bu özel durumda iyi çalışacaktır, ancak genel olarak tam olarak doğru değildir. Hoş olmayan sürprizlere yol açabileceği için kaynakları böyle zincirlememelisiniz. Değişken bir arabellek boyutuna sahip olduğunuzu varsayın:

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);
    } 
}

Bir şeylerin ters gittiğini ve sonunda sznegatif olduğunuzu varsayın . Bu durumda dosya kaynak (aracılığıyla oluşturulan new FileReader(filePath)) olacak DEĞİL kapatılacak.

Bu sorunu önlemek için her kaynağı aşağıdaki gibi ayrı ayrı belirtmelisiniz:

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);
    } 
}

Bu durumda, brbaşarısızlıkların başlatılması fileyine de kapanır. Daha fazla ayrıntıyı burada ve burada bulabilirsiniz .


Sz negatif olduğunda bir atılma new FileReader(filePath))durumunda aracılığıyla oluşturulan kaynağın neden kapanmayacağını anlamaya çalışıyorum IllegalArgumentException. Kaynakla deneme, AutoClosableatılan istisnalara bakılmaksızın tüm kaynakları kapatmıyor mu?
Prasoon Joshi

3
@PrasoonJoshi Hayır, yalnızca .close()try-with-resources başlatıcısında bildirilen değişkenleri çağırır . Bu nedenle, bu örnekte onu iki bildirime ayırmak hile yapar.
Mario Carneiro

4
Andrii ve @Mario Hem haklı hem de haksızsınız. İlk örnekte, Dosya Okuyucusu kaynakla deneme mantığı tarafından kapatılmamıştır. Ancak BufferedReader kapatıldığında, sarılı FileReader'ı da kapatacaktır. Kanıt için, java.io.BufferedReader.close () kaynağına bir göz atın. Sonuç olarak, ilk örnekteki kod daha kısa olduğu için tercih edilmelidir.
jschreiner

7
@jschreiner Doğru, Andrii'nin (biraz yapmacık) kurucunun sz < 0bir istisna atmasına neden olan sorunu aslında kaynağın sızmasına neden olacaktır.
Mario Carneiro

5
@mario Katılıyorum. Dış kurucu başarısız olabilir ve iç kaynak sızdırılabilir. Bunu daha önce görmedim, teşekkürler.
jschreiner
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.