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

时间:2018-01-09 10:03:57

标签: java-8 java-stream

我发现了java 8流。

从地图开始我想从地图键中获取所有匹配的值。

我不明白为什么那个代码

    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());

它给了我预期的结果

[005, 001, 003]

或使用时

    datas.entrySet().stream()
        .filter(entry -> {
          ... 
        })
        .forEach(entry -> System.out.println(entry.getKey()));

它也给了我预期的结果

Value_005_1
Value_001_1
Value_003_1
[005, 001, 003]

2 个答案:

答案 0 :(得分:3)

示例中没有终端操作:

datas.entrySet().stream()
    .filter(entry -> { ...

和流由终端操作驱动(在终端操作存在之前不会执行任何操作)。这就是您的第二个示例有效的原因,因为您通过collectforEach进行了终端操作。

除此之外,您违反了副作用的规则,基本上filter不得在自身之外执行任何操作(例如您正在更新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());

答案 1 :(得分:1)

Java 8中的Streams有两种类型的操作,即中间操作和终端操作。

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

终端操作适用于每个,收集,减少等。

您可以执行以下操作:

Stream createFilterStream(map,Predicate) {
return map.entryset.stream.filter(predicate)
}

不是实际的代码,但希望你能得到这个想法

方法的调用者可以按给定的谓词过滤地图,然后调用它上面的终端函数来使用结果

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