Java 8: preferred way to count iterations of a lambda?

后端 未结 11 1752
没有蜡笔的小新
没有蜡笔的小新 2021-02-01 00:17

I face the same problem often. I need to count the runs of a lambda for use outside the lambda.

E.g.:

myStream.stream().filter(...).forEa         


        
11条回答
  •  花落未央
    2021-02-01 00:34

    Another way of doing this (useful if you'd like your count to only be incremented in some cases, like if an operation was successful) is something like this, using mapToInt() and sum():

    int count = myStream.stream()
        .filter(...)
        .mapToInt(item -> { 
            foo();
            if (bar()){
               return 1;
            } else {
               return 0;
        })
        .sum();
    System.out.println("The lambda ran " + count + "times");
    

    As Stuart Marks noted, this is still somewhat odd, because it's not completely avoiding side effects (depending on what foo() and bar() are doing).

    And another way of incrementing a variable in a lambda that's accessible outside of it is to use a class variable:

    public class MyClass {
        private int myCount;
    
        // Constructor, other methods here
    
        void myMethod(){
            // does something to get myStream
            myCount = 0;
            myStream.stream()
                .filter(...)
                .forEach(item->{
                   foo(); 
                   myCount++;
            });
        }
    }
    

    In this example, using a class variable for a counter in one method probably doesn't make sense, so I'd caution against it unless there's a good reason to. Keeping class variables final if possible can be helpful in terms of thread safety, etc (see http://www.javapractices.com/topic/TopicAction.do?Id=23 for a discussion on using final).

    To get a better idea of why lambdas work the way they do, https://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood has a detailed look.

提交回复
热议问题