为什么可以传递方法引用而不是转换器实例?

时间:2017-08-25 05:10:14

标签: lambda java-8 method-reference

我对Java 8中解析的:: lambdas类型有疑问。

给定此示例方法,该方法使用给定的spring-core Converter实现转换对象列表:

public static <S, T> List<T> convertToList(Collection<? extends S> input, Converter<S, T> converter) {
    List<T> results = new ArrayList<>(input != null ? input.size() : 0);
    if (input != null && !input.isEmpty()) {
        for (S element : input) {
            results.add(converter.convert(element));
        }
    }

    return results;
}

然后说我有一个特定的实现,BoatConverter:

public class BoatConverter implements Converter<Boat, BoatConverted> {

    @Override
    public BoatConverted convert(Boat boat) {
       // ...
    }

}

调用此方法的一种方法是:

ConversionHelper.convertToList(response.getBoats(), boatConverter)

但是,我注意到Java编译器(和预期的结果)对此同样满意:

ConversionHelper.convertToList(response.getBoats(), boatConverter::convert)

在这种情况下给定convert()返回一个BoatConverted,但是convertToList()期望一个转换器类型,我的问题是编译器如何解决这个明显的冲突,特别是因为你传入一个lambda的convert()但是convertToList( )实用程序方法想要在传入的预期转换器对象上调用该方法吗?

2 个答案:

答案 0 :(得分:4)

Converter实际上是一个功能界面,因为它只包含一个单一抽象方法:

package org.springframework.core.convert.converter;

public interface Converter<S, T> {
    T convert(S var1);
}

这意味着它可以用作lambda表达式的目标,您的示例可以重写为:

c -> boatConverter.convert(c)

在这种情况下,您的lambda只是将作业委托给现有的Converter实例,并且由于方法签名与接口方法匹配,因此可以用方法引用替换它。

主要区别在于,当您传递boatConverter时,您只是将此实例重新用作Converter,但如果您编写boatConverter::convertc -> boatConverter.convert(c) ,则表示您正在创建将转换委托给Converter

的新boatConverter实例

答案 1 :(得分:2)

基本上转换器实际上与Function(从一种类型转换为另一种类型)相同,它是@FunctionalInterface - 因为它只有一个抽象方法。

这就是编译器可以解决这个问题的原因。考虑这个更简单的例子(IMO):

static class ToUpperCase implements Function<String, String> {

    @Override
    public String apply(String s) {
        return s.toUpperCase();
    }

}

private static List<String> transformList(List<String> input, Function<String, String> f) {
    return input.stream().map(f).collect(Collectors.toList());
}

这两个电话都有效:

transformList(list, func);
transformList(list, func::apply);

但第二部分也可以写得更清楚:

transformList(list, String::toUpperCase);

因此,你的例子可以更明确:

ConversionHelper.convertToList(response.getBoats(), Boat::getYourField)

getYourField显然应该替换为你正在做的事情。我发现这更加冗长,因为它清楚地表明你正在从船只转变为某些领域。

相关问题