2

What is the simplest way in Java to create an array/list/vector of specified size filled with instances of classes created with the default constructor (I hope this term is used outside C++ also?). I want to make the code more readable and reduce the risk of NullPointerException.

(For example, the ArrayList constructor has a constructor with argument for capacity, not size..)

Below is what is try to achieve in code. This is your typical approach. (It could be done with Vector or ArrayList also)

// Typical, I don't want this
class SomeSimpleClass {

    DataClass[] data = new DataClass[10];

    SomeSimpleClass() {
        // I don't want this..
        for(int i = 0; i < 10; i++) data[i] = new DataClass();
    }

    void doSomething() {
        data[5].doSomething();
    }

}

// What I want
class SomeSimpleClass 

    // now I have ten data objects, ready to be used...
    Holder<DataClass> data = new Holder<DataClass>(10);

    void doSomething() {
        data.get(5).doSomething();
    }

}

I find that quite many of my classes require a few instances of smaller, data-holding classes. The above example is simple but it can be a real nuisance when the class becomes more complicated.

What is the best approach here? Are there some holder classes that work like above? Are there functions for ArrayList (or similar class) such as below?

ArrayList<DataClass> data = new ArrayList<DataClass>().addNewObjects(10);
Toni Makkonen
  • 131
  • 1
  • 5

4 Answers4

3

Since Java 8 you can use something like

Stream.generate(DataClass::new).limit(10).toArray(DataClass[]::new);

but I don't see

DataClass[] data = new DataClass[10];
for(int i = 0; i < data.length; i++) data[i] = new DataClass();

as bad approach.

You can also use Arrays.setAll

DataClass[] data = new DataClass[10];
Arrays.setAll(data, i -> new DataClass());

BTW if you don't need synchronized methods then don't use Vector but List like ArrayList.

Java 8 code to create ArrayList of DataClass elements can look like

Stream.generate(DataClass::new).limit(10).collect(Collectors.toList());

In case you really need Vector then just use returned list and pass it to Vector constructor.

Pshemo
  • 122,468
  • 25
  • 185
  • 269
1

Actually, you should create/initialize objects if and only if you need them. Assuming that you create an array of your objects and each index initially holds a (object-)reference, a user of you api could get the feeling that there is actual data stored in that array. But the truth is, you have a bunch of redundant references to nowhere and because of that no NpE is thrown. That will possibly create some issues where a NpE would have clearly shown "nothin in here"

ifloop
  • 8,079
  • 2
  • 26
  • 35
  • Well what if you have a grid of sudoku cells that need to be initialized the same way? You need 9x9 different objects, ready to be used (filled by the user), and the default constructor could initialize all cells properly so that they **are** actual data, even if holding the **same** data. Some syntax sugar could be nice to avoid a loop, though I'm fine with the loops ^^ – Joffrey Apr 07 '14 at 13:39
  • That is a very specific case. You are very allowed to create such a multi-initializer in your projects. But because of my explanation, there is nothing like this in the jdk. – ifloop Apr 07 '14 at 13:41
  • This is an interesting remark but typically this is mostly about organizing the class variables, and making them "loopable". Consider class Triangle { float x0, y0, x1, y1, x2, y2; } versus class Triangle { Point corner[]; } – Toni Makkonen Apr 07 '14 at 13:41
  • @ifLoop well I'm not sure it is *that* specific. I've come across several situations where I needed an array of objects that needed no more initialization than their plain constructor. But I actually needed instances, not references ready to be filled by a `new`. – Joffrey Apr 07 '14 at 13:43
  • @user2582805 In case of a triangle, I don't think you would need to initialize 3 points to (0,0,0), this does not make much sense. You're likely to know something about the triangle you're creating, so you should initialize the vertices accordingly. – Joffrey Apr 07 '14 at 13:47
1

You can write a custom extension to ArrayList like this:

public class MyGeneratingArrayList<T> extends ArrayList<T> {
    public MyGeneratingArrayList(int count, Class<T> clazz) throws InstantiationException, IllegalAccessException {
        super(count);
        for (int i = 0; i < count; i++) {
            super.add(clazz.newInstance());
        }
    }
}

The clazz part is not exactly beautiful, but if you dont want to dig deep into reflection you will have to deal with that. This post could be of interest to you too.

Community
  • 1
  • 1
SebastianH
  • 2,172
  • 1
  • 18
  • 29
0

You can use Arrays.fill() on arrays, but I guess each item will point to the same object in this case.

If you want different instances, then AFAIK you'll have to stick with:

for(int i = 0; i < 10; i++) data[i] = new DataClass();
Joffrey
  • 32,348
  • 6
  • 68
  • 100