2014-07-01 16 views
17

Aşağıdaki sınıf, bir anonim iç sınıf örneği ile başlatılan runnable üye değişkeni içerir. iç sınıf aynı elemanı referanslar:Neden Java 8'deki lambdas, anonim sınıfların bulunmadığı üye değişkenlerine referans göndermez?

class Example { 
    Runnable runnable = new Runnable() { 
     @Override 
     public void run() { 
      System.out.println(runnable); 
     } 
    }; 
} 

Bu sürece birine tahsis JLS bir referansı edilmeden önce bir yöntem yürütülmez gibi bir sorun değildir. Aşağıdaki ile javac 1.8.0_05 tarafından Anladığım kadarıyla

Runnable runnable =() -> System.out.println(runnable); 

, bu önceki örneğe işlevsel olarak eşdeğer, ancak reddedilir:

üye değişkeni beyanı teorik böyle bir lambda ifadesi dönüştürülebilir olabilir Hata iletisi:

Error:(2, 54) java: self-reference in initializer 

Bu ifade doğru olsa da, bunun neden izin verilmediğini anlamıyorum. Bu kasten izin verilmiyordu, belki de lambda ifadeleri izin verirse sorunlara yol açacak farklı bayt koduna derlenmişlerdir? Ya da sadece izin verilmiyordu çünkü bu referanslar ile anonim iç sınıflarda kullanıldığında problemler vardı. Ya da JLS yazarları tarafından kasıtsız olarak izin verilmiyor muydu? Yoksa javac'da bir hata mı? Tam olarak bunu açıklar.

+8

Tutulma sırasında, bu çalışır: 'Runnable runnable =() -> System.out.println (bu.runnable); 'Sadece bu 'niteleyici eklenmeden başarısız. –

cevap

23

Bug #JDK-8027941 tam olarak bunu açıklar. Dan Smith (Project Lambda Specification Lead), lambdalarla sınırlı olmamakla birlikte, bir hata olmadığını yazıyor. a related bug report üzerine yorumlarda

, onu böyle koyar:

8.3.2.3: Kullanım alanı bildirimi önce oluşursa İlk olarak, bir saha başlatıcısı bir alanın genel olarak yasaktır "kullanmak" . Spesifik bu konuda çok açık değildir, ancak niyet her zaman "önce" alanın kendi başlatıcısı içerdiği olmuştur. Yani "int x = x+1;" geçerli bir alan bildirimi değil.

O da Uyarılar:

Olurdu mümkün anonim sınıfların organları (ya da daha genel olarak izin lambda kendisi başvurmak için olduğu gibi, özel olarak lambda organları tedavi edecek bir özellik eklemek eğer değişken bir başlatıcı ise), ancak bu yapılmamıştır. (FWIW, 8.3.2.3 bir basit çimdik 4 mermi kullanımından tamamen güvenli değildir, tıpkı tamamen güvenli olmaz. "Function f = (Function) ((Function) e -> f.apply(e)).apply(null);")

Sorun Java tasarımcıları istiyorum olduğunu düşünüyorum Daha karmaşık, semantik kod analizine bağlı olmak yerine, ne tür ifadelere izin verildiğine karar vermek için basit, sözdizimsel kurallara sahip olmak. Yarar muhtemelen daha basit bir özellik ve bu nedenle derleyiciler için daha az gerekliliktir, maliyet ise programcıların her programı - en azından istedikleri şekilde - ifade edememesidir. Marko Topolnik işaret ettiği gibi


, bir çözümü var: tam alanını nitelemek. Hata raporundan örnek:

import java.util.function.Function; 

public class LambdaSelfRef { 

    // COMPILATION FAILURE 
    public static Function<Object, Object> op1 = e -> op1.apply(e); 

    // COMPILES OK 
    public static Function<Object, Object> op2 = e -> LambdaSelfRef.op2.apply(e); 

    /* ... */ 
} 
İlgili konular