有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java“filter()”和“map()”可以互换

我有一个简单的流,如下所示:

List<Long> r = l.stream()
                .filter(a->a.getB() % 2 == 0)
                .map(A::getB)
                .collect(Collectors.toList());

但Intellij建议我:

'filter()' and 'map()' can be swapped Inspection info: Reports stream API call chains which can be simplified. It allows to avoid creating redundant temporary objects when traversing a collection. e.g.

  • collection.stream().forEach() → collection.forEach()
  • collection.stream().collect(toList/toSet/toCollection()) → new CollectionType<>(collection)

Intellij给出的例子很容易理解,但我不明白为什么它建议我map().filter()

我查看了ReferencePipeline的源代码,但没有找到任何线索:map().filter()filter().map()在涉及到与流实现相关的临时对象时没有什么区别(如果A.b是一个原语,那么filter().map()的自动装箱功能会减少,这让我更困惑)

那么,我是否错过了一些流点实现,或者这是Intellij的错误警报


共 (1) 个答案

  1. # 1 楼答案

    a.getB()被调用两次——一次在过滤器内部,它也是映射函数,因此与其这样做两次,不如先使用getB映射它,然后过滤掉它

    List<Long> r = l.stream().map(A::getB).filter(b->b % 2 == 0).collect(Collectors.toList());

    编辑

    如果getB返回一个long,那么mapToLong可以用来避免中间装箱操作

    List<Long> r = l.stream()
                    .mapToLong(A::getB)
                    .filter(b->b % 2 == 0)
                    .boxed()
                    .collect(Collectors.toList());
    

    样本输出

    使用静态计数器计算get方法的调用次数:

    class A {
        public static int count = 0;
        private long b;
    
        public long getB() {
            count++;
            return b;
        }
    }
    
    List<A> list= List.of(new A(1L), new A(3L), new A(4L));
    
    list.stream() 
        .filter(a -> a.getB()%2 == 0)
        .map(A::getB)
        .collect(Collectors.toList());
    System.out.println(A.count); // returns 4
    

    鉴于

    list.stream()
        .mapToLong(A::getB)
        .filter(b->b % 2 == 0)
        .boxed()
        .collect(Collectors.toList());
    System.out.println(A.count); // returns 3