2012-11-04 14 views
12

Chạy mã bên dưới dẫn đến thông báo lỗi Bad type on operand stack.Loại không hợp lệ trên ngăn xếp hạng ... sử dụng jdk 8, lambdas với các lớp bên trong vô danh không thành công, tại sao?

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

Tuy nhiên việc loại bỏ dấu ngoặc kép đôi (các lớp bên trong vô danh) trong lamda cho phép mã chạy như mong đợi, tại sao? Các công trình bên dưới:

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

Lỗi trình biên dịch? Đây là phiên bản đầu truy cập sau khi tất cả ...

(Điều này sẽ không biên dịch trừ khi bạn có mới nhất jdk 8 lambda download.)

+0

Thẻ lambda có nghĩa là cho các ngôn ngữ khác ngoài Java như C#, C++. – Lion

+8

@Lion: Tôi tin rằng Java 8 thực hiện lambdas (tôi chưa bao giờ sử dụng nó, vì vậy tôi không biết điều này cho một thực tế), và vì vậy thẻ này dường như là thích hợp cho câu hỏi. –

+11

@Lion đó là chỉ vì Java đã không có lambdas trước đây. Một lambda là một lambda, ngay cả khi nó là một phiên bản alpha của ngôn ngữ. –

Trả lời

7

Dường như, sự cố đó không chỉ xảy ra trong trường hợp khi lambda trả về loại anonymous, nhưng ngay cả khi có bất kỳ lớp ẩn danh nào được xây dựng bên trong lambda. I.e .:

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

Điều này thực sự dẫn đến Exception in thread "main" java.lang.VerifyError: Bad local variable type (...) Reason: Type top (current frame, locals[0]) is not assignable to reference type.

Điều tra thêm cho thấy rằng nếu chúng tôi giới thiệu tham số vào phương pháp xxx, lý do ngoại lệ sẽ chứa loại của nó. Ví dụ:

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

Và điều này đã rất thú vị. Chúng ta hãy thay đổi loại xxx tham số (mà không thực sự sử dụng) để gõ của đầu lớp, ví dụ: TestLambda:

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

Và bạn nghĩ gì? Điều này khắc phục sự cố! Mọi thứ bắt đầu hoạt động tốt. Ngay cả, nếu chúng tôi sẽ thay đổi return A(); thành return new A() {};. Kiểm tra điều này!


Kết luận của tôi là đây là số thực Lỗi JVM. Dường như, vấn đề là với chồng các lớp được nạp. Nó xuất hiện kết hợp với phương pháp, trong đó Java sử dụng để dịch các biểu thức lambda (http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html) - nó tạo ra các phương thức tổng hợp bên trong lớp cao nhất. Dường như, khi các lớp ẩn danh được giới thiệu trong ngăn xếp lambda bị hỏng. Nó có thể được cố định bằng cách sử dụng cách giải quyết được đề cập.

2

biên dịch lỗi? Đây là phiên bản tiếp cận sớm sau khi tất cả ...

Tôi có thể nói rằng bất kỳ thông báo lỗi mà đề cập đến operand stack là rất có khả năng là một do một lỗi biên dịch hoặc một lỗi trong JVM. Đặc biệt là nếu bạn có thể lấy nó bằng một ví dụ Java thuần túy.

(Dường như JVM được báo cáo một vấn đề typesafety mà lẽ ra phải được phát hiện bởi trình biên dịch, và/hoặc người xác minh bytecode lúc đẳng cấp tải.)

Báo cáo nó thông qua kênh khuyến khích cho Java 8 lỗi.

1

Không liên quan trực tiếp đến vấn đề của bạn, nhưng tôi muốn mạnh mẽ khuyên bạn không nên sử dụng các lớp ẩn danh theo cách này. Bạn đang tạo một loại phụ HashSet hoàn toàn mới chỉ nhằm mục đích thêm hai giá trị vào nó. Điều này không chỉ làm cho hệ thống (nó nằm trong bộ nhớ mãi mãi) nó còn có thể làm nhiễu JIT của JVM vì nó không bao giờ chỉ thấy HashSet tại một trang gọi ... nó thấy một trong nhiều kiểu con mà bạn đã tạo ra.

Các vấn đề liên quan