【问题标题】:using Optional and lambdas in Java [closed]在 Java 中使用 Optional 和 lambdas [关闭]
【发布时间】:2019-07-06 04:05:51
【问题描述】:

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

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);
    return bObject.flatMap(boMaybe -> {                <---- HERE
        try {
            LOGGER.debug(String.format("Object read: %s", ref));
            BObject obj = new BObjectBuilder(boMaybe).stream(loadDocumentStream(boMaybe)).build();
            return Optional.of(obj);
        } catch (IOException e) {
            LOGGER.error(String.format("Could not read file with ref: %s, error: %s", ref, e));
        }

        return Optional.empty();
    });
}

使用返回 Optional&lt;BObject&gt; 的 lambda 函数然后在其上使用 flatMap 以接收 Optional&lt;BObject&gt; 作为返回类型更好,还是在 lambda 中返回 null 然后更好只需使用map:

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);
   return bObject.map(boMaybe -> {              <--- HERE
       try {
           LOGGER.debug(String.format("Object read: %s", ref));
           return new BObjectBuilder(boMaybe).stream(loadDocumentStream(boMaybe)).build();
       } catch (IOException e) {
           LOGGER.error(String.format("Could not read file with ref: %s, error: %s", ref, e));
       }

       return null;
   });
}

第一种方法对我来说似乎稍微好一些,因为我可能会在其他地方重用 lambda 函数,它不会返回 null,而是返回 Optional。但是,只要我只在一个地方使用它就值得吗?

【问题讨论】:

  • 我认为这有点基于意见(即离题)。我更喜欢前者,因为我尽量避免使用 null 关键字,除非我必须这样做。但是后者更简洁。
  • 我建议不要在这种情况下使用 optional ,因为它只会使一切复杂化。
  • 您可以重新抛出包裹在 UncheckedIOException 中的异常,然后在 lambda 之外捕获它并返回一个空的可选项。

标签: java java-8 functional-programming optional


【解决方案1】:

您可能希望提供一个稳定且安全的 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

【讨论】:

    【解决方案2】:

    如果您有选择,我建议您编写返回 Optional 而不是 null 的函数,如果无结果是正常且预期的结果。因此,您将使用flatMap 来调用此类函数。 map 操作对于始终返回有效结果的函数很有用。它还将 null 返回转换为空的Optional,这主要在您需要适应无法更改的返回 null 的代码时有用。

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

    此外,对于 try/catch 块,我建议将 try 子句中的代码最小化为仅可以实际抛出您正在捕获的异常的代码,并在 try 语句之外进行额外的转换。在这种情况下,我假设index.read(ref)loadDocumentStream(boMaybe) 是可以抛出IOException 的语句。请注意,这意味着局部变量需要保存临时结果,并且它可以为空。我认为这没关系。 null 处理非常本地化,它允许您将返回的Optional 的创建合并到一个表达式中。

    最后,我建议不要对可选项使用后缀“可能”。这令人困惑,在示例中,flatMap 操作的 lambda 参数 boMaybe 不正确。仅当值存在时才会评估该 lambda,因此没有“可能”。

    应用所有这些建议会得到结果代码:

    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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-24
      • 1970-01-01
      • 1970-01-01
      • 2017-08-16
      • 2014-05-13
      • 2021-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多