13

I have two questions. Firstly, consider the below code.

public class Test{
    private static final List<String> var = new ArrayList<String>() {{
        add("A");
        add("B");
        System.out.println("INNER : " + var);
    }};

    public static void main(String... args){
        System.out.println("OUTER : " + var);
    }   
}

When I run this code it gives me below output

INNER : null
OUTER : [A, B]

Can any one elaborate why INNER is null and execution flow at a time when exactly "A" & "B" added to collection?

Secondly, I made some changes in above code and modified to below one (just put add method within first bracket)

public class Test{
    private static final List<String> var = new ArrayList<String>() {
        public boolean add(String e) { 
            add("A");
            add("B");
            System.out.println("INNER : " + var); return true; 
        };
    };

    public static void main(String... args){
        System.out.println("OUTER : "+var);
    }   
}

After running above code i got below result

OUTER : []

After viewing this I'm totally clueless here about what is going on. Where did INNER go? Why is it not printing? Is it not called?

xingbin
  • 27,410
  • 9
  • 53
  • 103
RBS
  • 207
  • 1
  • 11

4 Answers4

13
  1. Because the initializer block of the anonymous class off ArrayList is executed before the instance reference of the anonymous class is assigned to var.

  2. The code is not executed because you never call the add(String e) method. If you did, it would result in a StackOverflowError, since add("A") is a recursive call now.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • if i call add() from main method how does it becomes recursive call(i check it as you mentioned it gives StackOverflowError) – RBS Oct 07 '18 at 15:10
  • 5
    @RBS The first statement inside `add(String e)` is `add("A")`, which is a call to itself, so it executes `add("A")`, which is a call to itself, so it executes `add("A")`, which is a call to itself, so it executes `add("A")`, which is a call to itself, so it executes `add("A")`, which is a call to itself, so it executes `add("A")`, and **StackOverflowError**. – Andreas Oct 07 '18 at 15:16
5
  1. The object you created has not been assigned to var in the initialization procedure, try this:

    private static final List<String> var = new ArrayList<String>() {{
        add("A");
        add("B");
        System.out.println("THIS : " + this); // THIS : [A, B]
        System.out.println("INNER : " + var); // INNER : null
    }};
    
  2. You just override add method of ArrayList, it's nerver been called. It works like:

    static class CustomList<E> extends ArrayList<E> {
    
        @Override
        public boolean add(String e) {
            add("A");
            add("B");
            System.out.println("INNER : " + var);
            return true;
        }
    }
    
    private static final List<String> var = new CustomList<>();
    
xingbin
  • 27,410
  • 9
  • 53
  • 103
2

In your code snippet 1, you are using the double brace initialization to add items to the array list. It is basically an anonymous inner class with an instance initializer. Since you print var before the object is constructed it is null.

In your second snippet, you are creating an anonymous class of ArrayList providing an implementation of the add method. But no one calls the add method on the ArrayList object.

EDIT: Good point made by Andreas@ - Even if you call the add method, it will result in an infinite recursive call resulting in a StackOverflowError.

Reference:

Initialization of an ArrayList in one line

Thiyagu
  • 17,362
  • 5
  • 42
  • 79
1

In the first code you print the variable before that its constructor has returned as you add the elements and print the list inside the instance initializer. So it can only print null.

In the second code you override add() to add hardcoded elements but add() is never invoked on the created instance. So add() doesn't print anything and nothing is added in the List instance either.

To add elements in a List you generally want to invoke add() on the List reference such as :

List<String> list = new ArrayList<>();
list.add("element A");
list.add("element B");

You don't create an anonymous class for such a requirement.

If you want to use a simpler syntax you can still do :

List<String> list = new ArrayList<>(Arrays.asList("element A", "element B"));
davidxxx
  • 125,838
  • 23
  • 214
  • 215