我有一个任务,需要将以下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;
}我想使用Optional<T>删除null检查,而不修改以前创建的类和接口。
我尝试通过更改方法返回类型并执行以下操作开始,但编译器抛出了此错误:
Bad return type in method reference,因为VehicleMake类没有可选的实例字段。
以下是我的代码尝试:
public static Optional<List<VehicleMake>> loadMatchingJava8(Region region, String nameStartsWith, VehicleLoader loader) {
Optional<List<VehicleMake>> regionMakes = Optional.ofNullable(loader).ifPresent(loader.getVehicleMakesByRegion(Optional.ofNullable(region).ifPresent(region.name())));
/*
TODO rest of the conversion
*/
}编辑:通过不将参数传递给方法引用,删除了flatMap并更正了代码。但是现在它不允许我将region.name()传递给getVehicleMakesByRegion()
编辑:将消费者传递给ifPresent():
Optional<List<VehicleMake>> regionMakes = Optional.ofNullable(loader).ifPresent(()-> loader.getVehicleMakesByRegion(Optional.ofNullable(region).ifPresent(()->region.name()));发布于 2017-05-03 17:21:14
您可以将初始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为null。这样,您就不必测试null的getVehicleMakesByRegion结果,也就不会自己返回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引用的实际操作混淆。
发布于 2017-05-03 13:53:29
我已经用Optional更新了你的代码
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());
}发布于 2017-05-03 14:21:54
如果你真的想要将流控制转换成Optional,那么与你的代码保持一致的代码应该是这样的(我将代码分成两行打印):
public static Optional<List<VehicleMake>> loadMatchingJava8(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");
}
return Optional.ofNullable(loader.getVehicleMakesByRegion(region.name()))
.map(makers -> makers.stream()
.filter((it) -> it.getName() != null
&& it.getName().startsWith(nameStartsWith))
.collect(Collectors.toList()));
}备注:您可以在此question中查看有关为什么不滥用Optional的更多信息。
https://stackoverflow.com/questions/43751613
复制相似问题