我有以下成功执行的表达式:
Function<Long,Long> y = ((Function<Long,Long>)(x -> x*x)).andThen(x -> x+1).andThen(x -> x+2);
我理解为什么这里的第一个lambda表达式需要进行强制转换。但是后面的lambda给出了一个错误;x+1";不是第二个组合lambda表达式的有效操作
Function<Long,Long> y = ((Function<Long,Long>)(x -> x*x)).compose(x -> x+1).compose(x -> x+2);
我能够解决以上错误使用铸造与合成:
Function<Long,Long> y = ((Function<Long,Long>)(x -> x*x)).compose((Function<Long,Long>)x -> x+1).compose(x -> x+2);
我有以下问题:
- 为什么我们需要compose调用而不需要andThen进行强制转换电话
- 为什么我们需要带中间compose调用的强制转换,而不需要带终端组成呼叫
为什么我们需要使用compose调用而不使用andThen调用进行强制转换?
这两种方法不同。CCD_ 1采用其输入的类型不一定与当前函数的参数类型相同的函数。这里有一个稍微修改过的例子,表明编译器不必假定Long
:
Function<Long, Long> f = (x -> x * x);
Function<String, Long> g = f.compose(Long::parseLong);
您可以观察到f.compose()
具有类型为String
的类型自变量。在上面的代码中,它是从赋值上下文推断出来的(即,编译器知道输入是String
类型的,因为生成的函数被分配给了Function<String, Long>
变量(。
然而,当涉及到.andThen()
时,编译器的情况更简单:类型参数<V>
用于给定函数的输出(而不是像compose
那样用于输入(。因为它已经知道输入类型,所以它拥有所有信息:compose()
0只能有Long
作为输出类型,因为Long + int
将产生long
,装箱到Long
。结束。
为什么我们需要使用中间compose调用进行强制转换,而不需要使用终端compose调用?
现在,想想看,如果我写了这个会发生什么?
Function<String, Long> g = f.compose(Long::parseLong).compose(Long::parseLong);
由于赋值上下文的原因,编译器准备推断最后一个.compose()
到String
的<V>
(请参见上文(
问题是:是否应该假定中间.compose()
为String
?答案是Yes(是(在这种情况下*(因为Long.parseLong
只接受字符串,所以没有重载(,但编译器不会这样做;这是一个已知的限制。
我可以让它与f.<String>compose(Long::parseLong).compose(Long::parseLong);
一起工作(当然,由于明显的原因,这会打断我最后一次与.compose()
的通话,但你明白了。
换句话说,你可以用来修复它
A型见证
...<Long>compose(x -> x + 1).compose(x -> x + 2)
显式参数类型(我的首选(
...compose((Long x) -> x + 1).compose(x -> x + 2)
*我说";是的在这种情况下";因为不能期望编译器总是知道类型。这里是明确的,因为带有单个参数的Long.parseLong
没有重载,所以我们可以认为编译器可以将中间.compose()
的<V>
推断为<String>
。但这不应该被理解为编译器应该能够在所有情况下执行这样的推理。传递给.compose()
的函数可以是采用任何其他参数类型的函数。现在讨论的结束是编译器不支持这种推理
如果您运行以下代码。
Function<Long,Long> y1 = ((Function<Long,Long>)(x -> x*x)).andThen(x -> x+1).andThen(x -> x+2);
System.out.println(y1.apply(10l));
Function<Long,Long> y2 = ((Function<Long,Long>)(x -> x*x)).compose((Long x) -> x+1).compose(x -> x+2);
System.out.println(y2.apply(10l));
即使我们用相同的值(10(运行两个函数,它也会返回不同的值。使用andThen
时返回103(10x10+(1+2((,使用compose
时返回169(10+1+2,13x13(。因此,compose
在乘法lambda应用之前被调用,并且compose
获得Function<Object, Long>
作为参数而不是Function<Long, Long>
。compose对于之前发生的任何lambda都没有可见性,因为它将是第一个被调用的。
由于调用compose
时没有上下文,我们需要强制转换为Function<Long, Long>
,或者像我所做的那样在lambda本身中使用类型。希望这能有所帮助。