Java 8偷看vs地图

Ale*_*lex 24 java java-8

我有以下案例:有一个对象列表 - ProductData包含几个字段:

public class ProductData
{
....
  private String name;
  private String xref;

  //getters
  //setters
}
Run Code Online (Sandbox Code Playgroud)

并且有API返回以下对象的列表:

public class RatingTableRow
{
  private String planName;
  private String planXref;
  private int fromAge;
  private int toAge;
  private int ratingRegion;

 //constructor
 //getters
 //setters

}
Run Code Online (Sandbox Code Playgroud)

但它返回具有空计划名称字段的对象,因为在提取此对象期间不允许这样做.我需要通过外部参照将产品数据与RatingTableRow链接,以便将计划名称设置为RatingTableRow,因为我需要稍后使用此对象,因此我创建了以下代码来执行此操作:

Map<String, ProductData> productByXref = plans.stream()
        .collect(toMap(ProductData::getInternalCode, Function.identity()));

return getRatingTableRows(...).stream
        .filter(ratingRow -> productByXref.containsKey(ratingRow.getPlanXref()))
        .peek(row -> {
                ProductData product = productByXref.get(row.getPlanXref());
                row.setPlanName(product.getName());
        })....;
Run Code Online (Sandbox Code Playgroud)

我知道java文档说这peek不符合这些需求,但希望得到关于如何以更正确的方式完成此任务的建议.

Eug*_*ene 49

peek记录的原因主要是用于调试目的.

最终在内部处理的东西peek可能根本不符合终端操作的条件,并且流仅由终端操作执行.

首先假设一个简单的例子:

    List<Integer> list = new ArrayList<>();
    List<Integer> result = Stream.of(1, 2, 3, 4)
            .peek(x -> list.add(x))
            .map(x -> x * 2)
            .collect(Collectors.toList());

    System.out.println(list);
    System.out.println(result);
Run Code Online (Sandbox Code Playgroud)

一切看起来都不错吧?因为在这种情况下peek将运行所有元素.但是当你添加一个filter(并忘记做了什么peek)时会发生什么:

 .peek(x -> list.add(x))
 .map(x -> x * 2)
 .filter(x -> x > 8) // you have inserted a filter here
Run Code Online (Sandbox Code Playgroud)

您正在peek为每个元素执行,但不收集任何元素.你确定你想要吗?

这可能变得更加棘手:

    long howMany = Stream.of(1, 2, 3, 4)
            .peek(x -> list.add(x))
            .count();

    System.out.println(list);
    System.out.println(howMany);
Run Code Online (Sandbox Code Playgroud)

在java-8中填充了列表,但在jdk-9中 peek根本没有调用.由于您没有使用filter或者flatmap您没有修改Stream count的大小而只需要它的大小; 因此,根本没有调用.因此,依靠peek是一个非常糟糕的策略.

  • 有人需要告诉Jetbrains,IntelliJ一直告诉我用'peek`s'替换我的`map`s. (41认同)
  • @xagaffar:没错。软件逻辑取决于执行顺序。我真的不明白这会让任何人感到惊讶。 (6认同)
  • 是的,一旦我真正阅读了弹出窗口,结果发现这是因为“map”内部的函数返回了与它所提供的相同的对象。IntelliJ 只是没有意识到我同时正在修改它。 (3认同)
  • 这可能是因为 `map()` 方法应该没有副作用并且您返回的是同一个对象吗?至少对我来说是这样。 (3认同)
  • `您正在对每个元素执行窥视,但不收集任何元素。您确定要吗?`我不明白为什么这是个问题,偷看是在过滤器之前的,所以期望对每个元素都执行它? (3认同)
  • @CharlesWood - 如果我正确理解您的场景,您将在“map()”中返回相同的对象引用,并且可能您正在“map()”中修改该对象本身的值。在这种情况下,IntelliJ 建议使用 peek() 是正确的 - 假设您的流中有终端操作 - 因为您不想替换元素本身。 (2认同)