Making a 2D array of generic lists in Java - java

So - I want to make a 2D array of generic lists containing some data I am interested in (on a grid of of some set size),
private ArrayList<MyDataStruct>[][] gridData;
When I initialize this array, I go,
gridData = (ArrayList<MyDataStruct>[][])new ArrayList[w][h];
for(int x=0; x<w; x++)
for(int y=0; y<h; y++){
gridData[x][y] = (ArrayList<MyDataStruct>)new ArrayList<MyDataStruct>(0);
//other stuff, i.e. get data from somewhere, etc
}
and I get a unchecked cast warning. Was curious about why this is not type safe and what I can do to make it type safe (short of switching out of using a 2d array). I understand that it's not very good to mix arrays and generics, but in this case I'm just writing this to run some experiments, so i'm using this instead of say lists of lists lists to save myself some time. Are there any other more elegant approaches that let's me get away with easy to read/write syntax (i.e. no nested lists), but are also type safe?
Thanks!

The only type-safe option is to use nested lists.
Because of type erasure, you can't do new ArrayList<MyDataStruct>[w][h], because that basically becomes new ArrayList[w][h]...and things get complicated and hairy, fast, because arrays don't behave like generics.
Java considers String[] to be a subclass of Object[], but ArrayList<String> isn't a subclass of ArrayList<Object>. Normally, arrays throw an ArrayStoreException when you try to put an element into an array that doesn't match the array's true type, but because of type erasure, it can't do that when generics are in the picture.
Josh Bloch gives the following example in Effective Java:
// Why generic array creation is illegal - won't compile!
List<String>[] stringLists = new List<String>[1];
List<Integer> intList = Arrays.asList(42);
Object[] objects = stringLists;
objects[0] = intList;
String s = stringLists[0].get(0);
The only way to prevent all this code from being entirely legal in Java is to ban the generic array creation, or at least mark it as unsafe.
That said, IMO, the moderate overhead of typing out List and doing it with generic lists is absolutely worth the type safety.

I got here with the same problem (just some experiments, "get things done" approach).
Here is a solution that seems to work for me, using reflection.
note that it is 100% agnostic to the type of the cells in the array (can be list, map, anything). perhaps with a little more work it can also be agnostic to the # of dimensions of the array, but I've bigger fish to fry today...
private static <T> T[][] makeArray(Class<T> componentType, int... dimentions) {
return (T[][]) Array.newInstance(componentType, dimentions);
}
attached below is a test method. to keep the type of the array generic I had to ugly-cast here. this can be handled in another wrapping method to keep client code nice and clean:
#Test
public void testMakeArray() throws Exception {
#SuppressWarnings("unchecked")
List<String>[][] arr = makeArray(List.class, 2, 3);
Assert.assertEquals(2, arr.length);
Assert.assertEquals(3, arr[0].length);
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
arr[i][j] = Arrays.asList("cell", "r="+i, "c="+j);
System.out.print(arr[i][j] + "\t");
}
System.out.println("");
}
}
it prints:
[cell, r=0, c=0] [cell, r=0, c=1] [cell, r=0, c=2]
[cell, r=1, c=0] [cell, r=1, c=1] [cell, r=1, c=2]

I was playing around with a similar idea, but instead used nested Lists of Optionals. It seems to provide some benefits as you do not need to check for null and can instead use isEmpty or isPresent for each cell. However, I'm sure for reasons unknown to me, this is probably not a great solution. I thought i'd share anyways.
public class Grid<T> {
private final int rowCount;
private final int columnCount;
private final List<List<Optional<T>>> data;
public Grid(int rowCount, int columnCount) {
this.rowCount = rowCount;
this.columnCount = columnCount;
data = build();
}
private List<List<Optional<T>>> build() {
return IntStream.range(0, rowCount)
.mapToObj(rowId -> IntStream.range(0, columnCount)
.mapToObj(columnId -> Optional.<T>empty())
.collect(Collectors.toList()))
.collect(Collectors.toList());
}
public Optional<T> get(int rowId, int columnId) {
return data.get(rowId).get(columnId);
}
public void set(int rowId, int columnId, T t) {
data.get(rowId).set(columnId, Optional.ofNullable(t));
}
}

Related

Java : To write a method that can be applied on any kind of array

Hi and thanks for noticing my problem. I want to write a method that can be used by different types of arrays. But my code always looks like this:
public int indexOf_1(int[] a,int b){
//Find the first matched result and return, otherwise report -1
int index = -1;
for(int j=0;j<a.length;j++){
if (a[j]==b)
{index=j;}
}
return index;
}
public int indexOfChar_1(char[] a,int b){
//Consider merged to the previous method?
int index = -1;
for(int j=0;j<a.length;j++){
if (a[j]==b)
{index=j;}
}
return index;
}
That seems to be redundant and I'm completely uncomfortable with such code duplication. Is there any way to write a searching method for all kinds of array to avoid repeating in this case? Thanks!
Unfortunately because the way arrays and the JVM work, this can't be reduced. Not even generics can help since int[] cannot be safely cast to Object[] without explicit conversion.
This looks like a common util function. If you're not comfortable with the code duplication, you can consider using one of the many libraries which provide this functionality. Guava and Commons-Lang are a few.
Guava puts them in the class relevant to the primitive type. Commons-Lang arranges them in the ArrayUtils class
e.g.
Bytes.indexOf(byteArray, (byte) 2);
Ints.indexOf(intArray, 22);
ArrayUtils.indexOf(intArray, 6);
Well you could use Object[] but you might not want to use ==, since it will compare identity of objects instead of values, instead you probably want to use .equals(). (Unless you know the value will always be a char or int) Perhaps this:
public int indexOf(Object[] a, int b) {
int index = -1;
for (int j = 0; j < a.length; j++) {
if (a[j].equals(b)) {
index = j;
}
}
return index;
}
public static <T> int index_Of(Object[] input,T value){
//Find the first matched result and return, otherwise report -1
for(int j=0;j<input.length;j++){
if(input[j].equals(value))
return j;
}
return -1;
}
You can generalize you method to deal with all kind of arrays. However, please pay more attention to the type. If you want to use Object referring to primitive type, when declaring a primitive type array, you need to use reference type. For example,
Character [] a = new Character[]{'a','b','c'};
DO NOT use char, since it will compile error when type checking.

Java Generics method code duplication issue regarding primitive arrays

So I'm working on an implementation of a Grid class for a small, personal utilities library. After much work, I'm tidying up the Grid class and adding some functionality. One of the key pieces of functionality that I wish to use with my Grid class is to be able to take a single, 2D array of any given type as an argument to the constructor.
This worked fine until I realized that I can't compile any code that attempts to pass in any array of primitives to the constructor. Since autoboxing doesn't happen on primitive arrays, this presents a design problem to me in the form of code reuse. The method for initializing the Grid is the same regardless of the type of array passed in, even if they are primitives, but it appears that I need to write a separate constructor for all the different types of primitives. Which leaves me with 9 different constructors assuming I just use my base constructor (and I had planned to have constructors with different arguments for things such as grid-wrapping options).
Am I right in assuming that there is no way to avoid all this code duplication?
You can avoid (most of) the duplication by using Array class. But it's not pretty: your constructor parameter would have do be of type Object, and you'd have to just trust your caller to pass the actual array there, and not a Socket or a Properties.
For example, you could do your own boxing like this:
<T> public T[][] boxArray(Class<T> clazz, Object array) {
int height = Array.getLength(array);
int width = height == 0 ? 0 : Array.getLength(Array.get(array, 0));
T[][] result = (T[][]) Array.newInstance(clazz, height, width);
for(int i = 0; i < height; i ++) {
Object a = Array.get(array, i);
for(int j = 0; j < width; j++) {
result[i][j] = (T) Array.get(a, j);
}
}
return result;
}

How to add new instances to a generic list?

There is a program which handles many lists of many types (Person, Cat, Chairs etc..).
The following code appears many times in the code. The code fills a given list with instances of type Cat until the list has a given number of instances.
int howMany = max - cats.size();
for(int i = 0; i < howMany; ++i) {
cats.add(new Cat());
}
Since this code appears many time we want to create a method to replace it. The method will accept the List that we want to add instances to and the max number of instances. It can accept more parameters if needed.
This seems simple at first but then I remembered it's not possible to write new T() because of type erasure.
What other way is there to achieve this?
You can re-use a method, that instantiates a class of a given type T.
public T getInstanceOfT(Class<T> aClass) {
return aClass.newInstance();
}
Then, you can implement a method, that populates a given List<T> with n objects of type T.
public <T> void populateList(List<T> list, Class<T> clazz, int n) {
for (int i = 0; i < n; i++) {
list.add(getInstanceOfT(clazz));
}
}
Note1: You have to handle IllegalAccessException and InstatiationException.
Note2: If you don't want to use getInstanceOfT() you can just do clazz.newInstance() when adding to the list.
You can use the method as follows:
int howMany = max - cats.size();
Class<Cat> catClass = Cat.class;
List<Cat> listOfCats = new ArrayList<Cat>();
populateList(listOfCats, Cats.class, howMany);
More info:
Create instance of Generic type in Java
Instead of adding all those unnecessary objects to the list, couldn't you wrap the shorter lists in an object that makes them look longer?
class PaddedList<T> extends AbstractList<T> implements List<T> {
private final List<T> wrappedList;
private final int size;
private final T padding;
public PaddedList(List<T> wrap, int size, T pad) {
this.wrappedList = wrap;
this.size = size;
this.padding = pad;
}
#Override
public T get(int index) {
return index < wrappedList.size() ? wrappedList.get(index) : padding;
}
#Override
public int size() {
return size;
}
}
public void test() {
List<String> test = Arrays.asList("One", "Two");
List<String> list10 = new PaddedList<>(test, 10, "Many");
System.out.println(list10);
}
this prints
[One, Two, Many, Many, Many, Many, Many, Many, Many, Many]
Obviously this will go very wrong if you try to modify any of the objects that are used as padding but if all you want is your lists seeming like they are fixed length then this would work very efficiently.

Pattern to circumvent code bloat with primitives in Java

Hello fellow Stackoverflowers,
I have the following problem:
I have a situation, where I get an array of primitive numbers as an input. For example int[] or short[] or even byte[]. Now, I need to iterate over the code and do certain stuff, for example, write the numbers into a list. The problem is, however, that every type of number needs a certain list. No problem, I thought, and tried to use generics:
Object dataSet = provider.getDataArray();
Number[] copy = new Number[Array.getLength(dataSet)];
for(int i= 0; i < Array.getLength(dataSet); i++) {
copy[i] = (T) Array.get(dataSet, i);
}
This works beautifully. However, the problem is with performance. I know that is cannot be circumvented because Reflection and the occuring boxing of the primitives is costly. I am now searching for a pattern to reduce the amount of code, because writing
Object dataSet = provider.getDataArray();
Class<? extends Number> dataType = provider.getDataType();
Number[] copy = new Number[dataSet.length];
if(dataType == Float.class)
float[] dataSetAsFloat = (float[]) dataSet;
for(int i= 0; i < dataSet.length; i++)
copySet[i] = dataSetAsFloat[i];
else if (dataType == Double.class)
double[] dataSetAsDouble = (double[]) dataSet;
for(int i= 0; i < dataSet.length; i++)
copySet[i] = dataSetAsFloat[i];
....
is a very bloated solution, because the application in the program I'm writing is not as simple as shown here. Basically, I create several hundred lines of extra code because of this performance problem. Is there a solution to this? Perhaps a pattern I'm not aware of, or some really simple trick I'm not seeing?
I would be immensely grateful for a response.
Thanks.
Have you considered a strategy pattern that chooses a conversion strategy based on the data type? While it won't reduce much of the overall total code, it will help to modularize it.
public interface ArrayConversionStrategy<T extends Number> {
T[] convertArray
}
public class FloatConversionStrategy implements ArrayConversionStrategy<Float>
float[] convertArray(Object[] dataset) {
float[] dataSetAsFloat = new float[dataset.length];
for(int i= 0; i < dataSet.length; i++)
dataSetAsFloat [i] = dataset[i];
}
}
public class DoubleConversionStrategy { ... }
public class LongConversionStrategy { ... }
Then in the calling class have a map of data types to strategies
Map<Class<? extends Number>, ArrayConversionStrategy> map;
Object[] dataSet = provider.getDataArray();
Class<? extends Number> dataType = provider.getDataType();
ArrayConversionStrategy strategy = map.get(dataType)
return strategy.convertArray(dataSet);
Some of my generic syntax may be off here and may have some boxing/autounboxing that may need to be done, but just as a general strategy this may be useful.
Instead of unpacking the wrapper, you can use a getLong(int)/putLong for integers and getDouble(int)/putDouble for floating point. This will give you two methods which support all primitives types.
interface Array {
public long getLong(int idx);
public double getDouble(int idx);
public void setLong(int idx, long l);
public void setDouble(int idx, double d);
}
class ByteProvider implements Array {
}
class IntProvider implement Array {
etc.

Java - multidimensional array of vectors of generic type

Imagine, if you will, a 10x10x10 cube made out of 1x1x1 bricks. Each brick must be accessable by an x,y,z coordinate. For each brick I also need to store a list of names of who own that 'brick'.
As efficiency is an absolute must, I came up with the following idea - A 3d array of vectors.
note- I have made a class which stores a name, and other info (called person)
//declaration
protected Vector<person>[][][] position;
I think I must then allocate memory to the pointer position. I have tried this
position = new Vector<person>[10][10][10];
But am getting an error 'Cannot create a generic array of Vector' I am only familiar with C++ and Java is new to me. I understand java does not like declaring arrays with generic type? Does anyone know how I can get around this problem?
Cheers
No need to complicate things that much! You know the size of the array (10:10:10), so there's no need to go for vectors or other stuff for the bricks. Try using array of objects:
Class Brick {
public Brick(int x, int y, int z){
this.x=x;
this.y=y;
this.z=z;
owners = new ArrayList <String> ();
}
List<String> owners;
int x, y, z; //every brick "knows" its position - you might not need it
}
Code for creating the array:
Public Class Main {
.....
Brick Cube[][][] = new Brick[10][10][10];
for (int x=0; x < 10; x++)
for(int y=0; y < 10; y++)
for(int z=0; z < 10; z++)
{
Cube[x][y][z] = new Brick(x, y, z);
}
//adding an owner to a brick:
Cube[0][0][0].owners.add("Owner");
.....
}
Keep OOP in mind - It makes things much easier!
TODO: add getters/setters
If you did want to go down the route of using a List structure rather than arrays, this should be enough to get you started. This is based off of what #FrustratedWithFormsDes said, but I included the initilization code since it's hard to get the syntax right.
public class Person {
}
class PeopleStorage {
ArrayList<ArrayList<ArrayList<Person>>> data;
public PeopleStorage(int size) {
this.data = new ArrayList<ArrayList<ArrayList<Person>>>(size);
for (int i = 0; i < size; i++) {
ArrayList<ArrayList<Person>> inner = new ArrayList<ArrayList<Person>>(
size);
data.add(inner);
for (int j = 0; j < size; j++) {
ArrayList<Person> inner2 = new ArrayList<Person>(size);
inner.add(inner2);
for (int k = 0; k < size; k++) {
inner2.add(new Person());
}
}
}
}
public Person get(int index1, int index2, int index3)
{
//check indices against size, throw IllegalArgumentException here
return data.get(index1).get(index2).get(index3);
}
public void set(Person person, int index1, int index2, int index3)
{
//check indices against size, throw IllegalArgumentException here
data.get(index1).get(index2).set(index3, person);
}
}
What you are trying to do is impossible in java, because there is no operator overloading (like in C++). In short the [] operator in Java is defined only for arrays and cannot be overloaded. Therefore the only way to access elements inside Vector/ArrayList is through the get() method (or through an Iterator or couple other methods, but you get the picture). Analogically you cannot define multi-dimensional ArrayList that way. What you should do is
ArrayList<ArrayList<ArrayList<Person>>> people = new ArrayList<ArrayList<ArrayList<Person>>>()
and then go and initialize all the internal arrays with nested loops or whatever you wish.
It looks a little bit ugly, and since ArrayList/Vector is a dynamic collection adding for example a new element at the first array would require you to initialize the two nested arrays as well. So you might be better off in design terms with writing some form of a wrapper for that class in order to isolate that logic there.
The difference between ArrayList and Vector in Java is that vector is synchronized (therefore slower) and in the default growth pattern (Vector doubles its size, while ArrayList grows by 50%). Otherwise they are pretty much identical in functionality and complexity of operations.
I think you will want to use an ArrayList instead of a vector. I'm a bit rusty on this, but from what I recall, mixing arrays and generic containers is not a good idea.
You could try this:
position = new ArrayList(10)<ArrayList(10)<ArrayList(10)<Person>>;
but it's rather ugly to read. Accessing data is like this:
person = position.get(1).get(3).get(6); //get someone at x=1, y=3, z=6
Beware I don't have the chance right now to compile this and see if it actually works, so you will want to read the docs on ArrayList but I think this is the direction you could go in...
Update: jhominal has pointed out some news that I forgot, I don't have a Java compiler on hand to verify this, but if you try this solution, take a look at what he says as well.
Note: This is more of an explanation of why generic arrays don't work in Java rather than an answer to your actual question.
Effective Java 2nd Edition deals with generic arrays on page 119 of Chapter 5 (PDF).
Why is it illegal to create a generic
array? Because it isn't typesafe. If
it were legal, casts generated by the
compiler in an otherwise correct
program could fail at runtime with a
ClassCastException. This would
violate the fundamental guarantee
provided by the generic type system.
This is because Java Generics only have types at compile time and insert the appropriate casts so specific operations work at runtime.
The easiest solution to this problem is likely the one Ed.C provided.
I would also go with the object answer by Ed.C, but this seems to work:
#SuppressWarnings("unchecked")
protected Vector<Person>[][][] position = new Vector[10][10][10];
ie, you skip the diamond on the right.

Categories