2012-11-04 11 views
12

Aşağıdaki kodu çalıştırmak, Bad type on operand stack hata iletisiyle sonuçlanır.İşlenen yığınında hatalı tip ... jdk 8 kullanılarak, anonim iç sınıflara sahip lambeler başarısız, neden?

public static void main(String args[]) { 
     TransformService transformService = (inputs) -> { 
      return new ArrayList<String>(3) {{ 
       add("one"); 
       add("two"); 
       add("three"); 
      }}; 
     }; 

     Collection<Integer> inputs = new HashSet<Integer>(2) {{ 
      add(5); 
      add(7); 
     }}; 
     Collection<String> results = transformService.transform(inputs); 
     System.out.println(results.size()); 
    } 

    public interface TransformService { 
     Collection<String> transform(Collection<Integer> inputs); 
    } 

Ancak beklendiği gibi kod çalışmasına olanak tanır: Lamda içinde çift ayracı başlatma (anonim iç sınıflar) çıkarmadan, neden? Aşağıdaki işler:

public class SecondLambda { 
    public static void main(String args[]) { 
     TransformService transformService = (inputs) -> { 
      Collection<String> results = new ArrayList<String>(3); 
      results.add("one"); 
      results.add("two"); 
      results.add("three"); 

      return results; 
     }; 

     Collection<Integer> inputs = new HashSet<Integer>(2) {{ 
      add(5); 
      add(7); 
     }}; 
     Collection<String> results = transformService.transform(inputs); 
     System.out.println(results.size()); 
    } 

    public interface TransformService { 
     Collection<String> transform(Collection<Integer> inputs); 
    } 
} 

Derleyici hata? Ne de olsa erken erişim sürümü ...

(son jdk 8 lambda download olmadığı sürece bu derleme olmayacaktır.)

+0

Etiket lambda, C#, C++ gibi Java dışındaki diller içindir. – Lion

+8

@Lion: Java 8'in lambdaları uyguladığına inanıyorum (hiç kullanmadım, bu yüzden bir gerçeği bilmiyorum), ve bu etiket bu soru için uygun gibi görünüyor. –

+11

@Lion, bu sadece Java'nın daha önce lambda yapmamış olması. Bir lambda, dilin bir alfa sürümünde olsa bile, bir lambdadır. –

cevap

7

Bu sorun, yalnızca lambda'un anonymous türünü döndürdüğü durumlarda değil, aynı zamanda lambda içine herhangi bir anonim sınıf oluşturulsa bile sorun ortaya çıkar. Yani .:

public class TestLambda { 
    public static void main(String[] args) { 
     xxx(); 
    } 
    static void xxx() { 
     Functional1 f =() -> { 
      Object o = new Object() { }; 
      return new A(); 
     }; 
    } 
    static class A { } 
    static interface Functional1 { A func(); } 
} 

Bu aslında Exception in thread "main" java.lang.VerifyError: Bad local variable type (...) Reason: Type top (current frame, locals[0]) is not assignable to reference type yol açar.

Diğer araştırmalar, parametreyi xxx yöntemine dahil edersek, bir istisnanın nedeninin türünü içereceğini gösterir. Örn .:

Type 'java/lang/Integer' (current frame, stack[0]) is not assignable to 'lambda/TestLambda'

Ve bu zaten çok ilginç. en, üst sınıfının yazmak için (aslında kullanılmaz) xxx parametrenin türünü değiştirmek edelim yani TestLambda:

... 
    xxx(new TestLambda()); 
} 
private static void xxx(TestLambda x) { 
... 

Ve ne düşünüyorsunuz? Bu, sorunu giderir! Her şey işe yarıyor. Hatta return A();'u return new A() {}; olarak değiştirirsek bile. Şuna göz at!


Benim sonuç bu gerçek JVM hata olmasıdır. Görünüşe göre sorun, yüklü sınıfların yığını ile. Java'un lambda ifadelerini (http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html) çevirmek için kullandığı yöntemle birleştiğinde oluşur - üst sınıfın içinde sentetik yöntemler üretir. Görünüşe göre, anonim sınıflar lambda yığınının içine yerleştirildiğinde yığın bozulur. Belirtilen geçici çözüm kullanılarak düzeltilebilir.

2

Derleyici hata nedir? Bu

Ben işlenen yığınına bahseder hata iletisi derleyici hata veya JVM bir hatadan bir nedeni olması büyük olasılıkla olduğunu söyleyebilirim ... sonuçta erken erişim versiyonudur. Özellikle saf bir Java örneği kullanarak alabilirsiniz.

(O JVM derleyici tarafından algılanması gerekir bir typesafety sorunu bildiren gibi görünüyor ve/veya sınıf-yükleme sırasında baytkodu doğrulayıcı.) Java 8 için tavsiye kanalı üzerinden

Raporu onu böcek.

1

Sorununuzla doğrudan ilgili değil, ancak kesinlikle bu şekilde anonim sınıfları kullanmamanızı öneririz. Sadece iki değer eklemek amacıyla tamamen yeni bir HashSet alt türü oluşturuyorsunuz. Bu sadece sistemi şişirmekle kalmaz (aynı zamanda sonsuza kadar bellekte kalır), aynı zamanda JVM'nin JIT'sini de karıştırır, çünkü HashSet'i bir arama sitesinde asla görmez ... yarattığınız birçok alt türden birini görür.

İlgili konular