繁体   English   中英

使用具有条件的流迭代哈希图

[英]Iterating over hashmap with streams with condition

所以我有这个循环

for (Map.Entry<String, Integer> val : map.entrySet()) {
        if (val.getValue() >= 10 && !Objects.equals(val.getKey(), " ") && val.getKey().length() > 3) {
            stats = stats + val.getKey().toLowerCase() + " - " + val.getValue() + "\n";
        }
    }

现在我想摆脱 for 循环和使用流的 if 条件。 我怎样才能做到这一点?

这可能是一种方法:

String stats = map.entrySet().stream()
        // keep only the entries you're interested in:
        .filter(entry -> entry.getKey().length() > 3 && entry.getValue() >= 10)
        // serialise entries one by one:
        .map(entry -> entry.getKey().toLowerCase() + " - " + entry.getValue())
        // join:
        .collect(Collectors.joining("\n"));

方法有很多种,这里是一种。

  • 首先是一些测试数据。
Map<String, Integer> map = Map.of(" ", 18, "foo", 14, "abcd",
        20, "ab", 10, "efgh", 3, "rstuv", 14);
  • 然后我会定义一个Predicate<Entry<String, Integer>>来减少流结构的混乱。 请注意,由于您正在检查length < 3 ,因此可以省略单个空格的条件。 如果您的意思是检查一个空白字符串,您可以使用!val.getKey().isBlank()作为条件。

  • reduce接受一个初始参数,后跟一个BinaryOperator作为累加器。 在这种情况下,累积是映射字符串的串联。 String::concat满足要求,在这里用来完成操作。

Predicate<Entry<String, Integer>> check =
        val -> val.getValue() >= 10
                && val.getKey().length() > 3;

然后只需流式传输EntrySet即可。

String result = map.entrySet().stream().filter(check)
         .map(e -> e.getKey().toLowerCase() + " - " + e.getValue() + "\n")
         .reduce("", String::concat);

Systemm.out.print(result);

打印以下内容。

abcd - 20
rstuv - 14

要充分利用流功能,您需要使用流、过滤器和减少功能,如下所示:

// Get the stream from entrySet
String result = map.entrySet().stream()    
      // Filter entries based on your condition
      .filter(val ->  val.getValue() >= 10 
                           && !Objects.equals(val.getKey(), " ") 
                           && val.getKey().length() > 3)  
       // Apply the reduce to combine filtered entries in a single string     
      .reduce("", (stats, val) -> stats 
                                  + val.getKey().toLowerCase() 
                                  + " - " 
                                  + val.getValue() 
                                  + "\n");

应用于 Collection 的stream方法给出集合中存在的项目的新 Stream:

返回以此集合为源的顺序流。

应用于流的过滤方法:

返回由与给定谓词匹配的此流的元素组成的流。

流对象上的reduce函数:

使用提供的标识值和关联累积函数对此流的元素执行归约,并返回归约后的值

使用 forEach 方法做得很好。 使用流和流 API 是一种很好的做法。

这是一个非常简单的程序,它执行与您想做的类似的事情。

import java.util.Map;
import java.util.HashMap;
public class Test {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("aaaa", 1);
        map.put("bbbb", 2);
        map.put("cccc", 3);
        map.forEach((k,v)->System.out.println(k + ": " + v));
    }
}

现在我们可以编译并运行代码了。

% javac Test.java
% java Test
aaaa: 1
bbbb: 2
cccc: 3

现在,您的代码中的错误是什么?

错误是这样的。 Map.forEach 方法采用 BiConsumer。 BiConsumer 操作接受两个输入参数(k 和 v)并且不返回任何结果。 您正在使用 BiConsumer 操作以三元表达式返回结果。 BiConsumer 操作的返回类型为 void。 所以你可以做的是......你可以在 BiConsumer 操作中执行代码(就像我在我的示例中所做的那样),但你不能在 BiConsumer 操作中返回结果(你正在尝试这样做)。

您可以在 Java 文档中阅读有关 Map.forEach 方法和 BiConsumer 函数操作的信息。

  1. Map.forEach 方法的 Java 文档
  2. BiConsumer 操作的 Java 文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM