在Java中使用可选和lambdas

在Java中使用可选和lambdas,java,java-8,functional-programming,optional,Java,Java 8,Functional Programming,Optional,我在Java中使用Optional和lambdas编写代码,我想知道在以下情况下,什么是最好的方法: 公共可选readIndexMaybeString参考{ 试一试{ 返回可选的.ofNullableindex.readref.MapBobObjectBuilder::build; }捕捉异常{ LOGGER.errorString.Format无法读取ref的索引:%s,错误:%s,ref,e; } 返回可选的.empty; } 公共可选readMaybeString ref{ 可选bObje

我在Java中使用Optional和lambdas编写代码,我想知道在以下情况下,什么是最好的方法:

公共可选readIndexMaybeString参考{ 试一试{ 返回可选的.ofNullableindex.readref.MapBobObjectBuilder::build; }捕捉异常{ LOGGER.errorString.Format无法读取ref的索引:%s,错误:%s,ref,e; } 返回可选的.empty; } 公共可选readMaybeString ref{ 可选bObject=readIndexMayberef;
return bObject.flatmapbomaybay->{{您可能希望提供一个稳定且安全的api,这就是为什么您使用Optional,尽管在您的情况下,它会使内容复杂一些,因为您需要捕获检查过的异常。我建议使用这种方法:

public Optional<BObject> readIndexMaybe(String ref) {
   try {
       return Optional.ofNullable(index.read(ref)).map(BObjectBuilder::build);
   } catch (IOException e) {
       LOGGER.error(String.format("Could not read index of ref: %s, error: %s", ref, e));
   }
   return Optional.empty();
}

public Optional<BObject> readMaybe(String ref) {
   Optional<BObject> bObject = readIndexMaybe(ref);
   if(!bObject.isPresent()){
      return bObject; // is same as Optional.empty()
   }
   BObject boMaybe = bObject.get();
   try {
      LOGGER.debug(String.format("Object read: %s", ref));
      boMaybe = new BObjectBuilder(boMaybe).stream(loadDocumentStream(boMaybe)).build();
      return Optional.of(boMaybe);
   } catch (IOException e) {
      LOGGER.error(String.format("Could not read file with ref: %s, error: %s", ref, e));
      return Optional.empty();
   }
}

这与映射方法非常相似,但我认为这更清楚,因为lambda中没有try-catch。

如果您有选择,我建议编写返回Optional而不是null的函数,如果没有结果是正常和预期的结果。因此,您可以使用flatMap调用此类函数。映射操作非常有用对于总是返回有效结果的函数。它也会将空返回转换为空可选,这在需要适应无法更改的空返回代码时非常有用

通常的建议是提取方法,而不是使用多行语句lambda。然后,在flatMap操作中使用简单的lambda或方法引用

此外,对于try/catch块,我建议将try子句中的代码最小化,使其仅能引发正在捕获的异常,并在try语句之外进行其他转换。在这种情况下,我假设index.readref和loadDocumentStreamBo可能是可以引发IOException的语句。注意这意味着一个局部变量需要保存临时结果,并且它是可以为null的。我认为这是可以的。null处理是非常本地化的,它允许您将返回的可选值的创建合并到一个表达式中

最后,我建议不要将后缀maybe用于optionals。这很容易混淆,在示例中,flatMap操作的lambda参数boMaybe是不正确的。lambda仅在值存在时才计算,因此没有maybe

应用所有这些建议会产生以下代码:

Optional<BObject> readIndex(String ref) {
    Index i = null;
    try {
        i = index.read(ref);
    } catch (IOException e) {
        LOGGER.error(/*...*/);
    }
    return Optional.ofNullable(i).map(BObjectBuilder::build);
}

Optional<BObject> load(BObject bo) {
    DocStream docStream = null;
    try {
        LOGGER.debug(/*...*/);
        docStream = loadDocumentStream(bo);
    } catch (IOException e) {
        LOGGER.error(/*...*/);
    }
    return Optional.ofNullable(docStream)
                   .map(ds -> new BObjectBuilder(bo).stream(ds).build());
}

Optional<BObject> read(String ref) {
    return readIndex(ref).flatMap(bo -> load(bo)); // or this::load
}

我认为这有点基于观点,即脱离主题。我更喜欢前者,因为我尽量避免使用null关键字,除非我必须这样做。然而,后者更简洁。我建议在这种情况下不要使用optional,因为这会使一切复杂化。你可以重新显示包装在未选中的异常中的异常,然后在lambda之外捕获它并返回一个空的可选值。