在现有Java 7代码中使用Java 8可选

在现有Java 7代码中使用Java 8可选,java,java-8,optional,flatmap,null-check,Java,Java 8,Optional,Flatmap,Null Check,我有一个作业,其中我需要将以下Java 8之前的代码转换为Java 8代码。下面是一个让我很难完成的方法: public static List<VehicleMake> loadMatching(Region region, String nameStartsWith, VehicleLoader loader) { if ((nameStartsWith == null) || (region == null) || (loader == null)) {

我有一个作业,其中我需要将以下Java 8之前的代码转换为Java 8代码。下面是一个让我很难完成的方法:

  public static List<VehicleMake> loadMatching(Region region, String nameStartsWith, VehicleLoader loader) {
    if ((nameStartsWith == null) || (region == null) || (loader == null)) {
        throw new IllegalArgumentException("The VehicleLoader and both region and nameStartsWith are required when loading VehicleMake matches");
    }
    List<VehicleMake> regionMakes = loader.getVehicleMakesByRegion(region.name());
    if (regionMakes == null) {
        return null;
    }
    List<VehicleMake> matches = new ArrayList<>(regionMakes.size());
    for (VehicleMake make : regionMakes) {
        if ((make.getName() == null) || !make.getName().startsWith(nameStartsWith)) {
            continue;
        }
        matches.add(make);
    }
    return matches;
}
编辑:通过不将参数传递给方法引用,删除了
flatMap
,并更正了代码。但是现在它不允许我通过
region.name()
getVehicleMakesByRegion()

编辑:将使用者传递到
ifPresent()

Optional<List<VehicleMake>> regionMakes = Optional.ofNullable(loader).ifPresent(()-> loader.getVehicleMakesByRegion(Optional.ofNullable(region).ifPresent(()->region.name()));
Optional regionMakes=Optional.ofNullable(loader).ifPresent(()->loader.getVehicleMakesByRegion(Optional.ofNullable(region).ifPresent(()->region.name());

我已经用
可选的
更新了您的代码:

     public static List<VehicleMake> loadMatchingJava8(Region region, String nameStartsWith, VehicleLoader loader) {
        Optional<List<VehicleMake>> regionMakes = Optional.ofNullable(region)
                .flatMap(r -> Optional.ofNullable(loader).map(l -> l.getVehicleMakesByRegion(r.name())));

        return Optional.ofNullable(nameStartsWith)
                .map(s -> regionMakes
                    .map(Collection::stream)
                    .orElse(Stream.empty())
                    .filter(make -> make.getName() != null && make.getName().startsWith(s))
                    .collect(Collectors.toList()))
                .orElse(Collections.emptyList());
    }
publicstaticlist-loadMatchingJava8(Region-Region,字符串名称startswith,VehicleLoader-loader){
Optional regionMakes=Optional.ofNullable(区域)
.flatMap(r->Optional.ofNullable(loader).map(l->l.getVehicleMakesByRegion(r.name()));
返回可选的.ofNullable(nameStartsWith)
.map->regionMakes
.map(集合::流)
.orElse(Stream.empty())
.filter(make->make.getName()!=null&&make.getName().startsWith)
.collect(收集器.toList())
.orElse(Collections.emptyList());
}

如果您确实想将流量控制转换为
可选
,则代码应与您的一致(我将代码分成两行进行打印):

public静态可选加载匹配java8(Region,
字符串名称开始,
车辆装载机(装载机){
if((nameStartsWith==null)| |(region==null)| |(loader==null)){
抛出新的IllegalArgumentException(“车辆装载机和区域和”+
“加载车辆匹配项时需要的名称开始”);
}
返回可选的.ofNullable(loader.getVehicleMakesByRegion(region.name()))
.map(makers->makers.stream()
.filter((it)->it.getName()!=null
&&it.getName().startsWith(nameStartsWith))
.collect(Collectors.toList());
}

注意:您可以在这篇文章中看到更多关于为什么不滥用
可选

我不能说这很优雅,但它应该满足您的要求。没有明确的空检查,但如果任何输入参数为空,它将抛出异常,并从结果列表中过滤出具有无效名称的车辆。

public static List<VehicleMake> loadMatching(Region region, String nameStartsWith, VehicleLoader loader) {
    return Optional.ofNullable(nameStartsWith)
            .flatMap(startWith -> Optional.ofNullable(loader)
                    .flatMap(vl -> Optional.ofNullable(region)
                            .map(Region::name)
                            .map(vl::getVehicleMakesByRegion))
                    .map(makes -> makes.stream()
                            .filter(make -> Optional.ofNullable(make.getName())
                                    .filter(name -> name.startsWith(startWith))
                                    .isPresent())
                            .collect(Collectors.toList())))
            .orElseThrow(() -> new IllegalArgumentException("The VehicleLoader and both region and nameStartsWith are required when loading VehicleMake matches"));
公共静态列表加载匹配(区域、字符串名称开始、车辆加载程序加载程序){
返回可选的.ofNullable(nameStartsWith)
.flatMap(startWith->Optional.ofNullable(加载器)
.flatMap(vl->可选的空值(区域)
.map(区域::名称)
.map(vl::getVehicleMakesByRegion))
.map(make->make.stream()
.filter(make->Optional.ofNullable(make.getName())
.filter(name->name.startsWith(startWith))
.isPresent())
.collect(收集器.toList()))
.ORELSETROW(()->新的ILLEGARGUMENTEXCEPTION(“加载车辆匹配项时需要车辆加载程序以及区域和名称启动程序”));

您可以将初始的
null
检查替换为

Optional.ofNullable(nameStartsWith)
        .flatMap(x -> Optional.ofNullable(region))
        .flatMap(x -> Optional.ofNullable(loader))
        .orElseThrow(() -> new IllegalArgumentException(
            "The VehicleLoader and both region and nameStartsWith"
          + " are required when loading VehicleMake matches"));
但这是对API的滥用,更糟糕的是,它浪费资源用于在错误情况下提供一个毫无意义的异常这一可疑目标

比照

Objects.requireNonNull(region, "region is null");
Objects.requireNonNull(nameStartsWith, "nameStartsWith is null");
Objects.requireNonNull(loader, "loader is null");
这是一个简洁的异常,在错误情况下会抛出一个带有精确消息的异常。它将是一个
NullPointerException
,而不是一个
IllegalArgumentException
,但即使是这样的更改也会导致对实际问题的更精确描述

关于该方法的其余部分,我强烈建议不要让
Collection
s首先为
null
。这样,您就不必测试
getVehicleMakesByRegion
null
结果,也不会自己返回
null

但是,如果必须保持原始逻辑,可以使用

return Optional.ofNullable(loader.getVehicleMakesByRegion(region.name()))
               .map(regionMakes -> regionMakes.stream()
                    .filter(make -> Optional.ofNullable(make.getName())
                                            .filter(name->name.startsWith(nameStartsWith))
                                            .isPresent())
                    .collect(Collectors.toList()))
               .orElse(null);

用于拒绝
null
引用的初始代码不应与用于处理
null
引用的实际操作混淆。

您不能将参数传递给方法引用。您必须使用lambda。此外,如果值可能是
null
,则不要使用
of
;您必须要使用
的nullable
。您应该将flatMap更改为map。编辑使用。我假设这仍然无法编译?
ifPresent
使用
使用者
,这是一个接受值且不返回任何内容的接口。但它必须接受实现
使用者
的对象,或lambda,或方法refereence。您没有给它任何一个,而是试图给它另一个对象。此外,
ifPresent
返回
void
,因此您不能在需要值的地方使用它。@dm1530避免滥用
可选
,在这种情况下,流控制更为充分。
loadMatching
方法应该属于e> VehicleLoader
。如果只想在可选项确实为空时生成Collections::emptyList的结果,还可以使用可选项::OrelGet(Collections::emptyList)您的代码在空检查中的行为违反将导致两个方法具有不同的行为。为什么即使我们返回
可选,返回类型
列表
仍然有效。ofNullable(…
。为什么我更改时抛出编译器错误
Objects.requireNonNull(region, "region is null");
Objects.requireNonNull(nameStartsWith, "nameStartsWith is null");
Objects.requireNonNull(loader, "loader is null");
return Optional.ofNullable(loader.getVehicleMakesByRegion(region.name()))
               .map(regionMakes -> regionMakes.stream()
                    .filter(make -> Optional.ofNullable(make.getName())
                                            .filter(name->name.startsWith(nameStartsWith))
                                            .isPresent())
                    .collect(Collectors.toList()))
               .orElse(null);