为什么我不能将lambda分配给无类型谓词引用?但是可以为其分配初始化的类型谓词引用吗?

时间:2018-07-26 16:50:02

标签: java lambda java-8 predicate functional-interface

在尝试创建基于方法参数类型使用的自定义谓词引用时,我注意到了一些奇怪的事情。

我有一个名为AffiliateLinkSubset的对象,它有一个名为isGeneral的布尔型吸气剂。当我尝试执行以下操作时:

Predicate<?> partitionPredicate = AffiliateLinkSubset::isGeneral;

我收到错误non-static method cannot be referenced from a static context

但是当我将通用类型AffiliateLinkSubset分配给谓词时,这没什么特别的。然而,特别的是,以下内容也起作用:

Predicate<AffiliateLinkSubset> partitionPredicate = affiliateLinkSubset::isGeneral;
Predicate<?> test = partitionPredicate;

IDE对此没有错误!即使我实际上将相同的lambda分配给了无类型谓词测试。这怎么可能?谓词会在运行时起作用吗?我猜想是因为在编译过程中所有类型都被擦除并替换为Object类型。这就是为什么我不明白为什么无法分配无类型谓词lambda的原因。谁能解释?

AffiliateLinkSubset是实际类的缩写,在这里是:

import POJOs.PojoENUMS.LocalizedStorefront;

import java.util.Map;
import java.util.Set;

public class AffiliateLinkSubsetForStatisticsCalculation {
    private Long id;
    private String title;
    private Double productValue;
    private boolean general;
    private Set<String> keywords;
    private Map<String, Boolean> booleanKeywords;
    private LocalizedStorefront localizedStorefront;

    public AffiliateLinkSubsetForStatisticsCalculation(Long id, String title, Double productValue, boolean general, Set<String> keywords, Map<String, Boolean> booleanKeywords, LocalizedStorefront localizedStorefront) {
        this.id = id;
        this.title = title;
        this.productValue = productValue;
        this.general = general;
        this.keywords = keywords;
        this.booleanKeywords = booleanKeywords;
        this.localizedStorefront = localizedStorefront;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Double getProductValue() {
        return productValue;
    }

    public void setProductValue(Double productValue) {
        this.productValue = productValue;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public boolean isGeneral() {
        return general;
    }

    public void setGeneral(boolean general) {
        this.general = general;
    }

    public Set<String> getKeywords() {
        return keywords;
    }

    public void setKeywords(Set<String> keywords) {
        this.keywords = keywords;
    }

    public Map<String, Boolean> getBooleanKeywords() {
        return booleanKeywords;
    }

    public void setBooleanKeywords(Map<String, Boolean> booleanKeywords) {
        this.booleanKeywords = booleanKeywords;
    }

    public LocalizedStorefront getLocalizedStorefront() {
        return localizedStorefront;
    }

    public void setLocalizedStorefront(LocalizedStorefront localizedStorefront) {
        this.localizedStorefront = localizedStorefront;
    }
}

2 个答案:

答案 0 :(得分:4)

首先,由于类型未知,Predicate<?> predicate无法正常工作。他们中的任何一个都可以工作:

Predicate<? extends AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;
Predicate<AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;

方法引用快捷方式AffiliateLinkSubset::isGeneral被理解为object -> object.isGeneral(),其中objectAffiliateLinkSubset的类型。这就是为什么第一个谓词无法工作的原因,因为<?>并未定义AffiliateLinkSubset的类型。 isGeneral()中未定义Object方法。

让我们继续。如果您输入:

Predicate<?> partitionPredicate = object -> AffiliateLinkSubset.isGeneral();

由于您将类方法isGeneral()视为静态方法,因此无法编译。为此,您需要一个可以调用此方法的类的实例:

AffiliateLinkSubset affiliateLinkSubset = new AffiliateLinkSubset();
Predicate<?> partitionPredicate = object -> affiliateLinkSubset.isGeneral();

现在,objectObject的实例,结果依赖于lambda的右侧,该lambda不会触及object且与输入无关,因此这可能也可以:

Supplier<Boolean> supplier = () -> affiliateLinkSubset.isGeneral();

这没有多大意义,所以我想您已经提到过的解决方案:

Predicate<? extends AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;

答案 1 :(得分:1)

AffiliateLinkSubsetForStatisticsCalculation::isGeneral 

表示

(AffiliateLinkSubsetForStatisticsCalculation i) -> i.isGeneral()

同时

affiliateLinkSubsetForStatisticsCalculationInstance::isGeneral

是指(1)boolean isGeneral(Object o)的实例方法AffiliateLinkSubsetForStatisticsCalculation或(2)boolean isGeneral()的实例方法Object

由于这些方法都不存在,因此您可以编写方法参考。但是您可以写一个lambda:

Predicate<?> p = (Object i) -> affiliateLinkSubsetForStatisticsCalculationInstance.isGeneral();

* {AffiliateLinkSubsetForStatisticsCalculation是类名。
** {affiliateLinkSubsetForStatisticsCalculationInstance是该类的实例。