A final counter in a for loop?

后端 未结 6 868
滥情空心
滥情空心 2020-12-03 21:07

I have this code:

    List r = new ArrayList<>();
    for(int i = 0; i < 10; i++) {
        r.add(new Runnable() {

            @Ove         


        
相关标签:
6条回答
  • 2020-12-03 21:35

    Looks fine to me. You want to use the value of the loop variable inside your anonymous class and the loop variable obviously can't be final (as its value changes).

    Creating a new final local variable is a good solution.

    0 讨论(0)
  • 2020-12-03 21:42

    I think your solution is the simplest way.

    Another option would be to refactor the creation of the inner class into a factory function that does it for you, then your loop itself could be something clean like:

    List<Runnable> r = new ArrayList<>();
    for(int i = 0; i < 10; i++) {
        r.add(generateRunnablePrinter(i));
    }
    

    And the factory function could just declare a final parameter:

    private Runnable generateRunnablePrinter(final int value) {
        return new Runnable() {
           public void run() {
               System.out.println(value);
           }
        };
    }
    

    I prefer this refactored approach because it keeps the code cleaner, is relatively self descriptive and also hides away all the inner class plumbing.

    Random digression: if you consider anonymous inner classes to be equivalent to closures, then generateRunnablePrinter is effectively a higher order function. Who said you can't do functional programming in Java :-)

    0 讨论(0)
  • 2020-12-03 21:51

    (Less-than optimal) alternative: create a small inner class that implements Runnable:

    class Printer implements Runnable {
        private int index;
    
        public Printer(int index) {
            this.index = index;
        }
    
        public void run() {
            System.out.println(index);
        }
    }
    
    List<Runnable> r = new ArrayList<>();
    for(int i = 0; i < 10; i++) {
        r.add(new Printer(i));
    }
    
    0 讨论(0)
  • 2020-12-03 21:54

    This is what IntelliJ does for you as a fix. The only difference is I would do

    ExecutorService es = 
    for(int i = 0; i < 10; i++) {
        final int i_final = i;
        es.execute(new Runnable() {
    
    0 讨论(0)
  • 2020-12-03 21:55

    Your solution isn't bad. You could do other stuff, like define your own subclass of Runnable and initialize it with i in the constructor or initialization blocks, but in this case I think it would be just adding complexity without a good cause.

    BTW: I assume your example is a syntehetic one, in practice creating a new Runnable just to print an integer wouldn't seem a good idea.

    0 讨论(0)
  • 2020-12-03 21:58

    I'm afraid there's no other way than copy your counter to a second final variable and use that in your anonymous inner class. This is one of the "deficiencies" of Java around the topic of closures and an advertised advantage of sibling languages like Groovy.

    0 讨论(0)
提交回复
热议问题