使用Java 8中的一个Stream执行多个get操作并保存结果

问题描述 投票:0回答:4

我目前正在编写程序,我将在列表中流式传输,获取其中一个字段的第一个值并保存结果。

Product对象有两个字段(颜色和名称)。

我会使用Stream保存第一个找到的产品名称,如下所示:

List<Product> productList = Arrays.asList(new Product("red", "potatoes"),
  new Product("blue", "orange"), new Product("yellow", "lemon"),
  new Product("brown", "bread"), new Product("pink", "sugar"));

String firstProductName = 
  productList.stream().map(Product::getName).filter(Objects::nonNull).findFirst().get();

为了保存第一个找到的颜色值,我会使用另一个Stream:

String firstProductColor = 
  productList.stream().map(Product::getColor).filter(Objects::nonNull).findFirst().get();

有没有办法组合这两个Streams,以便我可以在一个Stream中提取第一个颜色和名字并保存到firstProductName和firstProductColor?

非常感谢你的帮助!

java java-8 java-stream
4个回答
1
投票

您要求使用流,但不保证某些空条件,我认为这是不可能的,因为结果可能来自流中的两个不同元素。

可以使用简单的for循环解决方案:

String firstProdName = null;
String firstProdColor = null;
for (Product prod : productList) {
    if (firstProdName == null) // set the product name if not set
         firstProdName = prod.getName();
    if (firstProdColor == null) // set the product color if not set
         firstProdColor = prod.getColor();
    if (firstProdName != null && firstProdColor != null)
         break; // both have been found - terminate loop
}

2
投票

如果我理解正确,您想要检索第一个非空产品名称和产品颜色,并且第一个非空产品名称可能位于列表中不同于第一个非空颜色的位置。

这里的问题是流管道的执行方式,即我们没有通过第一个中间操作传递流的每个元素,然后通过下一个中间操作传递从该中间操作返回的所有元素,依此类推,直到终端操作。而是流的每个元素垂直向下传递到流管道,并且通过调用findFirst().get()来检索成功通过所有中间操作的第一个元素。

因此,在我看来,用流来完成手头的任务是非常不可能的,即使由于流管道的执行方式,它也可能过于复杂。

另外,请注意,直接从get()调用Optional是一种误用,你不应该使用这种方法,除非你100%确定会有值存在;有理由在后面解释。

但是,使用for循环或foreach循环,我们可以通过列表单次传递所需的数据,例如lucaswv的答案所建议的。

除了前面提到的,我想指出Optional的滥用。当你这样做时:

...findFirst().get()

与调用一个可以返回null的方法没什么不同,但是当方法返回一个结果时,你只需要在这个方法的返回值之上调用另一个可能导致NullPointerException的方法,而不是防止null。

相反,当没有价值时,从get()Optional的调用将导致NoSuchElementException;因此,在大多数情况下直接使用get()结果使用Optional并不理想。

为防止出现此类异常,您需要使用OrElse返回值,如果存在,则提供默认值。

显然,Optional.get()是有原因的,但它是API设计师的错误,因此我建议你总是根据情况使用orElseorElseGet


0
投票

是的,您可以使用以下代码:

Product product = productList.get(0);
String firstProductName = product.getName();
String firstProductColor = product.getColor();
System.out.println(firstProductName + " / " + firstProductColor);

你的输出将是:red / potatoes

无需创建流即可从List获取第一个元素。这是最简单的方法。

但是如果您仍然想要使用流,请不要将列表分成两个流,使用单个流,如下所示:

Product product = productList.stream().filter(Objects::nonNull).findFirst().get();
String firstProductName = product.getName();
String firstProductColor = product.getColor();
System.out.println(firstProductName + " / " + firstProductColor);

输出将与上面相同:red / potatoes


0
投票

Streams不是为这种操作而设计的,您应该使用经典循环而不是流来在单次遍历集合期间获取多个值。

© www.soinside.com 2019 - 2024. All rights reserved.