我正在学习Java 8,我正在尝试同时使用lambda和泛型,我编写了这个小示例
import java.util.function.*;
public class LambdaTest<T> {
public T calculate(T x, T y, BiFunction<T, T, T> func) {
return func.apply(x, y);
}
public static void main(String args[]) {
LambdaTest<Integer> l = new LambdaTest<Integer>();
System.out.println("" + l.calculate(10, 10, (x, y) -> x + y));
System.out.println("" + l.calculate(10, 10, (x, y) -> x * y));
System.out.println("" + l.calculate(10, 10, (x, y) -> x / y));
System.out.println("" + l.calculate(10, 10, (x, y) -> x - y));
LambdaTest<Double> l2 = new LambdaTest<Double>();
System.out.println("" + l2.calculate(10.0, 10.0, (x, y) -> x + y));
}
}我有几个问题
(x, y) -> x + y。是否有可能只定义一次。int而不是Integer来定义它。我试着做new LambdaTest<int>,但是它没有起作用。发布于 2015-09-17 22:03:59
BiFunction<Integer, Integer, Integer>类型,另一个是BiFunction<Double, Double, Double>类型。因此,它们彼此不相容。发布于 2015-09-17 22:04:17
x和y都是Integer型,而在第二种类型中,x和y都是Double型。不幸的是,Integer和Double都是Number,没有为通用Number定义+操作。IntBinaryOperator:这是一个对两个int值进行操作并返回int值的函数接口。发布于 2015-09-18 02:26:18
为了求和,可以使用对相应方法的引用:
System.out.println("" + l.calculate(10, 10, Integer::sum));
System.out.println("" + l2.calculate(10.0, 10.0, Double::sum));在这里您可以看到,它实际上不是相同的代码,只是相似。
至于装箱,对于float/double类型,JIT编译器可以内联您的lambda,看到装箱的值不会转义并消除装箱。例如,让我们考虑这样的方法:
public static void testCalculate(double a, double b) {
LambdaTest<Double> l = new LambdaTest<Double>();
double d = l.calculate(a, b, (x, y) -> x + y);
System.out.println(d);
}x64汇编程序的启动方式如下:
# {method} {0x0000000051710670} 'testCalculate' '(DD)V' in 'LambdaTest'
# parm0: xmm0:xmm0 = double
# parm1: xmm1:xmm1 = double
# [sp+0xa0] (sp of caller)
mov %eax,-0x6000(%rsp)
push %rbp
sub $0x90,%rsp ;*synchronization entry
; - LambdaTest::testCalculate@-1 (line 10)
vaddsd %xmm1,%xmm0,%xmm2 ;*dadd
; - LambdaTest::lambda$testCalculate$0@8 (line 11)
; - LambdaTest$$Lambda$1/1555845260::apply@8
; - LambdaTest::calculate@3 (line 6)
; - LambdaTest::testCalculate@24 (line 11)
movabs $0x8c900c78,%r10 ; {oop(a 'java/lang/Class' = 'java/lang/System')}
mov 0x6c(%r10),%r10d
mov (%r10),%rax ; implicit exception: dispatches to 0x0000000005bd3426
mov %rax,%r11
and $0x7,%r11
mov %r10,%r9 ;*getstatic out
; - LambdaTest::testCalculate@35 (line 12)
... the rest is inlined code from PrintStream.println(double);因此,正如您所看到的,整个lambda调用和装箱被展开并简化为单个vaddsd指令。没有调用,没有装箱,没有内存访问,只有两个xmm寄存器。真快啊。
不幸的是,对于Integer/Long来说,由于缓存某些值,产生的汇编程序就不那么干净了。JIT编译器不能仅仅用简单的add替换它,因为它并不确切地知道,例如,对于缓存的Integer.valueOf(10),您实际上将得到原始的10值。谁知道呢,例如,您可能使用反射替换了一些值,使之成为2+2=5。然而,没有创建新的对象:如果缓存中缺少参数,那么实际上不会调用new Integer。
https://stackoverflow.com/questions/32640621
复制相似问题