2015-04-18 23 views
15

C++ arkaplanından geldiğimde, RAII modelinin büyük bir hayranıyım. Bellek yönetimini ve kilit yönetimini diğer kullanım durumlarıyla birlikte kullanmak için yoğun bir şekilde kullandım.RAII tasarım deseninde Java

Java 1.7 ile RAII kalıbı oluşturmak için kaynakla çalış modelini kullanabileceğimi görüyorum.

RAII kullanarak örnek bir uygulama oluşturdum ve çalışıyor, ancak java'dan derleyici uyarıları görüyorum.

Örnek Uygulama

try(MyResource myVar = new MyResource(..)) 
{ 
    //I am not using myVar here 
} 

Ben

warning: [try] auto-closeable resource node is never referenced in body of corresponding try statement 

Ben uyarıyı Aşağıdaki hatalar, ben bilmiyorum deneyin blok içine değişken kullanmış gerektiğini ima olsun Gerçekten her zaman yapmaya ihtiyacım var.

Buna baktığımda, Java'nın RAII için gerçekten gerçek bir desteği olmadığını ve C++'da tam olarak RAII eşdeğeri değil, yalnızca Kaynak Yönetimi için olan özelliği kötüye kullanmış olabileceğimi varsayıyorum. soruların

Çift:

  1. benim anlayış doğru mu?
  2. Bu uyarıları dikkate almamak ne kadar risklidir?
  3. Bu uyarıları karıncadan nasıl duyarım?
  4. Bunun üstesinden gelmek için basit bir yol var mı?

4 i derleyici sorunları çözer ama tasarım gibi de ray dışına özünü alır bu

try(MyResource myVar = new Resource()) 
{ 
    myvar.Initialize() 
    .... 

} 

gibi daha basit bir yapıcı içine yapıcı çağrısı ve bir örnek yöntemi bölme düşünüyorum.

+0

Yani 'Resource' inşaat ve sadece neden yan etkileri (kapat()' 'yanı sıra) anlamlı yöntemleri vardır ? Bir Java adamı olarak, bu bir antipattern gibi görünüyor. Kaynağın ne yaptığını açıklayabilir misin? –

+0

@TomG otomatik kilit açma işlemine çok benzer. Kilit inşaatta alınır, yıkımın kilidini açar. Ama Java'da yok edicileriniz olmadığından, close() –

+0

'u uygulayarak otomatik kapatmayı kullanıyorum hala biraz kafam karıştı. Bu kilit nasıl paylaşılıyor? Yeni bir Kaynak oluşturmak, başka bir kodun kontrol ettiği başka bir küresel değişkeni etkiler mi? –

cevap

13

1. Anlayışım doğru mu?

Daha fazla veya daha az. Evet, kaynakları bu şekilde kullanmayı ve evet, RAII ile semantik olarak karşılaştırılabilir. Aradaki fark, yalnızca bir yöntem çağrısı olan imhası veya tahsisatı'dir. Başka programcılar ile çalışıyorsanız

import java.util.concurrent.locks.Lock; 

public class Guard implements AutoCloseable { 
    private final Lock lock; 

    public Guard(Lock lock) { 
     this.lock = lock; 
     lock.lock(); 
    } 

    @Override 
    public void close() { 
     lock.unlock(); 
    } 
} 
try(Guard g = new Guard(myLock)) { 
    // do stuff 
} 

, ne anlatmak gerekebilir:

Bazı kaynak yönetimi mantığı örneğin sarmak için sadeceyazılı nesneleri bulmak için nadir bulunuyor Bu birkaç kişi anlamına gelir, ancak teknenizi yüzerse kişisel olarak bir sorun görmüyorum.

Ne tavsiye etmem kod incelemede WTF'lerinizi üretmek için emin

try(AutoCloseable a =() -> lock.unlock()) { 
    lock.lock(); 
    // do stuff 
} 

gibi garip bir kod yazıyor.

2. Bu uyarıları dikkate almamak ne kadar risklidir?

Riskli değil. Uyarı gerçekten sadece bir bildirim. Biliyorsunuz, numaralı telefonun numarasını bilmemesi durumunda.

deneyebilirsin uyarı kurtulmak için:

try(@SuppressWarnings("unused") 
    MyResource myVar = new MyResource()) 

Ya da belki de 'How do you get *ant* to not print out javac warnings?' görüyoruz.

Bir IDE, ya global olarak ya da yalnızca tek bir açıklama için (ek açıklama olmadan) belirli bir uyarıyı bastırma seçeneği sunmalıdır.

+1

Yanıtlarınız için teşekkür ederiz. Yukarıdaki örnekte, derleyici, bastırıcıları kullanana kadar Guard'ın kullanılmamasından şikayet ederdi, değil mi? Kodumun bu uyarılarla nasıl kirlenmesini önleyebilirim? –

+1

Bu yanıtı tamamlamak için, ANT'deki uyarıları göz ardı etmenin yolu şunun gibidir: '' –

+0

Belki sen bile yapabilirsin: ((AutoClosable)() -> lock.unlock()) {} – Johannes

7

Radiodef'in yanıtını genişletmek için. Bence, kaynaklar ile birlikte çalışarak RAII, java için tamamen kabul edilebilir bir modeldir. Ama aslında

  • uyarı bastırmak için size @SuppressWarnings("try") yerine @SuppressWarnings("unused") kullanmak gerekir.
  • ve yöntemi ek açıklama yerine değişken bildiriminde

uygulanan yukarıdaki noktaları ile bir örnek ekleyin:

@SuppressWarnings("try") 
    void myMethod1() { 
     try(MyResource myVar = new MyResource(..)) { 
      //I am not using myVar here 
     } 
    } 

desen kendisinde genişletilmesi. Okuma-yazma kilitlerini yönetmek için yoğun bir şekilde kullandım ve harika çalıştı. Benim kod

böyle, eşzamanlılık artırmak için bazen önlem amacıyla bazı kaynak kilidini hile kullandım:

try (Guard g1 = new Guard(myLock1)) { 
    someStuffThatRequiresOnlyLock1(); 
    try (Guard g2 = new Guard(myLock2)) { 
     someStuffThatRequiresBothLocks(); 
     if (isSomething) { 
      g1.close(); 
      someMoreSuffThatRequiresOnlyLock2() 
     } else { 
      someMoreSuffThatRequiresBothLocks(); 
     } 
    } 
} 

Kilitler hep aynı sırayla elde edilen, ancak bırakarak gerektiği gibi kilit açma gerçekleştirilir Eşzamanlı işlem için mümkün olduğunca fazla alan. o okuma-yazma kilitleri ile çalışması için ayar tekrarlanan kapanması izin Muhafız sınıfını değiştirmektir:

public class Guard implements AutoCloseable { 
    private final Lock lock; 
    private boolean isClosed = false; 

    public Guard(Lock lock) { 
     this.lock = lock; 
     lock.lock(); 
    } 

    @Override 
    public void close() { 
     if (!isClosed) { 
      isClosed = true; 
      lock.unlock(); 
     } 
    } 
} 
+0

Her kilitleme/kilit açma işleminde nesne oluşturma gerektirmeyen bir çözüm için https://stackoverflow.com/a/48145269/14731 adresine bakın. Dezavantajı, try bloğunun içinde açıkça 'close() 'yapamayacağınızdır. – Gili

İlgili konular