V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
easterfan
V2EX  ›  问与答

Java8 Stream 流一边 filter 过滤一边 map 映射??

  •  
  •   easterfan · 2020-11-20 16:10:38 +08:00 · 2143 次点击
    这是一个创建于 1253 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一时 stream 一时爽,用习惯了以后,突然想到对于流,能否实现过滤和 map 同时进行的操作,比如一个场景:

    // 如果元素是奇数,就 + 1,如果元素是偶数,就 +2,期望一顿流式操作后,输出一个新的 List:{2,4,4,6,6}
    
    List<Integer> input = Arrays.asList(1, 2, 3, 4, 5);
    
    inputList.stream()
             .filter(p -> xxx)
             .map(p -> xxx)
             .collect(Collectors.toList());
    

    现在最高频用到的 filter 通常只有一个条件,是从原来的 List 中过滤出满足条件的元素,然后对这些元素进行 map 操作,

    如果对一个集合,有两种过滤条件 A 和 过滤条件 B,满足过滤条件 A 就对元素进行 mapA 操作,满足过滤条件 B,就对元素进行 mapB 操作,最后元素都按照不同的 map 方式映射完了,再放到同一个集合里~~

    初用 stream,有大佬这样操作过嘛~~

    14 条回复    2020-12-08 14:43:30 +08:00
    chanchan
        1
    chanchan  
       2020-11-20 16:27:22 +08:00   ❤️ 2
    peek 了解一下
    wowo243
        2
    wowo243  
       2020-11-20 16:29:16 +08:00
    partitioningBy()?
    ye2moe
        3
    ye2moe  
       2020-11-20 16:33:19 +08:00
    直接的话是做不到的,可以搞两个流操作再合起来就好了。
    easterfan
        4
    easterfan  
    OP
       2020-11-20 16:57:54 +08:00
    @wowo243
    @ye2moe
    ```java
    Map<Boolean, List<Integer>> partitionMap = Stream.of(1, 2, 3, 4, 5).collect(Collectors.partitioningBy(p -> p / 2 == 0));

    Stream<Integer> evenStream = partitionMap.get(true).stream().map(p -> p + 2);
    Stream<Integer> oddStream = partitionMap.get(false).stream().map(p -> p + 1);
    Stream.concat(evenStream, oddStream);
    ```
    分组成两个流,然后再合并,合并后的流和原来的流元素顺序不一样了~~
    anzu
        5
    anzu  
       2020-11-20 17:12:21 +08:00   ❤️ 1
    为什么要 filter,奇偶不是二选一吗。如果判断条件复杂,要么 map 里面多写点代码,要么用 for
    input.stream().map(p -> p % 2 == 0 ? p + 2 : p + 1).collect(Collectors.toList())
    easterfan
        6
    easterfan  
    OP
       2020-11-20 17:50:45 +08:00
    @anzu
    感谢大佬!解决了我的问题,用 map 前总是很习惯的 filter 一下,有了思维定式,用你的思路,把判断逻辑写在 map 里,对一个元素 map 前先做一次判断,然后执行对应的 map,已经达到了我在找的一边 filter,一边 map 的想法,感谢!

    ```java
    Stream.of(1,2,3,4,5)
    .map(p -> {if(isFilterA) mapA(); if (isFilterB) mapB(); if (isFilterC) mapC();})
    .collect(Collectors.toList());
    ```
    (原来的固定思维的想法~:)
    https://imgur.com/7sn8euR
    jimmyismagic
        7
    jimmyismagic  
       2020-11-20 17:57:28 +08:00
    @easterfan filter 概念要搞清楚啊,没事干嘛搞 filter
    optional
        8
    optional  
       2020-11-20 18:00:34 +08:00 via iPhone
    rx 欢迎你
    easterfan
        9
    easterfan  
    OP
       2020-11-20 18:05:06 +08:00
    @jimmyismagic 母鸡啊~写顺手了,map 前必 filter~~Q
    easterfan
        10
    easterfan  
    OP
       2020-11-20 19:02:42 +08:00
    @optional
    敢问 rx 是?这 id 很 6
    jimmyismagic
        11
    jimmyismagic  
       2020-11-20 21:10:35 +08:00   ❤️ 1
    @easterfan rxJava,另外还有 project reactor,都是响应式编程,但其中也使用了 streams 里的一些概念
    oneisall8955
        12
    oneisall8955  
       2020-11-20 22:35:05 +08:00 via Android   ❤️ 1
    在 map 里面直接判断 A 或 B 条件分开转换就行了吧

    借楼,题外话,最近密的 stream 的另一个 API,Collectors.mapping,真是节省了不少代码逻辑,主要用于 group 分组后的 value 集合再 map

    https://stackoverflow.com/questions/52281724/java-streams-group-list-entries-based-on-a-property-but-collect-a-property-of-ob

    知道这个 API 的大佬请忽略
    zch693922
        13
    zch693922  
       2020-11-21 09:42:05 +08:00   ❤️ 1
    按一楼的 peek 一下就可以了
    list.stream().peek(item -> {
    if (xxxxx) { do something}
    if (xxxx) {item.setXXX}
    })
    easterfan
        14
    easterfan  
    OP
       2020-12-08 14:43:30 +08:00
    @zch693922
    @chanchan

    感谢回答!最近试了 map 和 peek 两种实现方式,实践后发现可能 map 更适用这种情况,具体原因是使用 peek 后续再进行终端操作(比如 collect/count )时,会出现报错:`java.lang.UnsupportedOperationException`, peek 可能只适合调试的场景,个人解释能力有限,感兴趣的话这篇文章举的例子挺好的:

    https://stackoverflow.com/questions/44370676/java-8-peek-vs-map
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5255 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 09:21 · PVG 17:21 · LAX 02:21 · JFK 05:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.