如何使用方法引用创建可重用的可选映射?

How to create reusable optional mapping with method references?

虽然我正在尝试将可选功能与方法引用一起使用,但我真的很困惑如何使用可重用代码对其进行优化。我想我在尝试使用所有这些新功能(对我来说)的同时我决定摆脱 java-6 风格,现在我想我不能简单地思考,我觉得它变得过于复杂。我如何创建

List<BooleanExpression> expressionMapping = new ArrayList<>();

    if (request != null) { // request is input parameter, a DTO

        Optional.ofNullable(request.getPlantId())
            .map(campaign.plant.id::contains) // campaign is static created by Querydsl
            .ifPresent(expressionMapping::add);

        Optional.ofNullable(request.getTitle())
            .map(campaign.title::containsIgnoreCase)
            .ifPresent(expressionMapping::add);

        Optional.ofNullable(request.getCampaignNumber())
            .map(this::getLikeWrapped)
            .map(campaign.campaignNumber::like)
            .ifPresent(expressionMapping::add);
... 20 more Optional bunch of code like this
}

像以前一样使用 Optional 编写此代码时也遇到了问题:

if (request.getLockVehicle() != null) {
            if (request.getLockVehicle()) {
                expressionMapping.add(campaign.lockVehicle.isNotNull());
            } else {
                expressionMapping.add(campaign.lockVehicle.isNull());
            }
        }

使用 Optional 的目的是告知谁在调用该方法/参数它可能是 null

在你的代码的第一部分,你没有从中得到任何好处,你只是重写了一些围绕 Optional 逻辑包装它的代码,但是,正如你所说,没有任何 "reusable"目的。

一种有用的方法是将其用作方法的 returning 值:例如,如果您知道 title 可能为 null,则可以重构 getter,例如

public Optional<String> getTitle(){
    return Optional.ofNullable(this.title); //I'm guessing the 'title' variable here
}

这将对您有所帮助:每次调用 getTitle() 时,您都会知道它可能为空,因为您获得的是 Optional<String> 而不是 String.

这将使您到达:

request.getTitle().ifPresent(title-> title.doSomething())
// you can also add something like .orElse("anotherStringValue")

第二个示例可以作为第一个示例进行修改,将 getLockVehicle() 的 return 设为 Optional<Boolean>,即使我在这里建议在您的 class,可能 false... Optional<Boolean> 恕我直言

希望这能帮助您理清思绪

如何使用 enum 声明 Request 中的所有字段并将其用作代码的公共部分。我没有查,这只是为了展示我的做法:

public enum RequestField {
    PLANT_ID(Request::getPlantId, (val, campaign) -> campaign.plant.id::contains),
    TITLE(Request::getTitle, (val, campaign) -> campaign.title::containsIgnoreCase),
    CAMPAIGN_NUMBER(Request::getCampaignNumber, (val, campaign) -> campaign.campaignNumber::like),
    // ... more fields here ...
    ;

    private final Function<Request, Optional<Object>> get;
    private final BiFunction<Object, Campaign, BooleanExpression> map;

    RequestField(Function<Request, Object> get, BiFunction<Object, Campaign, BooleanExpression> map) {
        this.get = get.andThen(Optional::ofNullable);
        this.map = map;
    }

    public static List<BooleanExpression> getBooleanExpressions(Request request, Campaign campaign) {
        if (request == null)
            return Collections.emptyList();

        List<BooleanExpression> res = new LinkedList<>();

        for (RequestField field : values())
            field.get.apply(request)
                     .map(r -> field.map.apply(r, campaign))
                     .ifPresent(res::add);

        return res.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(res);
    }
}

您的客户端代码将如下所示:

List<BooleanExpression> booleanExpressions = RequestField.getBooleanExpressions(request, campaign);

P.S. 您的最后一个代码可能如下所示:

if (request.getLockVehicle() != null)
    expressionMapping.add(request.getLockVehicle() ? campaign.lockVehicle.isNotNull() : campaign.lockVehicle.isNull());