Is there a concise/DRY way to add many objects to an ArrayList in Java

Viewed 71

Let's say you have created many objects with a simple numerical naming system

MyObject myObject1 = new MyObject(...);
MyObject myObject2 = new MyObject(...);
MyObject myObject3 = new MyObject(...);
MyObject myObject4 = new MyObject(...);
MyObject myObject5 = new MyObject(...);
.
.
.
MyObject myObjectn = new MyObject(...);

is there a more concise/DRY way to add them to an ArrayList than

arrayList.add(myObject1);
arrayList.add(myObject2);
.
.
.
arrayList.add(myObjectn);

or

ArrayList<MyObject> arrayList = new ArrayList<MyObject>(Arrays.asList(myObject1, myObject2, ..., myObjectn))
3 Answers

Collections.addAll()

Starting from JDK 1.5 we can use Collections.addAll() to populate a mutable collection with specified objects.

List<MyObject> myObjects = new ArrayList<>();

Collections.addAll(myObjects, new MyObject(...), new MyObject(...), ...);

List.of()

And since Java 9 we have a family of overloaded methods List.of() which facilitate creation of an immutable list.

List<MyObject> myObjects = List.of(new MyObject(...), new MyObject(...), ...);

If you're using Java 9 onwards, List.of() is a preferred alternative to Arrays.asList(), which wraps the arguments with an array due to the way how varargs work.

And unless the number of arguments exceeds 10 List.of() would not require allocating an intermediate array, and even you need to provide more than 10 argument using static method of the List interface would be more intuitive than resort to Arrays utility class.

Sidenotes:

  • Leverage abstractions, write your code against interfaces, not concrete classes like ArrayList. See What does it mean to "program to an interface"?.
  • Since Java 7 we can use diamond <> instead of repeating generic type arguments twice.
  • Avoid throw-away names, if you need a variable - then give it a proper name (See Self-documenting code), otherwise don't declare an intermediate variable.

If you can construct these Variables yourself, use this:

package stackoverflow;

import java.util.ArrayList;

public class SimpleAddList {


    static public class MyObject {
        private final int mValue;
        public MyObject(final int pValue) {
            mValue = pValue;
        }
        @Override public String toString() {
            return "MO[" + mValue + "]";
        }
    }


    public static void main(final String[] args) {
        final ArrayList<MyObject> sl = simple();
        System.out.println("Simple List");
        printList(sl);

        final ArrayList<MyObject> pl = parameterized(1, 3, 5, 7, 11, 13);
        System.out.println("Parameterized List");
        printList(pl);
    }



    private static ArrayList<MyObject> simple() {
        final ArrayList<MyObject> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            final MyObject myObject = new MyObject(i);
            list.add(myObject);
        }
        return list;
    }

    private static ArrayList<MyObject> parameterized(final int... pParams) {
        final ArrayList<MyObject> list = new ArrayList<>();
        for (final int param : pParams) {
            final MyObject myObject = new MyObject(param);
            list.add(myObject);
        }
        return list;
    }



    private static void printList(final ArrayList<MyObject> pSl) {
        System.out.println("List:");
        for (final MyObject mo : pSl) {
            System.out.println("\t" + mo);
        }
    }



}

If you cannot construct them, but they are member variables, you can use Reflection:

package stackoverflow;

import java.lang.reflect.Field;
import java.util.ArrayList;

public class SimpleAddList_Reflection {


    static public class MyObject {
        private final int mValue;
        public MyObject(final int pValue) {
            mValue = pValue;
        }
        @Override public String toString() {
            return "MO[" + mValue + "]";
        }
    }
    static public class ContainerClass {
        MyObject    myObject1   = new MyObject(1);
        MyObject    myObject2   = new MyObject(3);
        MyObject    myObject3   = new MyObject(5);
        String      badEntry    = new String("just to showcase");
    }


    public static void main(final String[] args) throws IllegalArgumentException, IllegalAccessException {
        final ContainerClass cc = new ContainerClass();
        final ArrayList<MyObject> sl = aggregateFromClassInstance(cc);
        System.out.println("Simple List");
        printList(sl);
    }



    private static ArrayList<MyObject> aggregateFromClassInstance(final ContainerClass pCc) throws IllegalArgumentException, IllegalAccessException {
        final ArrayList<MyObject> list = new ArrayList<>();
        final Field[] fields = pCc.getClass().getDeclaredFields();
        for (final Field field : fields) {
            if (field.getType() == MyObject.class) list.add((MyObject) field.get(pCc));
        }
        return list;
    }



    private static void printList(final ArrayList<MyObject> pSl) {
        System.out.println("List:");
        for (final MyObject mo : pSl) {
            System.out.println("\t" + mo);
        }
    }



}

If you cannot allocate them yourself, nor are they member variables (can be static too), then you're out of luck and have to go manually, but that's very likely to be really bad design then, and you should not work around bad design but correct the design first, then the rest will become a lot easier.

Note: In the rare case you use different classloaders, you might retype field.getType() == MyObject.class to field.getType().getName().equals(MyObject.class.getName())

The solution depends. For example, if the goal is to add the objects into the list and then pass the list or use the list later somewhere else, then in that case you can just use a loop.

List<Object> list = new ArrayList<>();
int numberOfObjectsToCreate = 10;

for(int count = 0; count < numberOfObjectsToCreate; ++count){
    list.add(new Object());
}
Related