2017-03-22 25 views
0

問題代碼如下。Java 8 lambda不喜歡額外的括號?

private ObjectMapper mapper = new ObjectMapper(); 
@Override 
     public List<GameSession> getAllGameSessions() { 
      try { 
       return Files.list(Paths.get(BASE_DIR)).filter(path -> path.getFileName().toString().endsWith(FILE_FORMAT_JSON)) 
         .map(path -> { 
          try (BufferedReader bufferedReader = Files.newBufferedReader(path)) { 
           return (mapper.readValue(bufferedReader, GameSession.class)); 
          } catch (IOException ioException) { 
           ioException.printStackTrace(); 
           return null; 
          } 
         }).filter(gameSession -> gameSession!=null).collect(Collectors.toList()); 
      } catch (IOException e) { 
       e.printStackTrace(); 
       return Collections.emptyList(); 
      } 
     } 

當我啓動的應用程序(春季啓動),我得到略帶神祕的風格例外其內容爲:

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled. 
2017-03-22 20:04:34.269 ERROR 26812 --- [   main] o.s.boot.SpringApplication    : Application startup failed 

java.lang.VerifyError: Inconsistent stackmap frames at branch target 49 
Exception Details: 
    Location: 
    com/x/game/repository/FileSystemGameSessionRepositoryImpl.lambda$getAllGameSessions$1(Ljava/nio/file/Path;)Lcom/x/game/model/GameSession; @49: aload 
    Reason: 
    Type 'java/lang/Object' (current frame, locals[4]) is not assignable to 'com/x/game/model/GameSession' (stack map, locals[4]) 
    Current Frame: 
    bci: @20 
    flags: { } 
    locals: { 'com/x/game/repository/FileSystemGameSessionRepositoryImpl', 'java/nio/file/Path', 'java/io/BufferedReader', null, 'java/lang/Object' } 
    stack: { 'java/io/BufferedReader' } 
    Stackmap Frame: 
    bci: @49 
    flags: { } 
    locals: { 'com/x/game/repository/FileSystemGameSessionRepositoryImpl', 'java/nio/file/Path', 'java/io/BufferedReader', 'java/lang/Throwable', 'com/x/game/model/GameSession' } 
    stack: { } 
    Bytecode: 
    0x0000000: 2bb8 0006 4d01 4e2a b400 042c 1207 b600 
    0x0000010: 083a 042c c600 1d2d c600 152c b600 0aa7 
    0x0000020: 0012 3a05 2d19 05b6 000c a700 072c b600 
    0x0000030: 0a19 04b0 3a04 1904 4e19 04bf 3a06 2cc6 
    0x0000040: 001d 2dc6 0015 2cb6 000a a700 123a 072d 
    0x0000050: 1907 b600 0ca7 0007 2cb6 000a 1906 bf4d 
    0x0000060: 2cb6 000e 01b0       
    Exception Handler Table: 
    bci [27, 31] => handler: 34 
    bci [7, 19] => handler: 52 
    bci [7, 19] => handler: 60 
    bci [70, 74] => handler: 77 
    bci [52, 62] => handler: 60 
    bci [0, 49] => handler: 95 
    bci [52, 95] => handler: 95 
    Stackmap Table: 
    full_frame(@34,{Object[#72],Object[#105],Object[#74],Object[#75],Object[#91]},{Object[#75]}) 
    same_frame(@45) 
    same_frame(@49) 
    full_frame(@52,{Object[#72],Object[#105],Object[#74],Object[#75]},{Object[#75]}) 
    same_locals_1_stack_item_frame(@60,Object[#75]) 
    full_frame(@77,{Object[#72],Object[#105],Object[#74],Object[#75],Top,Top,Object[#75]},{Object[#75]}) 
    same_frame(@88) 
    same_frame(@92) 
    full_frame(@95,{Object[#72],Object[#105]},{Object[#77]}) 

    at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_121] 
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[na:1.8.0_121] 
    at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[na:1.8.0_121] 
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:613) ~[spring-core-4.3.7.RELEASE.jar:4.3.7.RELEASE] 

顯然有問題的文字是:

Type 'java/lang/Object' (current frame, locals[4]) is not assignable to 'com/x/game/model/GameSession' (stack map, locals[4]) 

我也是做一些過於聰明的事情,或者Java 8再次有一些我尚未發現的lambda限制?

IntelliJ很高興,運行時不是。如果我用new GameSession();替換整個lambda地圖塊,然後過得愉快。

回答

3

我想,這與horrible way, javac compiles try(…) constructs有關,但這只是一個猜測。至少,我可以證實,這種行爲是可重複使用以下MCVE不使用任何第三方代碼或字節碼轉換工具:

import java.util.function.Supplier; 
import java.util.stream.Collectors; 
import java.util.stream.Stream; 

public class Tmp { 
    static <T> T readValue(Supplier<T> s, Class<T> type) throws Exception { 
     return s.get(); 
    } 
    interface Source extends Supplier<String>, AutoCloseable { 
     public default void close() throws Exception {} 
    } 

    public static void main(String[] args) { 
     Stream.of("one", "two", "three") 
       .map(s -> { 
        try(Source source =() -> s) { 
         return (readValue(source, String.class)); 
        } 
        catch(Exception ex) { 
         return null; 
        } 
       }) 
       .forEach(System.out::println); 
    } 
} 

可測試上Ideone和去除牙套確實indeed change the result


據我所見,這會影響所有版本的Java 8和更早版本的Java 9(適用於b66和更新版本)。

+1

你永遠不會抓住我來驚歎!你連接的答案是絕對精彩的。 – Eugene

0

發現問題...在return (mapper.readValue(bufferedReader, GameSession.class));

額外的支架錯字,我始終認爲,額外的括號沒有任何區別。那麼,這個令人愉快的例外就是它的確證明。任何人都渴望解釋,我會接受解釋這種行爲的答案。

更新了問題標題,以便其他人可以找到解決方案。

0

這是最有可能沒有相關這些括號,而是一些字節碼操作工具,你正在使用(可能甚至不知道它)。它可能是JRebel或Spring Boot的彈簧加載程序等。

當你放這些括號時,你可能做了更多的事情,比如去除舊戰爭,清理某些東西等,這就是它工作的原因。

+3

相信與否,大括號*做*有所作爲,沒有任何字節碼處理工具/庫涉及... – Holger