为什么compose方法需要casting,而andThen方法不需要casting



我有以下成功执行的表达式:

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

我有以下问题:

  1. 为什么我们需要compose调用而不需要andThen进行强制转换电话
  2. 为什么我们需要带中间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.compose和Function.andThen的行为不相同且不可交换。

如果您运行以下代码。

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本身中使用类型。希望这能有所帮助。

相关内容

最新更新