根据生成的字节码:
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Lambda:
private static java.lang.Integer lambda$main$0(java.lang.Integer);
descriptor: (Ljava/lang/Integer;)Ljava/lang/Integer;
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=1
0: aload_0
1: invokevirtual #9 // Method java/lang/Integer.intValue:()I
4: iconst_1
5: iadd
6: invokestatic #6 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
9: dup
10: astore_0
11: astore_1
12: aload_0
13: areturn
LineNumberTable:
line 20: 0
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 t Ljava/lang/Integer;
匿名类:
public java.lang.Integer get(java.lang.Integer);
descriptor: (Ljava/lang/Integer;)Ljava/lang/Integer;
flags: ACC_PUBLIC
Code:
stack=2, locals=4, args_size=2
0: aload_1
1: astore_2
2: aload_1
3: invokevirtual #2 // Method java/lang/Integer.intValue:()I
6: iconst_1
7: iadd
8: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
11: dup
12: astore_1
13: astore_3
14: aload_2
15: areturn
LineNumberTable:
line 16: 0
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this LTest$1;
0 16 1 t Ljava/lang/Integer;
如您所见,在匿名类中,从局部变量表(方法参数 t)加载变量后,运行时将参数的副本存储在另一个变量中(astore_2),然后使用此参数副本作为返回值。
Lambda 方法不会复制参数(加载 -> 取消框 ->添加 1 个 -> 框 ->存储 ->加载 -> 返回)。
更新
这绝对是一个javac错误。
我从 http://hg.openjdk.java.net/jdk8u/jdk8u 那里得到了源代码
匿名类和 lambda 转换为以下中间表示形式:
@Override()
public Integer get(Integer t) {
return (let /*synthetic*/ final Integer $112619572 = t in
(let /*synthetic*/ final Integer $1295226194 = t = Integer.valueOf((int)(t.intValue() + 1)) in $112619572));
}
/*synthetic*/ private static Integer lambda$main$0(final Integer t) {
return (let /*synthetic*/ final Integer $1146147158 = t = Integer.valueOf((int)(t.intValue() + 1)) in t);
}
在 lambda 生成的方法参数标记为 final,因为 LambdaToMethod 转换器将所有参数标记为 FINAL(根据源代码 LambdaTranslationContext.translate(...):1899年)。
然后让表达式生成器检查变量标志,如果它是最终的,则省略临时变量生成(根据源代码Lower.abstractRval(...):2277),因为修改被认为是被禁止的。
可能的解决方案:
- 禁止在 lambda 或
-
从局部变量中删除 FINAL 标志 (LambdaTranslationContext.translate(...):1894) 和参数 (LambdaTranslationContext.translate(...):1899) 在 lamda 生成方法:
case LOCAL_VAR:
ret = new VarSymbol(FINAL, name, types.erasure(sym.type), translatedSym);
...
case PARAM:
ret = new VarSymbol(FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym);
...
我删除了 FINAL 标志,并从以下位置获得了预期的测试结果:https://bugs.openjdk.java.net/browse/JDK-8038420