-1

List interface does not enforce copy of added elements in the Javadoc, but ArrayList and LinkedList both copy them (if I understand the source code correctly).

So, am I safe to clear() the added list in this code? I assume not?

@Test
void test() {
    List<MyObject> original = new ArrayList<>();
    original.add(new MyObject("John", 1));
    original.add(new MyObject("David", 2));

    List<MyObject> newList = new LinkedList<>(); // or ArrayList, both can pass the test, but not sure about other impl.
    newList.addAll(original);
    original.clear();
    System.gc();
    for (MyObject o: newList) {
        assertThat(o, CoreMatchers.notNullValue());
    }
}

In a code review and see such issue, the added list is cleared after addAll(), not sure about if I can let this pass.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
WesternGun
  • 11,303
  • 6
  • 88
  • 157
  • Are you asking if clearing `original` would remove elements from `newList`? It would not in any implementation of List that was not broken. And it certainly would not set elements to null. – khelwood Oct 14 '21 at 09:09
  • But it sounds like you think that ArrayList and LinkedList copy the objects that are added to them, which they do not. They save references to the same objects. – khelwood Oct 14 '21 at 09:12
  • Well in ArrayList.addAll() I see `System.arrayCopy()` which is native, and in LinkedList.addAll() I see reference saved. – WesternGun Oct 14 '21 at 09:18
  • OK so because the references of elements are referenced in the newList, gc() would not clear them, even no objects are copied. – WesternGun Oct 14 '21 at 09:23
  • 1
    Like you said, find my answer here: https://stackoverflow.com/questions/18009909/clearing-or-set-null-to-objects-in-java – WesternGun Oct 14 '21 at 09:34

1 Answers1

2

Both LinkedList.addAll() and ArrayList.addAll() copy the elements over to the new list. LinkedList.addAll() internally calls toArray(), and ArrayList.addAll() calls arraycopy().

so a call on original.clear() should only affect original, but not newList.

I can think of one list implementation that behaves slightly differently: CopyOnWriteArrayList.addAll() has an exception so it just takes the source's array if the source is another CopyOnWriteArrayList. But then, all write operations, including clear, start from scratch. So in the end, the behaviour on clear() should still be the same.