Java 8 Java8流-使用过滤器将元素添加到列表中

Java 8 Java8流-使用过滤器将元素添加到列表中,java-8,java-stream,Java 8,Java Stream,我正在发现Java8流 从映射开始,我想从映射键获取所有匹配的值 我不明白为什么会这样 Map<String,String> datas = new HashMap<String,String>(); datas.put("x1","123"); datas.put("x2","123"); datas.put("x3","123"); datas.put("Value_001_1","123"); datas.put(

我正在发现Java8流

从映射开始,我想从映射键获取所有匹配的值

我不明白为什么会这样

    Map<String,String> datas = new HashMap<String,String>();

    datas.put("x1","123");
    datas.put("x2","123");
    datas.put("x3","123");

    datas.put("Value_001_1","123");
    datas.put("Value_001_2","123");
    datas.put("Value_002_2","123");
    datas.put("Value_003_1","123");
    datas.put("Value_003_2","123");
    datas.put("Value_004_2","123");
    datas.put("Value_005_1","123");

    datas.put("y1","123");
    datas.put("y2","123");
    datas.put("y3","123");

    List<String> results = new ArrayList<String>();

    String expression = "Value_#Position#_1";
    Pattern pattern = Pattern.compile(expression.replaceAll("#Position#","(?<position>.*)"));

    datas.entrySet().stream()
        .filter(entry -> {
            Matcher matcher = pattern.matcher(entry.getKey());
            if(matcher.matches())
            {
                results.add(matcher.group("position"));
                return true;
            }
            return false;
        });

    System.out.println(results);
但是当使用

    datas.entrySet().stream()
        .filter(entry -> {
          ... 
        })
        .collect(Collectors.toList());
    datas.entrySet().stream()
        .filter(entry -> {
          ... 
        })
        .forEach(entry -> System.out.println(entry.getKey()));
它给了我预期的结果

[005, 001, 003]
Value_005_1
Value_001_1
Value_003_1
[005, 001, 003]
或者当使用

    datas.entrySet().stream()
        .filter(entry -> {
          ... 
        })
        .collect(Collectors.toList());
    datas.entrySet().stream()
        .filter(entry -> {
          ... 
        })
        .forEach(entry -> System.out.println(entry.getKey()));
这也给了我预期的结果

[005, 001, 003]
Value_005_1
Value_001_1
Value_003_1
[005, 001, 003]

示例中没有终端操作:

datas.entrySet().stream()
    .filter(entry -> { ...
并且流由终端操作驱动,在终端操作出现之前,不会执行任何操作。这就是为什么第二个示例有效,因为您有一个通过collect或forEach的终端操作

除此之外,您违反了一条关于副作用的规则,基本上,过滤器不能像您更新ArrayList那样执行自身之外的任何操作

和往常一样,霍尔格找到了一个更好的方法:

Pattern pattern = Pattern.compile("Value_(\\d+)_1");
List<String> results = datas.keySet().stream()
            .map(pattern::matcher)
            .filter(Matcher::matches)
            .map(m -> m.group(1))
            .collect(Collectors.toList());

Java8中的流有两种类型的操作,中间操作和终端操作

中间操作被惰性地评估,这意味着,直到流以终端操作结束时,它们才被执行

终端操作是forEach、collect、reduce等

您可以执行以下操作:

Stream createFilterStream(map,Predicate) {
return map.entryset.stream.filter(predicate)
}
不是实际的代码,但希望您能理解

方法的调用方可以根据给定的谓词过滤映射,然后调用映射上的terminal函数来使用结果

createFilterStream(map, predicate).collect(<collection_logic>)

谢谢你的链接。好的,我想我明白了。关于你的最后一句话,有没有一种更好的、不违反副作用规则的方法来做这项工作?@tweetysat你可以这样做,例如:List results=datas.keySet.stream.filterx->x.matchesValue\ud+\u 1.mapx->x.replaceFirstValue\ud+\u 1,$1.collectors.toList@tweetysat或只应用一次正则表达式列表results=datas.keySet.stream.mapx->{Matcher m=pattern.matcherx;if m.matches{return m.group1;}return;}.filterx->!x、 isEmpty.collectors.toList@Eugene:不需要引入空字符串,只需稍后对其进行过滤:List results=datas.keySet.stream.mappattern::matcher.filterMatcher::matches.mapm->m.group1.collectCollectors.toList@霍尔格太棒了!我有点倾向于这样,但找不到合适的词语。谢谢你